【数据结构】第十章排序基本算法的总结+C++算法实现(附完整代码及测试样例)

第十章 排序

绪论

排序算法(英语:Sorting algorithm)是将一组特定的数据按某种顺序进行排列的算法。排序算法有许多,性质和复杂度也各不相同。

排序的稳定性

稳定性是指相等的元素经过排序之后相对顺序是否发生了改变。

假设 R i = R j R_i = R_j Ri=Rj ,且排序前序列中 R i R_i Ri 领先于 R j R_j Rj
若在排序后的序列中 R i R_i Ri 仍领先于 R j R_j Rj,则称排序方法是稳定的。
若在排序后的序列中 R j R_j Rj 领先于 R i R_i Ri,则称排序方法是不稳定的。

基数排序、计数排序、插入排序、冒泡排序、归并排序是稳定排序。

选择排序、堆排序、快速排序不是稳定排序。

排序的复杂度

内部排序vs.外部排序

  • 内部排序: 指的是待排序记录存放在计算机随机存储器(内存)中进行的排序过程。
  • 外部排序: 指的是待排序记录的数量很大,以致内存一次不能容纳全部记录,在排序过程中尚需对外存进行访问的排序过程。

下面我们介绍内部排序的相关算法。

内部排序

按照排序过程中所依据的原则的不同可以分类为 :

  1. 插入排序(希尔排序)
  2. 交换排序(快速排序)
  3. 选择排序(堆排序)
  4. 归并排序
  5. 基数排序

插入类

将无序子序列中的一个或几个记录“插入”到有序序列中,从而增加记录的有序子序列的长度。

直接插入排序

思想:利用有序表的插入操作进行排序

有序表的插入:将一个记录插入到已排好序的有序表中,从而得到一个新的有序表。插入排序是一种稳定排序。

算法步骤
  1. 将第一待排序序列第一个元素看做一个有序序列,把第二个元素到最后一个元素当成是未排序序列。
  2. 从头到尾依次扫描未排序序列,将扫描到的每个元素插入有序序列的适当位置。(如果待插入的元素与有序序列中的某个元素相等,则将待插入元素插入到相等元素的后面。)
代码实现
void insertion_sort(int a[] , int n){
  //对 a[0],a[2],...,a[n-1] 进行插入排序
  for(int i = 1 ; i <= n ; ++i){
    int key = a[i] ; //设置“哨兵”
    int j = i - 1 ;
    while (j > 0 && a[j] > key){
      a[j + 1] = a[j] ;
      --j ;
    }
    a[j + 1] = key ;
  }
}
时间分析

在插入排序中,当待排序数组是有序时,是最优的情况,只需当前数跟前一个数比较一下就可以了,这时一共需要比较 N − 1 N-1 N1次,时间复杂度为 O ( N ) O(N) O(N)

最坏的情况是待排序数组是逆序的,此时需要比较次数最多,总次数记为: 1 + 2 + 3 + … + N − 1 1+2+3+…+N-1 1+2+3++N1,所以,插入排序最坏情况下的时间复杂度为 O ( N 2 ) O(N^2) O(N2)

平均来说, A [ 1.. j − 1 ] A[1..j-1] A[1..j1]中的一半元素小于 A [ j ] A[j] A[j],一半元素大于 A [ j ] A[j] A[j]。插入排序在平均情况运行时间与最坏情况运行时间一样,是输入规模的二次函数。

希尔排序

希尔排序,也称递减增量排序算法,是插入排序的一种更高效的改进版本。但希尔排序是非稳定排序算法

希尔排序是基于插入排序的以下两点性质而提出改进方法的:

  • 插入排序在对几乎已经排好序的数据操作时,效率高,即可以达到线性排序的效率;
  • 但插入排序一般来说是低效的,因为插入排序每次只能将数据移动一位;

思想:先将待排序记录序列分割成为若干子序列分别进行直接插入排序。

