【问题标题】:Sorting array of chars alphabetically then by length按字母顺序对字符数组进行排序,然后按长度
【发布时间】:2018-11-02 20:46:36
【问题描述】:

我有一个结构数组,我可以在其中跟踪每个唯一单词在给定文本中出现的次数:

struct List {
  char word[20];
  int repeat;
};

现在我需要对此进行排序:

as             6
a              1
appetite       1
angry          1
are            2
and            4
...

到这里:

a            1
as           6
and          4
are          2
angry        1
appetite     1
...

(按字母顺序,我的意思是只按第一个字母) 到目前为止,我想出了这个:

for (i = 0; i < length - 1; i++) {
        min_pos = i;
        for (j = i + 1; j < length; j++) // find min
            if (array[j].word[0] < array[min_pos].word[0]) {
                min_pos = j;
            }
            swap = array[min_pos]; // swap
            array[min_pos] = array[i];
            array[i] = swap;
        }

这段代码非常适合按字母顺序排序,但我无法编写正确的代码来按字母顺序和长度排序。

【问题讨论】:

  • 使用std::string 会更容易。您可以使用std::map&lt;std::string, int&gt; 将单词与频率相关联。排序将为您处理。 std::string 的自然排序是按字母,然后是长度,例如`"aa" 在 "ba" 之前。
  • 这里不清楚swap_pos 的目的是什么。应该是min_pos
  • 是的,忘记改回来了。
  • 第二个for - 它的左大括号在哪里?第一个for 右括号在哪里?

标签: c++ arrays sorting data-structures char


【解决方案1】:

制作一个比较器函数

operator&lt; 添加到您的List

bool operator<(const List &lhs) const {
    if(word[0] != lhs.word[0]) {
        return word[0] < lhs.word[0];
    }
    return strlen(word) < strlen(lhs.word);
}

现在使用这个运算符进行排序,使用任何你喜欢的算法。

【讨论】:

  • 好主意。我会将它与我的想法结合起来:使用元组字典比较运算符。 (下面回答)
【解决方案2】:

其他人指出,有更快、更清洁的排序方式。但是,如果您想使用自己的选择排序,就像您编写的那样,那么您只需要对您的代码进行一些更改。

将“我是否需要交换”逻辑与交换逻辑本身分开。然后代码变得更清晰,并且更清楚在哪里添加额外的检查。

我在这里只复制了内部循环。您想用这个替换现有的内部循环。我不清楚你为什么需要swap_posmin_pos,所以我不考虑语义。

    for (j = i + 1; j < length; j++) { // find min
        // first, determine whether you need to swap
        // You want to swap if the first character of the new word is
        // smaller, or if the letters are equal and the length is smaller.
        bool doSwap = false;
        if (array[j].word[0] < array[min_pos].word[0]) {
            doSwap = true;
        }
        else if (array[j].word[0] == array[min_pos].word[0] &&
                 strlen(array[j].word) < array[min_pos].word) {
            doSwap = true;
        }

        // do the swap if necessary
        if (doSwap) {
            swap_pos = j;
            swap = array[min_pos]; // swap
            array[min_pos] = array[i];
            array[i] = swap;
        }
    }

为了更清楚地说明必要的逻辑更改,我特意避免进行重大的样式更改或简单的优化。

【讨论】:

  • 最后把你的循环放在do ... while (doSwap) 工作就像一个魅力,谢谢。
  • @enjoy 我不认为条件循环是选择排序的好主意。选择排序的一般情况不允许提前退出。
【解决方案3】:

您可以将 lambda 传递给 sort 来执行此操作:

sort(begin(array), end(array), [](const auto& lhs, const auto& rhs){ return *lhs.word < *rhs.word || *lhs.word == *rhs.word && (strlen(lhs.word) < strlen(rhs.word) || strlen(lhs.word) == strlen(rhs.word) && strcmp(lhs.word, rhs.word) < 0); });

Live Example

【讨论】:

    【解决方案4】:

    使用元组字典比较运算符

    不写这个条件的一个简单方法是

    #include <tuple>
    

    那么std::tie就可以使用了:

    std::tie(array[j].word[0], array[j].repeat) < std::tie(array[min_pos].word[0], array[min_pos].repeat)
    

    这是因为std::tie 创建了一个对其参数的左值引用元组。 (这意味着std::tie 需要变量。如果您想比较函数std::make_tuplestd::forward_as_tuple 的结果会更好)

    std::tupleoperators

    按字典顺序比较 lhs 和 rhs,即比较第一个元素,如果相等,比较第二个元素,如果相等,比较第三个元素,依此类推。

    而上面的描述也是如何进行多值比较的思路。

    【讨论】:

    • OP 想要长度,没有repeat
    • 好的,我已将您的代码和tuple 库添加到我的项目中,但没有任何反应。就像它只是不执行。我已经读过std::tie 有一段时间了,但我想我错过了一些东西。
    • @enjoy 您在哪里使用此代码?在if 语句中?
    • @Jarod42 我认为repeat 是另一个要比较的变量。我修改了答案,建议在必须比较函数结果时使用make_tuple
    • 我会结合这个答案并在“制作比较器函数”中使用它。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-01-26
    • 2017-11-17
    • 1970-01-01
    • 1970-01-01
    • 2021-12-28
    • 2018-03-11
    相关资源
    最近更新 更多