Put characters received from an array in alphabetical order without using sorting functions?

笑着哭i 提交于 2019-12-11 03:26:52

问题


So, basically, I created an algorithm in java that takes characters from a string and counts its frequencies. Now, I need it to be printed in alphabetical order.

For example : A freq: 3 d freq: 1 l freq: 5

Any suggestions? Here's what I have thus far.

     int[] charCounts(String userSort) {
        int[] counts = new int[256];
        char[] c = userSort.toCharArray();
        for (int i=0;i<c.length;++i) {
            counts[c[i]]++;
        }
        return counts;
}

回答1:


First you want to sort the characters within your supplied String and a simple way to do that without using any API sorting methods is to utilize two for loops. Of course you will need to break down the supplied string into a character array. Let's assume the supplied string is "This is my string to sort":

String suppliedString = "This is my string to sort";
char[] charArray = suppliedString.toCharArray();

Now use two for loops to iterate through the Character Array and manipulate the elements of that Array to bring the least character values towards the beginning and the greater values progressively to the end. This type of sorting is called a Bubble Sort and it goes something like this:

Note: Yes...there are a lot of comments within the following code explaining what is going on. So much so that it's downright cluttering. That's what's so good about editors, you can easily delete them if you don't want them.

// The supplied String to sort.
String suppliedString = "this is my string to sort";
// Remove all whitespaces. We don't need them for 
// this excercise since our goal is to sort and 
// get character occurrences. If you want to also
// process whitespaces then comment the code line
// below.
suppliedString = suppliedString.replace(" ", "");

// Convert the supplied string to a character array.
char[] charArray = suppliedString.toCharArray();
// Declare a Character variable to hold the current
// Character Array element value being processed.
char tempChar;
// Iterate through the character array with two
// FOR loops so as to create a string which will
// hold the least character values to the greatest
// character values.
for (int i = 0; i < charArray.length; i++) {
    for (int j = 0; j < charArray.length; j++) {
        // Is the current Array element value in 
        // charArray[i] less than the what is in
        // the current Array element for charArray[j]?
        if (charArray[i] < charArray[j]) {
            // Yes it is...
            // Hold our current character element value.
            tempChar = charArray[i];
            // Now make the Array element at index i hold
            // what is in Array element at index j.
            charArray[i] = charArray[j];
            // Make the Array element at index j hold what
            // was originally in the Array element at index i.
            charArray[j] = tempChar;
        }
        // No it's not so let's continue iterations through 
        // the character array using the index place-holder 
        // j to see if there are still more character Array 
        // element values less than what is currently in the 
        // Character Array index place-holder i location.
    }
    // continue iterations through the character array 
    // using the index place-holder i to see if there 
    // are still more character Array element values less
    // that what might be in the Character Array index place
    // -holder j location.
}

//==============================================
// For your project you don't need this little
// section. I just added it so you can see what 
// the sort looks like.
// Now use yet another FOR loop to convert the 
// the sorted Character Array (charArray[]) back
// to a sorted string.
// Declare and initialize a String variable to 
// Null String (""). This variable will hold the
// new Sorted String.
String sortedString = "";
for (int i = 0; i < charArray.length; i++) {
    sortedString+= charArray[i];
}

// Display the sorted String. If you don't
// want spaces in your sort then use: 
// System.out.println(sortedString.trim());
// Spaces have the least value (32) so they
// will almost always be at the beginning of
// the sorted string.
System.out.println("Sorted String: -->   " + sortedString + "\n");
//==============================================

// Now that the Character Array is sorted let's
// use yet another couple FOR loops to figure out
// the occurrences of each character. We'll use our 
// same String variable (sortedString) to hold our 
// display text to console. (Note: There's a lot of 
// ways to do this sort of thing in Java)
int counter; // counter used to keep track of char occurrences.
sortedString = "";
for (int i = 0; i < charArray.length; i++) {
    counter = 0; // new character. Make sure counter is zeroed
    // Iterate through the entire array and count
    // those that are the same.   
    for (int j = 0; j < charArray.length; j++) {
        if (charArray[i] == charArray[j]) {
            counter++;
        }
    }
    // Make sure we don't place duplicate character/frequencies
    // into the string we're creating.
    if (!sortedString.contains("Char: " + charArray[i])) {
        // Add the current character and occurrence
        // to our string variable.
        if (sortedString.equals("")) {
            sortedString+= "Char: " + charArray[i] + " - Freq: " + counter; 
        } 
        else {
            sortedString+= " || Char: " + charArray[i] + " - Freq: " + counter; 
        }
    }
}
// Display the sorted characters and their occurrences.
System.out.println(sortedString);