待整个序列中的记录基本有序后,再全体进行一次直接插入排序。

算法步骤
  1. 选择一个增量序列 t 1 , t 2 , … … , t k t_1,t_2,……,t_k t1t2tk,其中 t i > t j , t k = 1 t_i > t_j, t_ k = 1 ti>tj,tk=1
  2. 按增量序列个数 k k k,对序列进行 k k k 趟排序;
  3. 每趟排序,根据对应的增量 t i t_i ti,将待排序列分割成若干长度为 m m m 的子序列,分别对各子表进行直接插入排序。仅增量因子为 1 1 1 时,整个序列作为一个表来处理,表长度即为整个序列的长度。
代码实现
/*希尔排序*/
void shell_sort(int a[], int length){
    int h = 1 ;
    while(h < length / 3){
        h = 3 * h + 1 ;
    }
    while(h >= 1){
        for(int i = h ; i < length ; i++){
            for(int j = i ; j >= h && a[j] < a[j - h] ; j -= h){
                int tmp = a[j] ;
                a[j] = a[j - h] ;
                a[j - h] = tmp ;
            }
        }
    h = h / 3 ;
    }
}
时间分析

希尔排序是按照不同步长对元素进行插入排序,当刚开始元素很无序的时候,步长最大,所以插入排序的元素个数很少,速度很快;当元素基本有序了,步长很小,插入排序对于有序的序列效率很高。所以,希尔排序的时间复杂度会比 O ( N 2 ) O(N^2) O(N2)好一些。

交换类

通过“交换”无序序列中的记录从而得到其中关键字最小或最大的记录,并将它加入到有序子序列中,以此方法增加记录的有序子序列的长度。

冒泡排序

冒泡排序是一种简单的交换算法,这个算法是稳定的排序。

思想: 通过不断比较相邻元素大小,进行交换来实现排序。

算法步骤
  1. 从数组起点开始扫描数组,每次比较扫描到的元素和其后面的元素,如果相邻两个元素满足交换关系,就交换它们。
  2. 循环进行上面的过程直到整个数组都被排好序。
  3. 算法优化:为了减少不必要的重复比较,设置一个“上一次最后一个交换的下标”,因为前面已经是交换好的,不再交换的一定是大小关系确定的,所以每一次外循环的i被更新为该下标即可,减少了不必要的比较次数。
代码实现
/*冒泡排序*/
void Bubble_sort(int a[] , int n){
    int i = n ;
    while(i > 0){
        int lastExchangeIndex = 0 ;
        for(int j = 0 ; j < i ; j++){
            if(a[j + 1] < a[j]){
                int tmp = a[j] ;
                a[j] = a[j + 1] ;
                a[j + 1] = tmp ;
                lastExchangeIndex = j ; //记录交换的位置
            }
        }
        i = lastExchangeIndex ; //本趟进行过交换的最后一个记录的位置
    }
}
时间分析

最好的情况(关键字在记录序列中顺序有序):只需进行 1 1 1趟起泡

​ 比较的次数: n − 1 n-1 n1;移动的次数: 0 0 0

最坏的情况(关键字在记录序列中逆序有序):需要进行 n − 1 n-1 n1趟起泡

​ 比较的次数: ∑ i = 2 n ( i − 1 ) = n ( n − 1 ) 2 \sum_{i=2}^n(i-1)=\frac{n(n-1)}{2} i=2n(i1)=2n(n1);移动的次数 3 n ( n − 1 ) 2 \frac{3n(n-1)}{2} 23n(n1)

快速排序

冒泡排序的改进版。

思想

  • 以首记录作为轴记录,从前、后双向扫描序列,通过交换,实现大值记录后移,小值记录前移,最终将轴记录安置在一个适当的位置。(小值记录在前、大值记录在后)
  • 轴记录将原序列分割成两部分,依次对前后两部分重新设定轴记录,继而分别再进行快速排序。
  • 直至整个序列有序。
