经典排序算法总结

目录

  • 交换排序
    • 冒泡排序
    • 快速排序
  • 插入排序
    • 直接插入排序
    • 希尔(shell)排序
  • 选择排序
    • 直接选择排序
    • 堆(Heap)排序
  • 归并排序

正文

排序方法 平均情况 最好 最差 空间复杂度 稳定性
冒泡排序 O ( n 2 ) O ( n ) O ( n 2 ) O ( 1 ) 稳定
快速排序 O ( n log n ) O ( n log n ) O ( n 2 ) O ( n log n ) 不稳定
直接插入排序 O ( n 2 ) O ( n ) O ( n 2 ) O ( 1 ) 稳定
shell排序 O ( n log n ) O ( n ) O ( n 2 ) O ( 1 ) 不稳定
选择排序 O ( n 2 ) O ( n 2 ) O ( n 2 ) O ( 1 ) 不稳定
Heap排序 O ( n log n ) O ( n log n ) O ( n log n ) O ( 1 ) 不稳定
归并排序 O ( n log n ) O ( n log n ) O ( n log n ) O ( n ) 稳定

交换排序

交换排序的基本思想都为通过比较两个数的大小,当满足某些条件时对它进行交换从而达到排序的目的。

1. 冒泡排序

基本思想:比较相邻的两个数,如果前者比后者大,则进行交换。每一轮排序结束,选出一个未排序中最大的数放到数组后面。

void bubbleSort(int *arr, int n) {
    for (int i = 0; i<n - 1; i++){
        for (int j = 0; j < n - i - 1; j++){
            //如果前面的数比后面大,进行交换
            if (arr[j] > arr[j + 1]) {
                int temp = arr[j]; arr[j] = arr[j + 1]; arr[j + 1] = temp;
            }
        }
    }
}

2. 快速排序

基本思想:选取一个基准元素,通常为数组第一个元素(或者最后一个元素)。从后向前遍历数组,当遇到小于基准元素的元素时,把它和左边第一个不小于基准元素的元素进行交换;然后从前往后遍历数组,交替执行上述过程,使基准元素确定自己的位置。在利用分治策略从已经分好的两组中分别进行以上步骤,直到排序完成。每轮循环确定一个元素的最终位置。

void quickSort(int *s, int left, int right){
    if (left< right){
        int i = left, j = right, x = s[left];
        while(i<j){
            while(i<j&&s[j]>=x)
                j--;
            if(i<j)
                s[i++]=s[j];
            while(i<j&&s[i]<x)
                i++;
            if(i<j)
                s[j--]=s[i];
        }
        s[i]=x;
        quickSort(s, left, i-1);
        quickSort(s, i+1,right);
    }
}
分析

  最差时间复杂度:每次选取的基准元素都为最大(或最小元素)导致每次只划分了一个分区,需要进行n-1次划分才能结束递归,故复杂度为 O ( n 2 ) ;最优时间复杂度:每次选取的基准元素都是中位数,每次都划分出两个分区,需要进行 log n 次递归,故时间复杂度为 O ( n log n ) ;平均时间复杂度: O ( n log n ) 。稳定性:不稳定的。辅助空间: O ( n log n )
  当数组元素基本有序时,快速排序将没有任何优势,基本退化为冒泡排序,可在选取基准元素时选取中间值进行优化。

插入排序

1.直接插入排序

  基本思想:不需要进行交换操作,而是用一个临时变量存储当前值。每一步将一个待排序的记录,插入到前面已经排好序的有序序列中去,直到插完所有元素为止。

void insertSort(int *s, int n){
    for(int i=1;i<n;i++){
        int tmp = s[i];
        int j;
        for(j=i-1;j>=0&&tmp<s[j];j--){
            s[j+1]=s[j];
        }
        s[j+1]=tmp;
    }
}
分析

  最坏时间复杂度为数组为逆序时,为 O ( n 2 ) 。最优时间复杂度为数组正序时,为 O ( n ) 。平均时间复杂度为 O ( n 2 ) 。辅助空间 O ( 1 ) 。稳定性:稳定

2.shell排序

  基本思想为在直接插入排序的思想下设置一个最小增量dk,刚开始dk设置为n/2。进行插入排序,随后再让dk=dk/2,再进行插入排序,直到dk为1时完成最后一次插入排序,此时数组完成排序。

void shellSort(int *s, int n){
    for(int r=n/2;r>0;r/=2){
        for(int i=r;i<n;i++){
            int tmp = s[i];
            int j=i-r;
            for(j;j>=0&&tmp<s[j];j-=r){
                s[j+r]=s[j];
            }
        s[j+r]=tmp;
        }
    }
}
分析

  最坏时间复杂度为 O ( n 2 ) 。最优时间复杂度为 O ( n ) 。平均时间复杂度为 O ( n 2 ) 。辅助空间 O ( 1 ) 。稳定性:不稳定。希尔排序的时间复杂度与选取的增量有关,选取合适的增量可减少时间复杂度。

选择排序

1. 直接选择排序

  基本思想:依次选出数组中最小的数放到数组的前面。首先从数组的第二个元素开始往后遍历,找出最小的数放到第一个位置。再从剩下数组中找出最小的数放到第二个位置。以此类推,直到数组有序。

void selectSort(int *s, int n){
    int min_num,tmp,index;
    for(int i=0;i<n;i++){
        min_num=s[i];
        index=i;
        for(int j=i+1;j<n;j++){
            if(s[j]<min_num){
                min_num=s[j];
                index=j;
            }
        }
        tmp=s[i];
        s[i]=s[index];
        s[index]=tmp;
    }
}
分析

  最坏时间复杂度为 O ( n 2 ) 。最优时间复杂度为 O ( n 2 ) 。平均时间复杂度为 O ( n 2 ) 。辅助空间 O ( 1 ) 。稳定性:不稳定。

2.Heap排序

  基本思想:将待排序列构造成完全二叉树,然后调整为大根堆或者小根堆,将堆顶元素与二叉树最后一个子节点交换,构造新的大根堆,重复上述步骤。

猜你喜欢

转载自blog.csdn.net/ppdd_0724/article/details/81506460