Yup, a lot of for loops in that code. Once you understand the code then delete all the commenting if you like. Once you do you'll see that there really isn't too much code to accomplish this task.




回答2:


Store your results in an ordered map, like a TreeMap. Iterating over the keys in the map will output them in sorted order with no additional processing required.

This would require a small modification to your code. Instead of returning an array, you would return a SortedMap:

 SortedMap<Character, Integer> charCounts(String userSort) {
    SortedMap<Character, Integer> counts = new TreeMap<>();
    for (int i=0; i < userSort.size(); ++i) {
        char c = userSort.charAt(i);
        if(counts.contains(c)) {
             counts.put(c, counts.get(c) + 1);
        } else {
             counts.put(c, 1);
        }
    }
    return counts;
 }

You can now iterate the characters with something like:

 for(Character c : charCounts(...).keySet()) ...

The Set returned by keySet() will be sorted like the map itself.

If you are stuck with the particular function you provided, you can add the results to the map after calling it, and then iterate over the map as before:

 int[] counts = charCounts(...);
 TreeMap<Character, Integer> map = new TreeMap<>();
 for(char c = 0; c < counts.length; c++)
      map.put(c, counts[c]);



回答3:


You are trying to implement what is called Counting Sort (Wikipedia).

It works well if your universe (the set of possible characters) is small, compared to the size of the input you want to sort.

It's relatively easy. You previously know the correct order of your universe and setup a sorted Map (LinkedHashMap to preserve order). For our example, let's limit the universe to [a, b, c, d, e].

LinkedHashMap<Character, Integer> charToCount = new LinkedHashMap<>();
charToCount.put('a', 0);
charToCount.put('b', 0);
charToCount.put('c', 0);
charToCount.put('d', 0);
charToCount.put('e', 0);

Now you traverse your input and count all occurrences:

String inputToSort = ...
for (char c : inputToSort.toCharArray()) {
    // Increase counter by one
    charToCount.put(c, charToCount.get(c) + 1);
}

Finally you simply traverse your Map in the previously known correct order and print each character the amount it occurred often:

StringBuilder sb = new StringBuilder();
// Every character
for (Entry<Character, Integer> entry : charToCount.entrySet()) {
    // How often it occurred
    for (int i = 0; i < entry.getValue(); i++) {
        sb.append(entry.getKey());
    }
}
String output = sb.toString();

Of course you can optimize the procedure a bit, but that is the general procedure. The linked Wikipedia article contains more information.

For example you can, in practice, use the int value of every char in Java to extract the correct order. By that you don't need to initialize the Map with the whole universe and can leave out stuff which does not even occur once. Also you can drop the Map in favor of an array which preserves order by definition and is extremely optimized by your machine. The index for a char then is based on its int value, as said before.




回答4:


You are 80% there. You already have a sorted map like that which @MadPhysicist refers to. You are using a distribute-gather technique. I guess you don't realize that in the distribution, you've already sorted the characters. You just need to gather them up again for output. Distributing and gathering can be a form of sorting. But, it's not using a sort function per se.

I'm not going to give code for this because you've got a good start and you are only asking for suggestions.

First, the distribution part that you've already done:

ASCII only has 128 characters. But, Java doesn't use ASCII anyway. Even so, it seems reasonable to limit your scope for this exercise to the C0 Controls and Basic Latin block plus the C1 Controls and Latin-1 Supplement block, which is what your new int[256] does.

So, are the characters in those blocks in the order you want and isn't that the same order as in counts? You've distributed the characters into ordered boxes as counts. counts[c[i]]++

Gathering:

You just have to gather them up again in the desired order and write them out in the desired format. A loop over counts would do that. Your question title asks to put the characters in order so that implies output putting the same number of characters. You can convert the count of a character into repeated characters. If your goal is to simply print them out, you can do that in a loop; Otherwise, you'd have to build a string.

BTW—The order is called lexicographic because it is based on a character set or encoding definition. Alphabetic implies either a chosen sequence of symbols (in the mathematical sense) or a particular writing system of a particular natural language with some letters designated by popular convention or language academy as "the alphabet". For example, the Danish alphabet in Latin script: ABCDEFGHIJKLMNOPQRSTUVWXYZÆØÅ. See Locale.



来源:https://stackoverflow.com/questions/46858061/put-characters-received-from-an-array-in-alphabetical-order-without-using-sortin

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!