算法步骤
  1. 从数列中挑出一个元素,称为 “基准”(pivot);

  2. 重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区(partition)操作;

  3. 递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序;

递归的退出条件是数列的大小是零或一,也就是都已经被排序好了。虽然一直递归下去,但是这个算法总会退出,因为在每次调用中,它至少会把一个元素摆到它最后的位置去。

代码实现
/*快速排序*/
int Paritition(int A[] , int low , int high){
    int pivot = A[low] ;
    while (low < high){
        while (low < high && A[high] >= pivot){
            --high ;
        }
        A[low] = A[high] ;
        while (low < high && A[low] <= pivot){
            ++low ;
        }
        A[high] = A[low] ;
    }
   A[low] = pivot ;
   return low ;
}

//快排母函数
void Quick_Sort(int A[] , int low , int high) {
    if(low < high){
    int pivot = Paritition(A , low , high) ;
    Quick_Sort(A, low, pivot - 1) ;
    Quick_Sort(A, pivot + 1, high) ;
    }
}
时间分析

在平均状况下,排序 n 个项目要 O ( n l o g n ) Ο(nlogn) O(nlogn)次比较。在最坏状况下则需要 O ( n 2 ) Ο(n^2) O(n2) 次比较,但这种状况并不常见。事实上,快速排序通常明显比其他 O ( n l o g n ) Ο(nlogn) O(nlogn)算法更快。

选择类

从记录的无序子序列中“选择”关键字最小或最大的记录,并将它加入到有序子序列中,以此方法增加记录的有序子序列的长度。

简单选择排序

思想:每一趟都选出一个最大或最小的元素,并放在合适的位置。

算法步骤
  1. 从头开始遍历数组(这是外循环),设置一个下标来在这个数后面的数组中遍历(内循环)。
  2. 如果满足条件就更新下标,最后如果下标与外循环此时的下标不同就交换这两个下标对应的值。
代码实现
/*简单选择排序*/
void Select_sort(int a[] , int n){
    for(int i = 0 ; i < n ; i++){
        int k = i ; 
        for(int j = i + 1 ; j < n ; j++){
            if(a[j] < a[k]) k = j ;
        }
        if(k != i){
            int tmp = a[i] ;
            a[i] = a[k] ;
            a[k] = tmp ;
        }
    }
}
时间分析

对 n 个记录进行简单选择排序,所需进行的 关键字间的比较次数总计为 ∑ i = 1 n − 1 n = n ( n − 1 ) 2 \sum_{i=1}^{n-1}n=\frac{n(n-1)}{2} i=1n1n=2n(n1)

移动的次数,最小为 0 0 0,最大为 3 ( n − 1 ) 3(n-1) 3(n1)

选择排序的主要操作是进行关键字间的比较。

n n n个关键字中选出最小值,至少需要 n − 1 n-1 n1次比较。

在剩余 n − 1 n-1 n1个关键字中选出最小值,至少需要 n − 2 n-2 n2次比较?(思考)

利用前 n − 1 n-1 n1次比较所得信息,可减少后面选择的比较次数。

堆排序

的概念: 一棵完全二叉树,任一个非终端结点的值均小于等于或大于等于其左、右儿子结点的值。分为大顶堆和小顶堆。

  • 大顶堆:每个节点的值都大于或等于其子节点的值,在堆排序算法中用于升序排列;
  • 小顶堆:每个节点的值都小于或等于其子节点的值,在堆排序算法中用于降序排列;

思想:将序列构造成一棵完全二叉树 ,然后将这棵普通的完全二叉树改造成堆,便可以获取最小(最大)值。每次输出最小(最大)值并删除根结点,再重复改造剩下的二叉树为堆,重复该过程就可以得到排序后的序列。

