【问题标题】:Put characters received from an array in alphabetical order without using sorting functions?在不使用排序函数的情况下按字母顺序从数组接收到的字符?
【发布时间】:2018-04-02 03:41:59
【问题描述】:

所以,基本上,我在 java 中创建了一个算法,它从字符串中获取字符并计算其频率。现在,我需要按字母顺序打印它。

例如: 频率:3 频率:1 l 频率:5

有什么建议吗?这是我到目前为止所拥有的。

     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;
}

【问题讨论】:

  • 通常提及您正在使用的编程语言会很有帮助,甚至添加标签!
  • 对不起!!我的大脑太炸了,哈哈,修好了!
  • 标签“频率”。这与似乎与打印字符有关的问题有关吗?你的问题不清楚。要么添加一些工作代码,要么添加一些输入示例和预期输出......至少我猜不出你想要做什么。再打一轮。
  • 使用有序树
  • 看起来像Counting Sort

标签: java arrays string ascii frequency


【解决方案1】:

首先,您要对提供的字符串中的字符进行排序,不使用任何 API 排序方法的简单方法是利用两个 for 循环。当然,您需要将提供的字符串分解为字符数组。假设提供的字符串是"This is my string to sort":

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

现在使用两个 for 循环遍历字符数组并操作该数组的元素,以将最小的字符值带到开头,将较大的值逐渐带到结尾。这种类型的排序称为Bubble Sort,它是这样的:

注意:是的……下面的代码中有很多 cmets 解释了发生了什么。如此之多,以至于它是彻头彻尾的 杂乱无章。这就是编辑器的好处,你可以轻松删除 如果你不想要它们。

// 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);

是的,该代码中有很多 for 循环。一旦你理解了代码,然后如果你喜欢删除所有的评论。一旦你这样做了,你就会发现实际上并没有太多的代码来完成这个任务。

【讨论】:

  • 问题标题说不使用排序功能。我不确定使用 BubbleSort 是否与之冲突。 OP 想知道如何自己编写排序,你解释得很好,或者他想要一个根本不使用 sorting 的解决方案。
  • @Zabuza Sorting functions 可能是指 Java 的 builtin 排序函数。事实上,我强烈怀疑分配的重点是让 OP (理解和)实现排序 algorithm (完全不同于 "frunction" ) 他自己;比如冒泡排序。事实上,我强烈怀疑 BubbleSort 正是导师会为练习考虑的算法,任何更高级的算法都是加分。
  • @Zabuza OP 声明他需要按字母顺序打印数组的内容。除非我们谈论一个 dumb 算法,比如多次遍历数组,每次都打印“最低”的非打印值,否则数组元素要么就地重新排列,要么重新排列为一个新的(排序的)数组...这是排序。 --- AFAICS,除非情况正是我所描述的那样,否则该要求没有任何意义:一项旨在教授或测试 OP 了解排序算法如何工作的作业。
  • 就像许多文本(好或坏)一样,大多数文本至少可以有 10 种不同的解释方式。我想这个OP的帖子没有什么不同。在我上面介绍的代码中使用了 很多 方法(函数或您喜欢的任何名称),但对于我的生活,我无法弄清楚如何看到对BubbleSort 方法。我只在原始代码中看到了 concept 的使用,但话又说回来,这只是我,也许还有其他一些人真正知道其中的区别。无论如何,@Zabuza 很可能是正确的。如果 OP 能让我们知道就好了。
  • @DevilsHnd 谢谢!这非常有帮助。我一直听说冒泡排序,但没有人愿意向我解释。
【解决方案2】:

将您的结果存储在有序映射中,例如TreeMap。遍历映射中的键将按排序顺序输出它们,无需额外处理。

这需要对您的代码进行少量修改。您将返回一个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;
 }

您现在可以使用以下内容迭代字符:

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

keySet() 返回的Set 将像地图本身一样进行排序。

如果您对提供的特定功能感到困惑,您可以在调用它后将结果添加到地图中,然后像以前一样迭代地图:

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

