概述
一、前言
到这里,数据结构的八大排序就算是全部写完了。这一期总结篇我们来测试一下八大排序的效率,印证一下八大排序的时间复杂度,以及深度剖析一下八大排序的稳定性问题。
二、八大排序
1、直接插入排序
文章链接
2、希尔排序
文章链接
3、堆排序
文章链接
4、快速排序(霍尔发、挖坑法、前后指针法、非递归方法)
文章链接
5、直接选择排序
文章链接
6、冒泡排序
文章链接
7、归并排序
文章链接
8、计数排序
文章链接
三、稳定性问题
稳定性
假定在待排序的记录序列中,存在多个具有相同的关键字的记录,若经过排序,这些记录的相对次序保持不变,即在原序列中,r[i]=r[j],且r[i]在r[j]之前,而在排序后的序列中,r[i]仍在r[j]之前,则称这种排序算法是稳定的;否则称为不稳定的。
1、直接插入排序 ——稳定
一般都是把小的数字插入到对应的位置,并不会影响其他有序数字的相对位置。
如图,我们只是会把 3 插入到序列中,而前面的 1 2 3 4 5 6的相对位置是没有变化的,所以直接插入排序是稳定的。
2、希尔排序 ——不稳定
其实这个很好理解,希尔排序一开始的间隔很大的时候得到的是大致有序的序列,而后间隔逐渐变小,排在前面的一些较大的数字还是可能会被换到后面去,这样就破坏的原先的有序的序列。
我们可以看到,原本的5排完第一轮之后结果还走到1的前面去了。
显而易见,希尔排序是不稳定的排序。
3、堆排序 ——不稳定
堆排序不管是向上调整还是向下调整,都是只注重父节点与子节点的大小关系,而兄弟节点之间大小关系很容易随着父节点和子节点的交换被打破。
4、快速排序 ——不稳定
快速排序因为是每次找到大于key和小于key的值来交换,还是有可能把较大的数放到了前面
这样的情况也是有可能的,最后还是需要调整5和4的位置,但是这样就打破了4 7 8 9之间的相对位置。
所以快速排序是不稳定的。
5、直接选择排序 ——不稳定
因为是直接在整个数组中找出最大和最小,通过交换之后放在数组头部和尾部,看着好像稳定,但是某些特定情况下还是会出现不稳定。
我们找到第一个8和第一个5的时候是要交换的,但是交换之后的8到了第二个8的右边,就打破了稳定性。
6、冒泡排序 ——稳定
冒泡排序虽然效率不高,但是稳定性还是可以的。因为冒泡排序是把大的数字逐渐往右移动,所以不存在打破稳定性一说,一定是从无序变成有序的,而且不会改变之前的元素相对位置。
7、归并排序 ——稳定
归并排序分到最细的时候排完之后有序元素的相对位置就不会再变了,因为剩下的归并然后排序都是从有序的数组中抽取数字进行有序排序,所以一定不会改变原来的相对位置。
详情参考下图:
计数排序不存在排序过程,这里就不探讨其稳定性问题了。
四、效率测试
在10000个数字测试下
时间复杂度O(N*logN)和O(N^2) 的差距还不是很大,但是还是能够看出:希尔排序、快排、堆排序、归并排序是很快的,特别是快排,基本没用时间。
100000个数字测试下
时间复杂度O(N*logN)和O(N^2) 的差距差距就非常明显了 ,快排还是最快的那个。所以,大家明白为什么企业考的最多的就是快排了吧,效率是非常高的。
10000000个数字测试案例博主就不测试了,需要时间过长……
有兴趣的小伙伴可以自己试试,下面附上测试代码:
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(a5, 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:%dn", end1 - begin1);
printf("ShellSort:%dn", end2 - begin2);
printf("SelectSort:%dn", end3 - begin3);
printf("BubbleSort:%dn", end7 - begin7);
printf("HeapSort:%dn", end4 - begin4);
printf("QuickSort:%dn", end5 - begin5);
printf("MergeSort:%dn", end6 - begin6);
free(a1);
free(a2);
free(a3);
free(a4);
free(a5);
free(a6);
free(a7);
}
int main()
{
TestOP();
return 0;
}
最后
以上就是呆萌早晨为你收集整理的八大排序总结篇的全部内容,希望文章能够帮你解决八大排序总结篇所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复