算法步骤
  1. 将待排序序列构建成一个堆 H [ 0 … … n − 1 ] H[0……n-1] H[0n1],根据(升序降序需求)选择大顶堆或小顶堆;
  2. 把堆首(最大值)和堆尾互换;
  3. 把堆的尺寸缩小 1 1 1,并把新的数组顶端数据调整到相应位置输出;
  4. 重复步骤 2,直到堆的尺寸为 1 1 1
  5. 得到的就是排好序的数组。
代码实现
/*堆排序*/
//已知 R[s..m]中记录的关键字除 R[s] 之外均满足堆的特征,本函数自上而下调整 R[s] 的关键字,使 R[s..m] 也成为一个大顶堆
void HeapAdjust(int a[] , int s , int e){
    int rc = a[s] ; //暂存a[s],s可以看作父亲结点的下标
    for(int i = 2 * s + 1 ; i <= e ; i *= 2){
        if(i + 1 <= e && a[i] < a[i + 1]) i++ ;
        if(a[s] >= a[i]) break ;
        else{
            a[s] = a[i] ;
            s = i ;
        }
        a[s] = rc ;
    }
}

//堆排序母函数
void Heap_Sort(int a[] , int length){
    //从最后一个结点的父亲结点开始,完成堆化
    for(int i = (length - 1 - 1) / 2 ; i >= 0 ; i--) HeapAdjust(a , i , length - 1) ;
    //先将第一个元素和已经排好的元素前一位作交换,再重新堆化,直到排序完成
    for(int i = length - 1 ; i > 0 ; i--){
        int tmp = a[0] ;
        a[0] = a[i] ;
        a[i] = tmp ;
        HeapAdjust(a , 0 , i - 1) ;
    }
}
时间分析

堆排序的平均时间复杂度为 O ( n l o g n ) Ο(nlogn) O(nlogn)

归并类

通过“归并”两个或两个以上的记录有序子序列,逐步增加记录有序序列的长度。

归并排序

归并: 将两个或两个以上的有序表合并成一个新的有序表。

之前已经学过的归并:有序线性表、有序链表的归并

思想: 将两个或两个以上的有序表合并成一个新的有序表。

初始, n n n 个记录看作是 n n n个有序的子序列,长度为 1 1 1

两两归并,得到 n 2 \frac{n}{2} 2n个长度为 2 2 2 1 1 1的有序的子序列 ;

重复执行直至得到一个长度为 n n n的有序序列为止 。

这种算法称之为 2 2 2路归并排序。

算法步骤
  1. 申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列;
  2. 设定两个指针,最初位置分别为两个已经排序序列的起始位置;
  3. 比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置;
  4. 重复步骤3直到某一指针达到序列尾;
  5. 将另一序列剩下的所有元素直接复制到合并序列尾。
代码实现
/*归并排序*/
void Merge(int a[], int i , int mid , int n){
    // 将有序的记录序列 a[i..m] 和 a[m+1..n]
    // 归并为有序的记录序列 tmp[i..n]
    int k = i ; 
    int j = mid + 1 ;
    int i0 = i ;
    int n0 = n ;
    int *tmp = (int *)malloc((n - i + 1)*sizeof(int));
    //归并步骤
    while(i<= mid & j <= n){
        if(a[i] <= a[j]) tmp[k++] = a[i++] ;
        else tmp[k++] = a[j++] ;
    }

    //处理剩余元素,将其加到尾上
    if(i <= mid){
        while(i <= mid){
            tmp[k++] = a[i++] ;
        }
    }
    else if(j <= n){
        while(j <= n){
            tmp[k++] = a[j++] ;
        }
    }
    //将这个临时数组放到原数组对应的位置上,完成局部的归并
    for(int index = i0; index <= n0 ; index++){
        a[index] = tmp[index] ;
    }
    //不要忘记释放指针
    free(tmp) ;
}
//归并排序母函数
void Merge_Sort(int a[] , int s , int e){
    int mid = 0 ;
    if(s < e){
        mid = (s + e) / 2 ;
        //递归调用归并排序当前数组的前半段
        Merge_Sort(a , s , mid) ;
        //递归调用归并排序当前数组的后半段
        Merge_Sort(a , mid + 1 , e) ;
        //将当前数组的前后两个part归并,得到
        Merge(a , s , mid , e) ;
    }
}
时间分析

