各种排序算法概览

Posted xytpai

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了各种排序算法概览相关的知识,希望对你有一定的参考价值。

快速排序(交换范式)

快速排序代码基本上背一遍就可以了,注意>=和<=个人认为不加也可以但是可能会超时。

// 一趟快排就是找到第一个元素的位置使得左边比它小右边比它大
int _quicksort(int *a, int low, int high) {
    int mid_value = a[low];
    while(low < high) {
        while(low < high && a[high] >= mid_value) high--;
        a[low] = a[high];
        while(low < high && a[low] <= mid_value) low++;
        a[high] = a[low];
    }
    a[low] = mid_value;
    return low;
}

void quicksort(int *a, int low, int high) {
    if (low < high) {
        int mid = _quicksort(a, low, high);
        quicksort(a, low, mid-1);
        quicksort(a, mid+1, high);
    }
}

冒泡排序(交换范式)

void bubblesort(int *a, int n) {
    for(int i=0; i<n-1; i++) {
        int flag = 0;
        for(int j=n-1; j>i; j--) {
            if (a[j-1] > a[j]) {
                int tmp = a[j-1];
                a[j-1] = a[j];
                a[j] = tmp;
                flag = 1;
            }
        }
        if (!flag) return;
    }
}

直接插入排序(插入范式)

比较简单就不贴代码了,就是从数组a的第二个元素开始往后迭代,找到一个值后插入到前面使整个数组有序。

希尔排序(插入范式)

代码题也不需要写,举例一趟增量为3排序子过程:

第0步 15 9 7 8 20 -1 4
第1步 15     8       4  ->  4      8       5
第2步    9     20       ->    9      20   
第3步      7      -1    ->      -1       7
(每一步都用直接插入排序获取)
第一趟得到: 4 9 -1 8 20 7 5

在此基础上,希尔排序遵循如下过程:

  • 从增量为n/2开始,逐趟增量减少一半进行上述操作,直到增量最终为1那一趟结束。

选择排序(选择范式)

非常简单,如果从小到大排,从索引0开始到结束,每一步选择后面最小的放在当前索引位置。

堆排序(选择范式)

推排序把数组看作一颗完全二叉树,大根堆意思是这颗二叉树的任何父节点永远大于子节点。
完全二叉树就是数组的每个元素依次填入一个完整的二叉树。
建大根堆过程:

  1. 从最后一个非叶结点开始,自底向上调整每一个非叶节点(从右向左从下到上)
  2. 调整操作:如果当前节点比两个儿子都大无需调整,否则找到最大的那个儿子把值与自己交换,再调整那个儿子直到叶结点。
    堆排序过程(建完堆后):
void heapsort(int *a, int n) {
    build_maxheap(a, n);
    for(int i=n-1; i>0; i--) {
        swap(a[0], a[i]); // 从后往前迭代,每次将堆顶输出到当前位置, 排序后为从小到大
        adjust(a, i-1); 
    }
}

归并排序

归并算法还是比较重要的,建议背一下,其功能是归并两个本来就有序的数组,使输出有序。

void merge(int *a, int low, int mid, int high, int *buffer) {
    // a[low:mid] 与 a[mid+1:high] 各自有序, 现在要输出一个有序的a[low:high]
    int i, j, k;
    for (k=low; k<=high; k++) buffer[k] = a[k]; //拷贝
    for (i=low, j=mid+1, k=low; k<=mid && j<=high; k++) {
        // i,j为两个有序数组的扫描指针, k为当前输出指针
        if (buffer[i] <= buffer[j]) a[k] = buffer[i++];
        else a[k] = buffer[j++];
    }
    while(i<=mid)  a[k++] = buffer[i++];
    while(j<=high) a[k++] = buffer[j++];
}

int *buffer = new int[n] // 需要开一个和输入一样大的数组
void mergesort(int *a, int low, int high) {
    if (low<high) {
        int mid = (low+high)/2;
        mergesort(a, low, mid);
        mergesort(a, mid+1, high);
        merge(a, low, mid, high, buffer); //归并放最后,这个算法是自底向上的
    }
}

基数排序

十进制基,优先低位基数排序过程:

  1. 建立10个队列
  2. 按照输入所有数最后一位(%10),放入这些队列(比如123就放入3号队列队尾)
  3. 从0~10将各个队列里的值输出
  4. 再按照倒数第二位放入队列(与2操作相似)
  5. 从0~10将各个队列里的值输出
  6. 一直继续直到最高位操作结束

排序算法特性表

算法 最好复杂度 平均复杂度 最坏复杂度 空间复杂度 稳定性
直接插入排序 O(n) O(n^2) O(n^2) O(1) Y
冒泡排序 O(n) O(n^2) O(n^2) O(1) Y
选择排序 O(n^2) O(n^2) O(n^2) O(1)
希尔排序 O(1)
快速排序 O(nlogn) O(nlogn) O(n^2) O(logn)
堆排序 O(nlogn) O(nlogn) O(nlogn) O(1)
2路归并排序 O(nlogn) O(nlogn) O(nlogn) O(n) Y
基数排序 O(d(n+r)) O(d(n+r)) O(d(n+r)) O(r) Y

以上是关于各种排序算法概览的主要内容,如果未能解决你的问题,请参考以下文章

在第6731次释放指针后双重免费或损坏

各种排序算法代码汇总

各种排序算法整理(附带习题及代码)

Java排序算法 - 堆排序的代码

程序员面试必问系列——各种排序算法比较

用Python实现各种排序算法