什么是适用于嵌入式系统的排序算法?

时间:2011-09-09 05:44:43

标签: algorithm sorting embedded

我正在为嵌入式系统开发软件,我需要实现一个排序例程,而我在选择最佳解决方案时遇到了麻烦。我的要求如下:

  1. 因为这是一个非常受内存限制的系统,所以空间复杂性是一个主要因素。
  2. 由于要排序的元素数量通常很少,而排序只会偶尔发生,因此时间复杂度不一定是主要因素。
  3. 我的应用程序需要稳定的算法。
  4. 因为这是一个嵌入式系统,所以代码大小是一个因素。
  5. 无法保证数据最初的排序几乎是按顺序排列。
  6. 我考虑过以下算法:

    • 冒泡排序(是的,即使我很惭愧地说出来)
    • gnome sort
    • 插入排序
    • 就地合并排序(虽然在我看来,链接列表比数组更理想?)

    虽然答案(对于我的确切情况)可能很好,“呃,呃,这并不重要,对我们所关心的所有人使用冒泡排序”,这个答案并不是很有用。 通常,哪种排序算法对嵌入式系统有用?

6 个答案:

答案 0 :(得分:9)

插入排序也很好,它在实践中运行速度快,稳定且就地。它与gnome排序非常相关,在实践中更快但是对于gnome排序,代码更小并且它需要更少的辅助空间(不是大O,差异在常量中)

编辑:是的,我搞砸了一下,让他们逆转了 - 我可能不应该在喝咖啡之前回答问题..之前说插入​​排序的代码和空间比gnome排序少

答案 1 :(得分:6)

不要为泡泡排序感到羞耻,它有它的位置。如果你的数据集很小,那么它很容易编码并且如果你做得正确就是稳定的(不要交换相同的元素)。

如果您的数据主要按照每次通过的交替方向进行排序,那么它也可能非常快。我知道你说它最初并没有接近排序,我正在谈论如果你排序然后坚持下去的可能性。在任何一种情况下,如果数据集大小很小,那么它是否完全未排序并不重要。

如果正如您在另一个答案的评论中提到的那样,您的数据集大小约为11,那么特别是的情况。如果明确设计的排序算法不足故意骇人听闻,任何算法都可以很快地处理这样的大小。

如果您的环境不能提供稳定的排序,我会根据您的约束和属性选择冒泡排序。


事实上,使用以下程序和time实用程序,我发现用于qsort和冒泡排序的CPU时间只有在元素计数达到10,000时才开始产生差异。

而且,即便如此,泡沫排序还不到半秒钟。除非你每秒要做很多种,否则这将是无关紧要的。

#include <stdio.h>
#include <stdlib.h>

static int data[10000];
#define SZDATA (sizeof (*data))
#define NMDATA (sizeof (data) / sizeof (*data))

int compfn (const void *a, const void *b) {
    if (*((int*)a) > *((int*)b))
        return 1;
    if (*((int*)a) < *((int*)b))
        return -1;
    return 0;
}

int main (void) {
    int i, tmp, swapped, count;

    for (i = 0; i < NMDATA; i++)
        data[i] = (i * 3) % 11;

    if (0) {
        qsort (data, NMDATA, SZDATA, compfn);
    } else {
        swapped = 1;
        count = NMDATA;
        while (swapped) {
            swapped = 0;
            for (i = 1; i < count; i++) {
                if (data[i] < data[i-1]) {
                    tmp = data[i];
                    data[i] = data[i-1];
                    data[i-1] = tmp;
                    swapped = 1;
                }
            }
            count --;
        }
    }

    //for (i = 0; i < NMDATA; i++)
        //printf ("%10d\n", data[i]);

    return 0;
}

通过改变data数组和if (0)语句的大小,我得到了以下结果(以毫秒为单位),每种情况下有五次运行:

Data size | qsort | bubble
----------+-------+-------
      100 |    61 |     76
          |    76 |     76
          |    77 |     61
          |    61 |     60
          |    61 |     61  avg qsort = 67, bubble = 67

     1000 |    77 |     93
          |    61 |     45
          |    76 |     77
          |    77 |     76
          |    76 |     77  avg qsort = 73, bubble = 74
          |       |
    10000 |    92 |    414
          |    77 |    413
          |    61 |    413
          |    76 |    405
          |    61 |    421  avg qsort = 73, bubble = 413