归并排序是一种分治的思想,其时间复杂度为 O ( n l o g n ) O(nlogn) O(nlogn)

其他类

基数排序

基数排序借助“分配”和“收集”两种操作实现对单逻辑关键字的排序。

基数排序是一种非比较型整数排序算法,其思想是每次将待比较的数分割成好几个位,从低到高,按照位关键字相同的放在一起,将其中放在一起的数按照大小关系排好序,然后将其再依次串联,选取下一位,重复上面的操作,直到所有的位都被用完且串联在一起,这样得到的就是排好序的数组。

由于基数排序的算法实现需要定义一系列的数据结构来存储和实现,不大方便测试样例中的数组的排序,故在此不赘述。

对比和总结

排序算法平均时间复杂度最好情况最坏情况空间复杂度稳定性
插入排序 O ( n 2 ) O(n^2) O(n2) O ( n ) O(n) O(n) O ( n 2 ) O(n^2) O(n2) O ( 1 ) O(1) O(1)稳定
希尔排序 O ( n l o g n ) O(nlogn) O(nlogn) O ( n ) O(n) O(n) O ( n l o g 2 n ) O(nlog^2n) O(nlog2n) O ( 1 ) O(1) O(1)不稳定
冒泡排序 O ( n 2 ) O(n^2) O(n2) O ( n ) O(n) O(n) O ( n 2 ) O(n^2) O(n2) O ( 1 ) O(1) O(1)稳定
快速排序 O ( n l o g n ) O(nlogn) O(nlogn) O ( n l o g n ) O(nlogn) O(nlogn) O ( n 2 ) O(n^2) O(n2) O ( l o g n ) O(logn) O(logn)不稳定
选择排序 O ( n 2 ) O(n^2) O(n2) O ( n 2 ) O(n^2) O(n2) O ( n 2 ) O(n^2) O(n2) O ( 1 ) O(1) O(1)不稳定
堆排序 O ( n l o g n ) O(nlogn) O(nlogn) O ( n l o g n ) O(nlogn) O(nlogn) O ( n l o g n ) O(nlogn) O(nlogn) O ( 1 ) O(1) O(1)不稳定
归并排序 O ( n l o g n ) O(nlogn) O(nlogn) O ( n l o g n ) O(nlogn) O(nlogn) O ( n l o g n ) O(nlogn) O(nlogn) O ( n ) O(n) O(n)稳定
基数排序 O ( n × k ) O(n\times k) O(n×k) O ( n × k ) O(n\times k) O(n×k) O ( n × k ) O(n\times k) O(n×k) O ( n + k ) O(n+ k) O(n+k)稳定

完整代码及测试样例

#include <iostream>
using namespace std ;

/*插入排序*/
void insertion_sort(int a[] , int n){
    //对 a[1],a[2],...,a[n] 进行插入排序
    for(int i = 1 ; i < n ; i++){
        int key = a[i] ;
        int j = i - 1 ;
        while (j >= 0 && a[j] > key){
            a[j + 1] = a[j] ;
            --j ;
        }
        a[j + 1] = key ;
    }
}

/*希尔排序*/
void shell_sort(int a[], int length){
    int h = 1 ;
    while(h < length / 3){
        h = 3 * h + 1 ;
    }
    while(h >= 1){
        for(int i = h ; i < length ; i++){
            for(int j = i ; j >= h && a[j] < a[j - h] ; j -= h){
                int tmp = a[j] ;
                a[j] = a[j - h] ;
                a[j - h] = tmp ;
            }
        }
    h = h / 3 ;
    }
}