【讨论】:

  • 这可能是一个课堂作业。我不认为他打算用有序的集合来解决它。如标题所示,他不允许使用(内置)排序函数。这并不意味着不能使用排序算法。赋值的目的其实很可能是让他自己实现这样的排序算法;我什至可以猜测导师特别考虑了冒泡排序。 ---我对此表示反对,因为它会破坏练习的目的。遵循这个答案将对 OP 造成伤害。
  • @AlmightyR。既然你认为这不符合问题的精神,我恭敬地接受你的反对票。但是,由于本网站的目的是提供 OP 以外的帮助,因此我将保留这个技术上正确的答案。
  • 我认为这种类型的答案非常有用,但显然不符合问题的所有环境限制。所以,它不应该是唯一的答案,也可能不是公认的答案。
  • @Tom。我完全同意
  • @MadPhysicist 本网站的目的是帮助解决所提出的问题(OP 或更高版本的读者;正确),考虑到提出这些问题的情况答案应提供答案;不是解决方案。 --- 简单地提供一个解决方案,特别是通过一个阴暗的变通方法来欺骗问题的措辞以避免它的情况,在恕我直言绝对不是一个有效的答案。它与纯代码的“答案”没有什么不同:它破坏了问题的目的,而不是解决它,因此,帮不了任何人
【解决方案3】:

您正在尝试实现所谓的Counting Sort (Wikipedia)。

如果您的 universe(可能的字符集)与您要排序的输入的大小相比较小,则效果很好。

这相对容易。您以前知道 universe 的正确顺序并设置了已排序的 MapLinkedHashMap 以保持顺序)。对于我们的示例,让我们将宇宙限制为 [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);

现在您遍历您的 input 并计算所有出现次数:

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

最后,您只需以先前已知的正确顺序遍历您的 Map 并打印每个字符它经常出现的数量:

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();

当然你可以稍微优化一下程序,但那是一般程序。链接的 Wikipedia 文章包含更多信息。

例如,您可以在实践中使用 Java 中每个 charint 值来提取正确的顺序。这样你就不需要用整个宇宙来初始化Map,并且可以忽略甚至不会出现一次的东西。您也可以放弃Map 以支持array,它保留了定义的顺序并由您的机器进行了极大的优化。如前所述,charindex 基于其 int 值。

【讨论】:

    【解决方案4】:

    你占了 80%。您已经有一个类似@MadPhysicist 所指的排序地图。您正在使用分发-收集技术。我猜你没有意识到在分布中,你已经对字符进行了排序。您只需要再次收集它们以进行输出。分发和收集可以是一种排序形式。但是,它本身并没有使用排序功能。

    我不会为此提供代码,因为你有一个良好的开端,你只是寻求建议。

    首先,你已经完成的分发部分:

    ASCII 只有 128 个字符。但是,Java 无论如何都不使用 ASCII。即便如此,将本练习的范围限制在 C0 Controls and Basic Latin 块加上 C1 Controls 和 Latin-1 Supplement 块似乎是合理的,这就是你的 new int[256] 所做的。

    那么,这些块中的字符是否按照您想要的顺序排列,与counts 中的排列顺序不一样吗?您已将字符分配到有序框中作为计数。 counts[c[i]]++

    聚会:

    您只需按照所需的顺序再次收集它们并以所需的格式写出它们。 counts 上的循环可以做到这一点。您的问题标题要求按顺序排列字符,这意味着输出放置相同数量的字符。您可以将字符数转换为重复字符。如果您的目标是简单地将它们打印出来,您可以循环执行;否则,您必须build a string

    顺便说一句 - 该顺序称为字典顺序,因为它基于字符集或编码定义。字母意味着选择的符号序列(在数学意义上)或特定自然语言的特定书写系统,其中一些字母被流行惯例或语言学院指定为“字母表”。例如,拉丁文中的丹麦字母表:ABCDEFGHIJKLMNOPQRSTUVWXYZÆØÅ。见Locale

    【讨论】:

    • 该问题要求提供建议,就好像它是为学习或家庭作业的提问者提供最终解决方案一样。这个问题几乎已经解决了。
    • 建议的哪一部分与实际问题相关? Distributing and gathering can be a form of sorting. But, it's not using a sort function per se.?
    猜你喜欢
    • 2015-06-08
    • 2016-04-28
    • 2014-11-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多