我怀疑由于缺少函数调用,因此使用小数据集进行更快速的气泡排序。

从中可以看出,对于较小的数据集,算法的效率通常并不重要,因为像big-O这样的东西通常与数据集变大时相关。

但是,此测试是在我的环境中完成的,您的测试可能会有很大差异。我建议在你的环境中执行相同的测量 - 实现冒泡排序,只考虑在必要时转移到更复杂的算法。


根据评论者的建议,我使用srand(42)然后rand()重新运行测试以填充数组元素。在这种情况下,对于冒泡排序,结果仅稍微差一点,对于10,000个元素为642对413毫秒,对于1,000个对象为82对74毫秒。

考虑到问题中的限制(小元素数,不常排序,稳定性要求,低空间复杂度),我仍然更喜欢将气泡排序简单化为任何更复杂的算法。

但是,请记住我之前的建议:您需要在自己的环境中计时。结果可能大不相同。您可以使用我提供的代码作为执行此操作的基准。说真的,如果你选择的方法花费的时间不到一秒钟,那么它可能足以满足你的目的。

答案 2 :(得分:3)

系统嵌入与否的事实并不重要。重要的是您列出的因素:代码大小限制,可用内存,所需速度和元素数量。

根据您的概述,冒泡排序是一种完全可以接受的解决方案:它小巧,可预测,易于内存,并且非常易于实现和调试。我在20世纪80年代早期看到了一个证据,即对于 n ≤11,气泡排序是时间最佳的。现代快速排序有可能略微改变,但我怀疑收支平衡可能会减少很多。 / p>

要使不稳定的排序算法稳定,请添加包含原始位置的排序键。仅当主要是平局时才参考辅助密钥。

答案 3 :(得分:2)

删除“在嵌入式系统上”并将问题更改为“通常,哪种算法有用”。接下来,试试吧!到目前为止你尝试了什么,内存消耗是什么,执行时间是什么,代码大小是多少?

嵌入式或桌面式您应该执行这些实验并询问这些问题。没有一般答案,因为没有一般要求。每种解决方案都取决于要求。一种尺寸适合所有人都不合适。真正的问题是您的要求是什么,然后您担心实施并满足这些要求。甚至是必需的,这可以用不同的方式解决吗?这种类型适合您的整体性能数字?帐篷里的其他长杆是什么?

就像在桌面上一样,对它们进行编码并尝试它们,看看你提出了什么。提及泡沫排序从来没有理由感到尴尬。如果你的要求没有性能或大小数字,泡泡排序是好的,每个人都可以阅读和理解代码,简单,可维护,不依赖于库或库的版本等。不是一件坏事可以说(如果有的话)没有性能要求)。

答案 4 :(得分:1)

Sorting in Embedded Systems,Nigel Jones关于嵌入式大师的文章值得一看。

他得出结论,shell sort是他根据代码大小和性能选择的排序算法。

答案 5 :(得分:0)

嵌入式系统的限制因目标平台和应用要求而异,通常需要在竞争因素之间进行权衡。您需要考虑的因素可能包括:

  • 确定性执行时间
  • 确定性内存使用
  • 最小化时间
  • 最小化内存使用
  • 代码大小

例如,您可能有一个算法平均使用的内存很少,但内存量与排序中的项目数不成线性关系。然后,您可能最好使用一个平均值使用更多内存的算法,但内存使用更有界或线性。类似地,对于执行速度,非确定性算法取决于初始顺序,而其他算法对初始顺序的依赖性较小或不变。

在这种情况下,您可能会将内存使用问题优先于执行速度。

所以答案是没有单一的答案,这取决于你的具体要求和约束。这个useful comparison table应该用于帮助您选择最合适的算法。

所有这一切,为了加速开发,总是值得尝试编译器标准库提供的标准qsort()函数。如果这对您有用,则符合您的约束条件,无需进一步的工作。