/*冒泡排序*/
void Bubble_sort(int a[] , int n){
    int i = n ;
    while(i > 0){
        int lastExchangeIndex = 0 ;
        for(int j = 0 ; j < i ; j++){
            if(a[j + 1] < a[j]){
                int tmp = a[j] ;
                a[j] = a[j + 1] ;
                a[j + 1] = tmp ;
                lastExchangeIndex = j ; //记录交换的位置
            }
        }
        i = lastExchangeIndex ; //本趟进行过交换的最后一个记录的位置
    }
}

/*快速排序*/
int Paritition(int A[] , int low , int high){
    int pivot = A[low] ;
    while (low < high){
        while (low < high && A[high] >= pivot){
            --high ;
        }
        A[low] = A[high] ;
        while (low < high && A[low] <= pivot){
            ++low ;
        }
        A[high] = A[low] ;
    }
   A[low] = pivot ;
   return low ;
}

//快排母函数
void Quick_Sort(int A[] , int low , int high) {
    if(low < high){
    int pivot = Paritition(A , low , high) ;
    Quick_Sort(A, low, pivot - 1) ;
    Quick_Sort(A, pivot + 1, high) ;
    }
}

/*简单选择排序*/
void Select_sort(int a[] , int n){
    for(int i = 0 ; i < n ; i++){
        int k = i ; 
        for(int j = i + 1 ; j < n ; j++){
            if(a[j] < a[k]) k = j ;
        }
        if(k != i){
            int tmp = a[i] ;
            a[i] = a[k] ;
            a[k] = tmp ;
        }
    }
}

/*堆排序*/
//已知 R[s..m]中记录的关键字除 R[s] 之外均满足堆的特征,本函数自上而下调整 R[s] 的关键字,使 R[s..m] 也成为一个大顶堆
void HeapAdjust(int a[] , int s , int e){
    int rc = a[s] ;
    for(int i = 2 * s + 1 ; i <= e ; i *= 2){
        if(i + 1 <= e && a[i] < a[i + 1]) i++ ;
        if(a[s] >= a[i]) break ;
        else{
            a[s] = a[i] ;
            s = i ;
        }
        a[s] = rc ;
    }
}

//堆排序母函数
void Heap_Sort(int a[] , int length){
    //从最后一个结点的父亲结点开始,完成堆化
    for(int i = (length - 1 - 1) / 2 ; i >= 0 ; i--) HeapAdjust(a , i , length - 1) ;
    //先将第一个元素和已经排好的元素前一位作交换,再重新堆化,直到排序完成
    for(int i = length - 1 ; i > 0 ; i--){
        int tmp = a[0] ;
        a[0] = a[i] ;
        a[i] = tmp ;
        HeapAdjust(a , 0 , i - 1) ;
    }
}

/*归并排序*/
void Merge(int a[], int i , int mid , int n){
    // 将有序的记录序列 a[i..m] 和 a[m+1..n]
    // 归并为有序的记录序列 tmp[i..n]
    int k = i ; 
    int j = mid + 1 ;
    int i0 = i ;
    int n0 = n ;
    int *tmp = (int *)malloc((n - i + 1)*sizeof(int));
    //归并步骤
    while(i<= mid & j <= n){
        if(a[i] <= a[j]) tmp[k++] = a[i++] ;
        else tmp[k++] = a[j++] ;
    }

    //处理剩余元素,将其加到尾上
    if(i <= mid){
        while(i <= mid){
            tmp[k++] = a[i++] ;
        }
    }
    else if(j <= n){
        while(j <= n){
            tmp[k++] = a[j++] ;
        }
    }
    //将这个临时数组放到原数组对应的位置上,完成局部的归并
    for(int index = i0; index <= n0 ; index++){
        a[index] = tmp[index] ;
    }
    //不要忘记释放指针
    free(tmp) ;
}
//归并排序母函数
void Merge_Sort(int a[] , int s , int e){
    int mid = 0 ;
    if(s < e){
        mid = (s + e) / 2 ;
        //递归调用归并排序当前数组的前半段
        Merge_Sort(a , s , mid) ;
        //递归调用归并排序当前数组的后半段
        Merge_Sort(a , mid + 1 , e) ;
        //将当前数组的前后两个part归并,得到
        Merge(a , s , mid , e) ;
    }
}

