排序算法全解析:归并排序、非递归实现与映射型排序 - 指南


前言
大家好啊,我是云泽Q,欢迎阅读我的文章,一名热爱计算机技术的在校大学生,喜欢在课余时间做一些计算机技术的总结性文章,希望我的文章能为你解答困惑~
一、归并排序
归并排序算法思想:
归并排序(MERGE - SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。
例如下图数组,如果看整个数组是乱序的,但是如果把数组中的数组看作一个一个的数据,5是有序的,2是有序的…

然后通过合并两个有序序列的算法,就可以不断合并两个单独有序的数据,来让整个数组有序
下面这张图就完美的展示了在分治法中,归并排序是如何进行拆分和合并的
这张图的逻辑很好理解,接下来就是如何实现了,首先定义两个变量,left指向数组的起始位置,right指向数组的结束位置。(left+right)/2得到的就是二分的中间位置下标,以3这个位置,直接划分为[0,3],[4,7]两个序列
以此类推,下面的序列用同样的方法不断二分,当left等于right的时候就不能再进行二分了
若数组是奇数个数据依旧一样,(0+2)/2=1,分成[0,1],[2,2]两个序列,然后以依次类推
二分也是和二叉树一样的递归过程
归并排序和快速排序的参数有所不同,归并排序函数这里只需要两个参数,一个是指向数组的指针,一个是数组数据个数(n),给了n就知道数据下标范围是[0,n-1],然后在一个内部函数实现归并排序中分解的过程
接下啦就是合并了,第一次合并,10和6合并时先对两个序列取值,取到第一个值后比较,谁小谁放前,开一个临时的数组暂存合并后的结果,申请数组的大小和原数组大小一样(8个数据)

大致过程就是这样,接下来看代码的实现

由于归并排序是一个递归的代码,所以想要求时间复杂度就要按照递归算法的时间复杂度进行推理
在外层的MergeSort函数内没有循环,_MergeSort函数内的while循环是用于两个序列分开进行数据的比较,实际上可以看作是对一个数组进行遍历,所以单词递归的时间复杂度为n。分解是一个二叉树不断递归的过程,所以递归的次数就和二叉树的高度有关系,所以递归次数为logn
由于归并排序中malloc了一个和原数组一样大小空间的数组,所以其空间复杂度为O(n)
可以看到归并排序和希尔排序,快速排序,堆排序所花时间差不多
二、非递归版本归并排序



该代码有个问题就是没有处理奇数个数据的问题,偶数个数据的合并是没有问题的,奇数个数据两两合并就会出现多一个数据的情况,begin2 = end1+1 = 7,然而实际上并没有begin2,此时begin2就越界了,所以会出现有随机值的情况
4没有可以合并的右序列就把本次合并直接跳过,让其走到下一次的循环
接下来gap = 2,继续两两一组进行合并,4由于只有一个数据,其区间的begin2为6,其end2理论上来说等于i(4)+ 2 × gap - 1 = 7,但是该组end2为6
所以还需判断,若begin2没有越界,若end2越界了,还需特殊处理(end2变为n-1,n是7)


三、非比较排序
3.1 计数排序
计数排序又称为鸽巢原理,是对哈希直接定址法的变形应用。操作步骤:
- 统计相同元素出现次数
- 根据统计的结果将序列回收到原来的序列中

然后创建一个能存储10个整形数据大小的数组(count),然后把每个数据出现的次数放到该数组中,例如1出现了两次,就在下标为1的位置放2、2出现两次,就在下标为2的位置放2…其他没有赋值的地方统一给0,数据对应到count数组中就是下标,原数组中出现的次数在count数组中就是值
接下来就要把count数组中的数据还原到原数组9个空间中,遍历count数组中的数据,下标为0的位置值为0,不用管,然后遍历到下标为1的位置
下标1的位置有数据2,就把下标为1的值循环插入arr两次
插入完成之后,count数组中的i++
然后循环将下标为2的值循环插入arr数组两次,然后i++
3出现了0次,i继续++,4出现了3次,就在arr数组中把下标为4的值循环插入arr3次
之后i继续++,值为0继续++,然后把下标为6的值插入arr数组一次
然后i不断++走到下标为9的位置,把9往原数组插入一次
之后i再++,直到i越界。
这个过程并没有进行值大小的比较,然而数组已经有序
上面count数组的大小是直接给定了一个结果,接下来解释一下count数组的大小如何确定,若直接在原数组中找最大值,然后开最大值+1空间大小的数组,在下面的情况就会造成较严重的空间浪费,count数组实际上只使用了4个空间,然而却申请了110个空间大小

正确开辟的大小应该是max - min + 1 = 10,开辟10个空间大小的数组(0-9),虽然也存在空间浪费,但是浪费的并不多,这个过程就要通过映射的方式放到count数组当中,例如100出现一次,原本要在count数组下标100的位置放1,映射的方式就是data - min,这里data是100,min也是100,所以现在就是把100放到100-100对应下标的位置,100出现了1次,在下标为0的位置放1
101映射到count数组中,所以就是在下标为1的位置出现两次,同理105在下标为5的位置出现了两次,109在下标为9的位置出现了1次
至此,只开辟了10个空间,就可以把原数组数据重复的次数存储在count数组中
接下来进行数据的还原,把count数组的数据还原到原数组6个空间中,还是遍历count数组,i开始在下标为0的位置,要把数据存储在arr数组当中,这时就不是把0往arr数组中重复放1次了,而是让i加上min(100)再将结果循环的往arr数组中存放一 次
接下来i++,来到了下标为1的位置,1+100=101,把101循环的往arr数组中存放两次
之后i一直++,次数为0的依次++过去(这里没有标0),来到下标为5的位置,将105循环往arr插入两次
i++到下标为9的位置,109循环的往arr中插入一次
这样就完美解决了空间浪费的问题,注意前面6,1,2,9,4,2,4,1,4没有采用映射的方式把arr数组中的数据放到count数组中,且开辟的空间是10个,理应是开辟max-min+1(9-1+1=9)个空间的大小,前面的位置只是为了展示计数排序的大概过程和效果展示。
下面是代码实现

代码总的时间复杂度是n+n+range,也就是O(n+range)
空间复杂度是O(range)
这么一看计数排序是不是很厉害,但是在一些场景下,计数排序就会造成很大的性能浪费。
若现在有一个数组是[0,10000],给count数组开辟空间时就是max-min+1(10000-0+1),给两个数据创建了10001个空间的大小,造成了很大的空间浪费
计数排序在数据范围集中时,效率和稳定性都很高,可以说在一众排序算法中遥遥领先,但是使用范围及场景有限
四、排序算法复杂度及稳定性分析
稳定性:假定在待排序的记录序列中,存在多个具有相同的关键字的记录(重复的数据),若经过排序,这些记录的相对次序保持不变,即在原序列中,r[i]=r[j],且r[i]在r[j]之前,而在排序后的序列中,r[i]仍在r[j]之前,则称这种排序算法是稳定的;否则称为不稳定的
比如说现在数组中有重复数据
经过排序算法之后变为有序
这两个3相对次序保持不变即稳定
若重复的数据相对的顺序发生了交换,则该算法不稳定
稳定性对于程序来说是非常重要的,比如说在成绩排名中肯定会有很多重复的数据,例如现在有这些分值,98,96,95,95,94。这时候两位分值同为95分的同学,谁先交卷,谁的优先级就更高。此时若出现A同学交卷的速度比B同学快,但是成绩排序却比后交卷的同学成绩靠后,那就是算法的稳定性不好。
也算是一种场景的需求,若一个排序需要对类似学生交卷顺序的要求,这种情况就要求重复的数据相对顺序不能发生改变
冒泡排序由于是前后两个数据交换,而不会跨范围交换,所以说其是稳定的,比如说3,1,3排升序,相同的值是不会发生交换的
直接插入排序是将待排序序列中的数据往有序序列中插入,比如说现在存在重复的数据3,3,第一次把第一个3插入有序序列
接下来把第二个待排序序列中的3往前面插时,只有比已经排好序的3小才会往前放,和这个3相等只会往后面放
所以说直接插入排序算法稳定
归并排序:比如说现在有已经二分好的4个数据3,1,3,2。分别两组数据一合并结果如图
接下来两个序列再合并
二者合并之后顺序并不会交换
接下来再说4个不稳定的排序:
直接选择排序:现在有一个数组5,8,5,2,9。直接选择排序是直接在begin和end的范围内找最大和最小值


现在把2交换到5的位置,最大值和end位置进行交换,还是9
第一个5和2交换完成之后,第一个5来到了第2个5的后面,所以说是不稳定希尔排序:当gap>1时是进行预排序,gap=1是直接插入排序,若现在gap为2,即每隔两个数据为一组,5,2,9为一组,剩下的8,5为一组

现在每组分开进行直接插入排序,5,2,9排完序如图
8,5排序后变为5,8
可以看到第二个5排完序后来到了第一个5的前面,所以说该算法不稳定堆排序:

建立完堆后就要拿堆顶和最后一个数据进行交换
可以看到这时候顺序就已经发生改变了,所以该算法不稳定快速排序:以lumoto双指针法为例,定义prev和cur

接下来找基准值,找比5小的数据,cur找到了指向3,prev++,prev和cur指向同一个位置,数据不交换
cur继续向后走,指向的数据比基准值小,prev++,二者值相等不交换
cur继续往后走,又找到比基准值小的数据4,prev++,二者相等,值不交换
cur走到3还是一样
cur走到8后,找到了比基准值大的值
cur继续向后走找比基准值小的值,直到越界,此时prev指向3
3这个位置就是基准值的位置,接下来3和5交换,很明显重复的3顺序改变了
所以说快速排序不是稳定的排序算法
五、完整源码
Sort.h
#pragma once
#include<stdio.h>
#include<time.h>
#include<stdlib.h>
#include<memory.h>
//插入排序
//1)直接插入排序n^2
void InsertSort(int* arr, int n);
//2)希尔排序n^1.3
void ShellSort(int* arr, int n);
//选择排序
//1)直接选择排序n^2
void SelectSort(int* arr, int n);
//2)堆排序 nlogn
void HeapSort(int* arr, int n);
//交换排序
//1)冒泡排序
void BubbleSort(int* arr, int n);
//2)快速排序
void QuickSort(int* arr, int left, int right);
//非递归版本快速排序
void QuickSortNorR(int* arr, int left, int right);
//归并排序
void MergeSort(int* arr, int n);
//归并排序 - 非递归版本
void MergeSortNonR(int* arr, int n);
//非比较排序--计数排序
void CountSort(int* arr, int n);
Stack.h
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#include<assert.h>
//定义栈的结构
typedef int STDataType;
typedef struct Stack {
STDataType* arr;
int top; //指向栈顶的位置---刚好就是栈中有效数据个数
int capacity;//栈的空间大小
}ST;
//初始化
void STInit(ST* ps);
//销毁
void STDesTroy(ST* ps);
//入栈——栈顶
void STPush(ST* ps, STDataType x);
//出栈———栈顶
void STPop(ST* ps);
//取栈顶元素
STDataType STTop(ST* ps);
//栈是否为空
bool STEmpty(ST* ps);
//获取栈中有效元素个数
int STSize(ST* ps);
Sort.c
#define _CRT_SECURE_NO_WARNINGS 666
#include"Sort.h"
#include"Stack.h"
//1)直接插入排序
void InsertSort(int* arr, int n)
{
for (int i = 0; i < n - 1; i++)
{
int end = i;
int tmp = arr[end + 1];
while (end >= 0)
{
if (arr[end] > tmp)
{
arr[end + 1] = arr[end];
end--;
}
else {
break;
}
}
arr[end + 1] = tmp;
}
}
//希尔排序
void ShellSort(int* arr, int n)
{
int gap = n;
while (gap > 1)
{
gap = gap / 3 + 1;
for (int i = 0; i < n - gap; i++)
{
int end = i;
//当前组的下一个位置数据
int tmp = arr[end + gap];
while (end >= 0)
{
if (arr[end] > tmp)
{
arr[end + gap] = arr[end];
end -= gap;
}
else {
break;
}
}
arr[end + gap] = tmp;
}
}
}
void Swap(int* x, int* y)
{
int tmp = *x;
*x = *y;
*y = tmp;
}
//向下调整算法 logn
void AdjustDown(int* arr, int parent, int n)
{
int child = parent * 2 + 1;
while (child < n)
{
//建大堆:<
//建小堆: >
if (child + 1 < n && arr[child] < arr[child + 1])
{
child++;
}
//孩子和父亲比较
//建大堆:>
//建小堆:<
if (arr[child] > arr[parent])
{
Swap(&arr[child], &arr[parent]);
parent = child;
child = parent * 2 + 1;
}
else {
break;
}
}
}
//堆排序————使用的是堆结构的思想 n * logn
void HeapSort(int* arr, int n)
{
//向下调整算法——建堆n
for (int i = (n - 1 - 1) / 2; i >= 0; i--)
{
AdjustDown(arr, i, n);
}
////向上调整算法建堆n*logn
//for (int i = 0; i < n; i++)
//{
// AdjustUp(arr, i);
//}
//n*logn
int end = n - 1;
while (end > 0)
{
Swap(&arr[0], &arr[end]);
AdjustDown(arr, 0, end);//logn
end--;
}
}
//冒泡排序
void BubbleSort(int* arr, int n)
{
int exchange = 0;
for (int i = 0; i < n; i++)
{
for (int j = 0; j < n - i - 1; j++)
{
if (arr[j] > arr[j + 1])
{
exchange = 1;
Swap(&arr[j], &arr[j + 1]);
}
}
//经历一次循环exchange没有改变,没有发生交换
//说明数组本身有序,此时时间复杂度达到最好(n)
if (exchange == 0)
{
break;
}
}
}
////1)直接选择排序
//void SelectSort(int* arr, int n)
//{
// //找最小值
// for (int i = 0; i < n; i++)
// {
// int mini = i;
// for (int j = i + 1; j < n; j++)
// {
// if (arr[j] < arr[mini])
// {
// mini = j;
// }
// }
// //遍历完一遍后找到了最小值mini
// //将其放到下标为0的位置...
// Swap(&arr[mini], &arr[i]);
// }
//}
//1)直接选择排序
void SelectSort(int* arr, int n)
{
int begin = 0, end = n - 1;
while (begin < end)
{
//初始情况假定最大最小在下标为0的位置
int mini = begin;
int maxi = begin;
//在begin和end的范围内找最大和最小
for (int i = begin + 1; i <= end; i++)
{
if (arr[i] < arr[mini])
{
mini = i;
}
if (arr[i] > arr[maxi])
{
maxi = i;
}
}
//特殊情况处理,当maxi和begin在同一位置时
if (maxi == begin)
{
maxi = mini;
}
//找到最小最大值,和begin和end位置交换
Swap(&arr[begin], &arr[mini]);
Swap(&arr[end], &arr[maxi]);
begin++;
end--;
}
}
//找基准值 hoare版本
int _QuickSort1(int* arr, int left, int right)
{
int keyi = left; //初始基准值在数组最左边的位置
left++; //初始left在基准值右边
while (left <= right)
{
//right:从右往左走找比基准值小的值
while (left <= right && arr[right] > arr[keyi])
{
right--;
}
//left:从左往右找比基准值大的值
while (left <= right && arr[left] < arr[keyi])
{
left++;
}
//left和right交换
if (left <= right)
{
Swap(&arr[left++], &arr[right--]);
}
}
//right的位置就是基准值的位置
Swap(&arr[keyi], &arr[right]);
//返回当前基准值的下标
return right;
}
//找基准值 挖坑法
int _QuickSort2(int* arr, int left, int right)
{
int hole = left;
int key = arr[hole];
while (left < right)
{
//right 从右向左找比基准值小的值
while (left<right && arr[right]>key)
{
--right;
}
arr[hole] = arr[right];
hole = right;
//left 从左向右找比基准值大的值
while (left < right && arr[left] < key)
{
++left;
}
arr[hole] = arr[left];
hole = left;
}
arr[hole] = key;
return hole;
}
//找基准值 lumoto双指针法
int _QuickSort3(int* arr, int left, int right)
{
int prev = left, cur = prev + 1;
int keyi = left;
while (cur <= right)
{
//cur数据和基准值比较
if (arr[cur] < arr[keyi] && ++prev != cur)
{
Swap(&arr[cur], &arr[prev]);
}
//cur指向的数据不比基准值要小或prev++之后和cur指向同一个位置
cur++;
}
Swap(&arr[keyi], &arr[prev]);
return prev;
}
//2)快速排序
void QuickSort(int* arr, int left, int right)
{
if (left >= right)
{
return;
}
//找基准值
int keyi = _QuickSort3(arr, left, right);
//左序列[left,keyi-1] 右序列[keyi+1,right]
QuickSort(arr, left, keyi - 1);
QuickSort(arr, keyi + 1, right);
}
//非递归版本的快速排序---栈
void QuickSortNorR(int* arr, int left, int right)
{
ST st;
STInit(&st);
STPush(&st, right);
STPush(&st, left);
while (!STEmpty(&st))
{
//取栈顶两次
int begin = STTop(&st);
STPop(&st);
int end = STTop(&st);
STPop(&st);
//[begin,end]---找基准值
int keyi = begin;
int prev = begin, cur = prev + 1;
while (cur <= end)
{
if (arr[cur] < arr[keyi] && ++prev != cur)
{
Swap(&arr[prev], &arr[cur]);
}
++cur;
}
Swap(&arr[prev], &arr[keyi]);
keyi = prev;
//begin keyi end
//左序列[begin,keyi-1]
//右序列[keyi+1,end]
if (keyi + 1 < end)
{
STPush(&st, end);
STPush(&st, keyi + 1);
}
if (begin < keyi - 1)
{
STPush(&st, keyi - 1);
STPush(&st, begin);
}
}
STDesTroy(&st);
}
void _MergeSort(int* arr, int left, int right, int* tmp)
{
//分解
if (left >= right)//==也可以
{
return;
}
int mid = (left + right) / 2;
//根据mid将[left,right]划分左右两个序列:[left,mid] [mid+1,right]
_MergeSort(arr, left, mid, tmp);
_MergeSort(arr, mid + 1, right, tmp);
//合并两个序列:[left,mid] [mid+1,right]
int begin1 = left, end1 = mid;
int begin2 = mid + 1, end2 = right;
//临时数组下标
int index = left;
//循环比较
while (begin1 <= end1 && begin2 <= end2)
{
if (arr[begin1] < arr[begin2])
{
//放的位置和左序列的起始位置有关
tmp[index++] = arr[begin1++];
}
else {
tmp[index++] = arr[begin2++];
}
}
while (begin1 <= end1)
{
tmp[index++] = arr[begin1++];
}
while (begin2 <= end2)
{
tmp[index++] = arr[begin2++];
}
//tmp --》arr
for (int i = left; i <= right; i++)
{
arr[i] = tmp[i];
}
}
//归并排序
void MergeSort(int* arr, int n)
{
//临时数组
int* tmp = (int*)malloc(sizeof(int) * n);
//[0,n-1]
_MergeSort(arr, 0, n - 1, tmp);
free(tmp);
}
//非比较排序--计数排序
void CountSort(int* arr, int n)
{
//找max,min
int max = arr[0], min = arr[0];
for (int i = 1; i < n; i++)
{
if (arr[i] < min)
{
min = arr[i];
}
if (arr[i] > max)
{
max = arr[i];
}
}
//确定count数组的大小 max-min+1
int range = max - min + 1;
int* count = (int*)malloc(sizeof(int) * range);
if (count == NULL)
{
perror("malloc fail!");
exit(1);
}
//给count数组中的每个空间实现初始化 calloc/memset
//原位置 设置的初始值 多大的空间
memset(count, 0, sizeof(int) * (range));
//将原数组中重复的数据的次数依次放到count中
for (int i = 0; i < n; i++)
{
count[arr[i] - min]++;
}
//将count数组中的数据还原到原数组中
int index = 0;
for (int i = 0; i < range; i++)
{
while (count[i]--)
{
arr[index++] = i + min;
}
}
}
//归并排序 - 非递归版本
void MergeSortNonR(int* arr, int n)
{
//合并后的结果依旧保存在临时数组tmp之中
int* tmp = (int*)malloc(sizeof(int) * n);
if (tmp == NULL)
{
perror("malloc fail!");
exit(1);
}
//这里gap指每个要合并序列的数据个数
int gap = 1;
while (gap < n)
{
//根据gap划分组,两两一合并
for (int i = 0; i < n; i += gap * 2)
{
int begin1 = i, end1 = i + gap - 1;
int begin2 = i + gap, end2 = i + 2 * gap - 1;
//奇数个数据特殊处理
if (begin2 >= n)
{
break;
}
if (end2 >= n)
{
end2 = n - 1;
}
int index = begin1;
//两个有序序列进行合并
while (begin1 <= end1 && begin2 <= end2)
{
if (arr[begin1] < arr[begin2])
{
tmp[index++] = arr[begin1++];
}
else {
tmp[index++] = arr[begin2++];
}
}
while (begin1 <= end1)
{
tmp[index++] = arr[begin1++];
}
while (begin2 <= end2)
{
tmp[index++] = arr[begin2++];
}
//导入到原数组中,拷贝的目的地,拷贝的来源,多大空间
memcpy(arr + i, tmp + i, sizeof(int) * (end2 - i + 1));
}
gap *= 2;
}
}
Stack.c
#include"Stack.h"
//初始化
void STInit(ST* ps)
{
ps->arr = NULL;
ps->top = ps->capacity = 0;
}
//销毁
void STDesTroy(ST* ps)
{
if(ps->arr)
free(ps->arr);
ps->arr = NULL;
ps->top = ps->capacity = 0;
}
//入栈——栈顶
void STPush(ST* ps, STDataType x)
{
assert(ps);
//判断空间是否足够
if (ps->top == ps->capacity)
{
//增容
int newCapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;
STDataType* tmp = (STDataType*)realloc(ps->arr, newCapacity * sizeof(STDataType));
if (tmp == NULL)
{
perror("realloc fail!");
exit(1);
}
ps->arr = tmp;
ps->capacity = newCapacity;
}
//空间足够
ps->arr[ps->top++] = x;
}
//栈是否为空
bool STEmpty(ST* ps)
{
assert(ps);
return ps->top == 0;
}
//出栈———栈顶
void STPop(ST* ps)
{
assert(!STEmpty(ps));
ps->top--;
}
//取栈顶元素
STDataType STTop(ST* ps)
{
assert(!STEmpty(ps));
return ps->arr[ps->top - 1];
}
//获取栈中有效元素个数
int STSize(ST* ps)
{
assert(ps);
return ps->top;
}
test.c
#define _CRT_SECURE_NO_WARNINGS 666
#include"Sort.h"
void printArr(int* arr, int n)
{
for (int i = 0; i < n; i++)
{
printf("%d ", arr[i]);
}
printf("\n");
}
void test01()
{
//int a[] = { 5,3,9,6,2,4 };
int a[] = { 5,3,9,6,2,4,7,1,8 };
//int a[] = { 6,1,2,7,9,3 };
//int a[] = { 100,101,109,105,101,105 };
//int a[] = { 10,6,7,1,3,9,4,2 };
//用整个数组的大小/单个数据的大小 = 数组中数据个数
int n = sizeof(a) / sizeof(a[0]);
printf("排序之前:");
printArr(a, n);
//InsertSort(a, n);
//ShellSort(a, n);
//SelectSort(a, n);
//QuickSort(a, 0, n - 1);
//QuickSortNorR(a, 0, n - 1);
//MergeSort(a, n);
//CountSort(a, n);
MergeSortNonR(a, n);
printf("排序之后:");
printArr(a, n);
}
// 测试排序的性能对⽐
void TestOP()
{
srand(time(0));
const int N = 100000;
int* a1 = (int*)malloc(sizeof(int) * N);
int* a2 = (int*)malloc(sizeof(int) * N);
int* a3 = (int*)malloc(sizeof(int) * N);
int* a4 = (int*)malloc(sizeof(int) * N);
int* a5 = (int*)malloc(sizeof(int) * N);
int* a6 = (int*)malloc(sizeof(int) * N);
int* a7 = (int*)malloc(sizeof(int) * N);
for (int i = 0; i < N; ++i)
{
a1[i] = rand();
a2[i] = a1[i];
a3[i] = a1[i];
a4[i] = a1[i];
a5[i] = a1[i];
a6[i] = a1[i];
a7[i] = a1[i];
}
//在执行排序之前打印程序执行到此处的时间
int begin1 = clock();
InsertSort(a1, N);
//在执行排序之后打印程序执行到此处的时间
int end1 = clock();
int begin2 = clock();
ShellSort(a2, N);
int end2 = clock();
int begin3 = clock();
SelectSort(a3, N);
int end3 = clock();
int begin4 = clock();
HeapSort(a4, N);
int end4 = clock();
int begin5 = clock();
QuickSort(a4, 0, N - 1);
int end5 = clock();
int begin6 = clock();
MergeSort(a6, N);
int end6 = clock();
int begin7 = clock();
BubbleSort(a7, N);
int end7 = clock();
printf("InsertSort:%d\n", end1 - begin1);
printf("ShellSort:%d\n", end2 - begin2);
printf("SelectSort:%d\n", end3 - begin3);
printf("HeapSort:%d\n", end4 - begin4);
printf("QuickSort:%d\n", end5 - begin5);
printf("MergeSort:%d\n", end6 - begin6);
printf("BubbleSort:%d\n", end7 - begin7);
free(a1);
free(a2);
free(a3);
free(a4);
free(a5);
free(a6);
free(a7);
}
int main()
{
test01();
//TestOP();
return 0;
}
结语


浙公网安备 33010602011771号