经典排序算法总结

目录

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

正文

排序方法平均情况最好最差空间复杂度稳定性
冒泡排序O(n2)O(n2)O(n)O(n)O(n2)O(n2)O(1)O(1)稳定
快速排序O(nlogn)O(nlog⁡n)O(nlogn)O(nlog⁡n)O(n2)O(n2)O(nlogn)O(nlog⁡n)不稳定
直接插入排序O(n2)O(n2)O(n)O(n)O(n2)O(n2)O(1)O(1)稳定
shell排序O(nlogn)O(nlog⁡n)O(n)O(n)O(n2)O(n2)O(1)O(1)不稳定
选择排序O(n2)O(n2)O(n2)O(n2)O(n2)O(n2)O(1)O(1)不稳定
Heap排序O(nlogn)O(nlog⁡n)O(nlogn)O(nlog⁡n)O(nlogn)O(nlog⁡n)O(1)O(1)不稳定
归并排序O(nlogn)O(nlog⁡n)O(nlogn)O(nlog⁡n)O(nlogn)O(nlog⁡n)O(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(n2)O(n2);最优时间复杂度:每次选取的基准元素都是中位数,每次都划分出两个分区,需要进行lognlog⁡n次递归,故时间复杂度为O(nlogn)O(nlog⁡n);平均时间复杂度:O(nlogn)O(nlog⁡n)。稳定性:不稳定的。辅助空间:O(nlogn)O(nlog⁡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(n2)O(n2)。最优时间复杂度为数组正序时,为O(n)O(n)。平均时间复杂度为O(n2)O(n2)。辅助空间O(1)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(n2)O(n2)。最优时间复杂度为O(n)O(n)。平均时间复杂度为O(n2)O(n2)。辅助空间O(1)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(n2)O(n2)。最优时间复杂度为O(n2)O(n2)。平均时间复杂度为O(n2)O(n2)。辅助空间O(1)O(1)。稳定性:不稳定。

2.Heap排序

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

void Swap(int *x,int *y){
    int tmp;
    tmp=*x;
    *x=*y;
    *y=tmp;
}


void Max_heap(int array[],int i,int heap_size){
    int largest;
    int left=2*i+1;
    int right=2*i+2;
    if(left<heap_size&&array[left]>array[i])
        largest=left;
    else
        largest=i;
    if(right<heap_size&&array[right]>array[largest])
        largest=right;
    if(largest!=i){
        Swap(&array[i], &array[largest]);
        Max_heap(array, largest, heap_size);
    }
}

void Build_max_heap(int array[],int heap_size){
    for(int i=(heap_size-1)/2;i>=0;i--){
        Max_heap(array, i, heap_size);
    }
}

void Heap_sort(int array[],int heap_size){
    Build_max_heap(array, heap_size);
    for(int i=heap_size-1;i>0;i--){
        Swap(&array[0], &array[i]);
        heap_size--;
        Max_heap(array, 0, heap_size);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值