/*测试part*/

void test_insert(){
    int a[] = {49 , 38 , 65 , 97 , 76 , 13 , 27 , 48 , 55 , 4 , 19} ;
    insertion_sort(a , 11) ;
    for(int i = 0 ; i < 11 ; i++){
        cout << a[i] << ' ' ;
    }
    cout << endl ;
}

void test_shell(){
    int b[] = {49 , 38 , 65 , 97 , 76 , 13 , 27 , 48 , 55 , 4 , 19} ;
    shell_sort(b , 11) ;
    for(int i = 0 ; i < 11 ; i++){
        cout << b[i] << ' ' ;
    }
    cout << endl ;
}

void test_Bubble(){
    int c[] = {49 , 38 , 65 , 97 , 76 , 13 , 27 , 48 , 55 , 4 , 19} ;
    Bubble_sort(c , 10) ;
    for(int i = 0 ; i < 11 ; i++){
        cout << c[i] << ' ' ;
    }
    cout << endl ;
}

void test_Quick(){
    int d[] = {49 , 38 , 65 , 97 , 76 , 13 , 27 , 48 , 55 , 4 , 19} ;
    Quick_Sort(d , 0 , 10) ;
    for(int i = 0 ; i < 11 ; i++){
        cout << d[i] << ' ' ;
    }
    cout << endl ;
}

void test_Select(){
    int e[] = {49 , 38 , 65 , 97 , 76 , 13 , 27 , 48 , 55 , 4 , 19} ;
    Select_sort(e , 11) ;
    for(int i = 0 ; i < 11 ; i++){
        cout << e[i] << ' ' ;
    }
    cout << endl ;
}

void test_Heap(){
    int f[] = {49 , 38 , 65 , 97 , 76 , 13 , 27 , 48 , 55 , 4 , 19} ;
    Heap_Sort(f , 11) ;
    for(int i = 0 ; i < 11 ; i++){
        cout << f[i] << ' ' ;
    }
    cout << endl ;
}

void test_Merge(){
    int g[] = {49 , 38 , 65 , 97 , 76 , 13 , 27 , 48 , 55 , 4 , 19} ;
    Merge_Sort(g , 0 , 10) ;
    for(int i = 0 ; i < 11 ; i++){
        cout << g[i] << ' ' ;
    }
    cout << endl ;
}
int main(){
    test_insert() ;
    test_shell() ;
    test_Bubble() ;
    test_Quick() ;
    test_Select() ;
    test_Heap() ;
    test_Merge() ;
    return 0 ;
}

运行结果
排序算法测试结果
如有错误请多多指教!!!
参考资料

[1]Oi Wiki :https://oi-wiki.org/basic/sort-intro/

[2]图解排序算法(二)之希尔排序 :https://www.cnblogs.com/chengxiao/p/6104371.html

[3]数据结构(C语言版) 第2版 (严蔚敏等)

[4]百度百科-插入排序 https://baike.baidu.com/link?url=KlekmiNQt9t7DEdH-waoOzLN2eh6Nc1VL18b1iaaJpo1s_sioeHOnF78imOVpEV0LRF0yOYLKRDQ5X40sdvtL9A2RYKtleBeW9qyb59ukQQP5XddrfC5D7hLuCVPR-eH

[5]百度百科-希尔排序 https://baike.baidu.com/item/希尔排序

[6]《十大经典排序算法》https://github.com/zhangyuuao/JS-Sorting-Algorithm

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值