简体   繁体   中英

How do I sort an ArrayList<String> that contains integers?

I made a Word Counter binary search tree that increments the count of a word when it is entered more than once. Both the word and word count are saved in the tree. I am attempting to print the highest count words first, and go down in descending count order.

I converted the BST to an ArrayList in order to do this, but now I cannot seem to figure out how to sort the list by decreasing count order. Here's what I have so far:

public ArrayList<String> toArray() {
  ArrayList<String> result = new ArrayList<String>();
  toArrayHelp(root, result);
  Collections.sort(result);
  return result;
}

private void toArrayHelp(Node<String, Integer> node, ArrayList<String> result) {
  if (node == null) {
      return;
  }
  toArrayHelp(node.left, result); 
  result.add("count: " + String.valueOf(node.count) + "/t word: " + node.data); 
  toArrayHelp(node.right, result); 
}

I have tried Collections.sort() but that isn't ordering it by string, only by word.

  • traverse the tree, generating a List<Node<String, Integer>> from all elements
  • sort the List , ordering by the int part of the nodes
  • create a list retaining only the strings, in the same order

You are constructing the output string too soon: you need to sort the list first by using the count as a key, and afterwards print the results. You can make a simple wrapper that will contain the result:

public class WordCount implements Comparable<WordCount>{
   private String word;
   private Integer count;

   //constructors, getters, setters etc..

   @Override
   public int compareTo(WordCount other) {
       return Integer.compare(this.count, other.count);
   }

}

and construct a List<WordCount> list while you traverse the tree. After you are done you just need to sort the list by Collections.sort(list) and print the results.

1.For DESC order use Collections.sort(result, Collections.reverseOrder()); because default sorting order is ASC.

2.Make sure that count's string representation has the same length. Otherwise, lexicographical order assumes 11 < 2:

List<String> list = Arrays.asList("11", "1", "2");
Collections.sort(list, Collections.reverseOrder());
System.out.println(list); // output: [2, 11, 1]

But if numbers have the same length works fine:

List<String> list = Arrays.asList("11", "01", "02");
Collections.sort(list, Collections.reverseOrder());
System.out.println(list); // output: [11, 02, 01]

How to add leading zeroes you can find here https://stackoverflow.com/a/275715/4671833 . Should be something like this result.add("count: " + String.format("%02d", String.valueOf(node.count)) + "/t word: " + node.data);

Two brief points: Let name selection and formatting be your friends! You'll want to make a habit of choosing simple and expressive variable names, and of keeping your code neatly formatted.

Let's start by putting this into clear steps:

(1) There is a source of word data, expressed as a tree of nodes. Avoiding too much detail, lets set the important details of the node type, and have the node tree available using a getter.

An important detail to mention is that the nodes are intended to be kept in a sorted binary tree that has distinct key values, and for which the value of any left node is strictly less than the value of the node, and the value of any right node is strictly greater than the value of the node. That has an important consequence which is that the values of the left sub-tree of a node are all strictly less than the value of the node, and the values of the right sub-tree are similarly all strictly greater than the value of the node.

public class Node<K, V> {
  public K key;
  public V value;

  public Node<K, V> left;
  public Node<K, V> right;

  public Node(K key, V value) {
    this.key = key;
    this.value = value;
  }
}

public Node<String, Integer> getRootNode() {
    // Undetailed ...
}

(2) There are three main operations which are needed: An operation to collect the nodes of the tree into a list, an operation to sort this list, and an operation to display the sorted list:

public List<Node<String, Integer>> flatten(Node<String, Integer> rootNode) {
    // Undetailed ...
}

public void sort(List<Node<String, Integer>> nodes) {
    // Undetailed ...
}

public void print(List<Node<String, Integer>> nodes) {
    // Undetailed ...
}

(3) This fits together, for example, as follows:

public void tester() {
  Node<String, Integer> rootNode = getRootNode();
  List<Node<String, Integer>> flatNodes = flatten(rootNode);
  sort(flatNodes);
  print(flatNodes)l
}

(4) What remains are to detail the several methods. We begin with 'flatten'. That will be implemented as a recursive operation. And, since passing around the storage for the flat list is simpler, the method will be split into two parts, one which allocates storage, and another which does the recursive processing. This technique of passing along a storage collection is typical of this sort of processing.

'flatten' makes use of the ordering property of a node with respect to the node's left node and the node's right node: 'flatten' adds all values of the left sub-tree to the flat nodes list, followed by the node, followed by all values of the right sub-tree.

public List<Node<String, Integer>> flatten(Node<String, Integer> rootNode) {
    List<Node<String, Integer>> flatNodes = new ArrayList<Node<String, Integer>>();
    flatten(rootNode, flatNodes);
    return flatNodes;
}

public void flatten(Node<String, Integer> node, List<Node<String, Integer>> flatNodes) {
   if ( node == null ) {
       return;
   }
   flatten(node.left, flatNodes);
   flatNodes.add(node);
   flatten(node.right, flatNodes);
}

(5) At a cost of clarity, this can be made somewhat more efficient by moving the null checks. For a fully balanced tree, this will avoid about 2/3's of the recursive calls, which is pretty good reduction. This only matters if the number of nodes is high. And a good compiler will likely convert the code in this fashion anyways.

public List<Node<String, Integer>> flatten(Node<String, Integer> rootNode) {
    List<Node<String, Integer>> flatNodes = new ArrayList<Node<String, Integer>>();
    if ( rootNode != null ) {
        flatten(rootNode, flatNodes);
    }
    return flatNodes;
}

public void flatten(Node<String, Integer> node, List<Node<String, Integer>> flatNodes) {
    Node<String, Integer> leftNode = node.left;
    if ( leftNode != null ) {
        flatten(leftNode, flatNodes);
    }

    flatNodes.add(node);

    Node<String, Integer> rightNode = node.right;
    if ( rightNode != null ) {
        flatten(rightNode, flatNodes);
    }
}

(6) The next bit is sorting the flat nodes list. Two implementations are presented, a more modern one which uses lambdas, and an older style one which uses an explicit comparator. The comparisons are written to generate a list sorted from smallest to largest. To reverse the sort order, exchange the order of comparison.

public void sort(List<Node<String, Integer>> nodes) {
    Collections.sort(
        nodes,
        ((Node<String, Integer> n1, Node<String, Integer> n2) -> Integer.compare(n1.value, n2.value)) );
}

public static final Comparator<Node<String, Integer>> NODE_COMPARATOR = 
    new Comparator<Node<String, Integer>>() {
        public int compare(Node<String, Integer> n1, Node<String, Integer> n2) {
            return Integer.compare(n1.value, n2.value);
        }
    };

public void sort(List<Node<String, Integer>> nodes) {
    Collections.sort(nodes, NODE_COMPARATOR);
}

(7) Printing of the resulting sorted list is left as an exercise.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM