排序总结C


一、排序的概念

排序:所谓排序,就是使一串记录,按照其中的某个或某些关键字的大小,递增或递减的排列起来的操作。
稳定性:假定在待排序的记录序列中,存在多个具有相同的关键字的记录,若经过排序,这些记录的相对次序保持不变,即在原序列中,r[i]=r[j],且r[i]在r[j]之前,而在排序后的序列中,r[i]仍在r[j]之前,则称这种排序算法是稳定的;否则称为不稳定的。
内部排序:数据元素全部放在内存中的排序。
外部排序:数据元素太多不能同时放在内存中,根据排序过程的要求不能在内外存之间移动数据的排序。

二、常见的排序算法

在这里插入图片描述

1.排序测试

代码如下(示例):

// 排序实现的接口
// 插入排序
void InsertSort(int* a, int n);
// 希尔排序
void ShellSort(int* a, int n);
// 选择排序
void SelectSort(int* a, int n);
// 堆排序
void AdjustDwon(int* a, int n, int root);
void HeapSort(int* a, int n);
// 冒泡排序
void BubbleSort(int* a, int n)
// 快速排序递归实现
// 快速排序hoare版本
int PartSort1(int* a, int left, int right);
// 快速排序挖坑法
int PartSort2(int* a, int left, int right);
// 快速排序前后指针法
int PartSort3(int* a, int left, int right);
void QuickSort(int* a, int left, int right);
// 快速排序 非递归实现
void QuickSortNonR(int* a, int left, int right)
// 归并排序递归实现
void MergeSort(int* a, int n)
// 归并排序非递归实现
void MergeSortNonR(int* a, int n)
// 计数排序
void CountSort(int* a, int 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);
 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];
 }
 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();
 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);
 free(a1);
 free(a2);
 free(a3);
 free(a4);
 free(a5);
 free(a6);
}

排序OJ(可使用各种排序跑这个OJ)OJ排序链接

三、各类排序使用的场景以及复杂度

在这里插入图片描述
在这里插入图片描述

1.插入排序

  1. 直接插入排序
    使用场景:当序列中的记录基本有序或n值较小
    时间复杂度最坏😮(N ^ 2) : 1+2+3+…+n-2+n-1 平均😮(N ^ 2) 最好😮(N)
    何时时间复杂度最低:所需排序的数组是有序的,只需执行一次从头到尾的插入操作,而每次插入操作都这是进行一次比较,实际上是n次比较操作,其时间复杂度为O ( n )
    何时时间复杂度最高:何时时间复杂度最高:所需排序的数组是倒序排列的,第n个元素需要n-1次比较操作和n次移位操作,其时间复杂度为O(N^2)
    稳定性:稳定
    原地排序
  2. 希尔排序
    使用场景:当序列中的记录基本无序,希尔排序是对直接插入排序的一种优化,可以用于大型的数组,希尔排序比插入排序和选择排序要快的多,并且数组越大,优势越大
    时间复杂度最坏😮(N ^ 2) 平均😮(NlogN~N ^ 2) 最好😮(N ^ 1.3)
    空间复杂度:O(1)
    稳定性:不稳定
    原地排序

2.选择排序

  1. 简单选择排序
    使用场景:当n值较小
    时间复杂度最坏😮(N ^ 2) 平均😮(N ^ 2) 最好😮(N ^ 2)
    空间复杂度:O(1)
    稳定性:不稳定
    原地排序
  2. 堆排序
    使用场景1. 堆排序虽然较之快排慢一些,但特别适合海量数据的排序。如在100万个数据里面找出前1000大的数据。可以用建立一个小顶堆存储1000元素。2. 堆排序所需的辅助空间少于快速排序,并且不会出现快速排序可能出现的最坏情况。3.优先队列通常用堆排序来实现。
    时间复杂度最坏😮(NlogN) 平均😮(NlogN) 最好😮(NlogN)
    空间复杂度😮(1)
    稳定性:不稳定
    原地排序

3.交换排序

  1. 冒泡排序
    使用场景:当n值较小,或趋近于有序的情况下
    时间复杂度最坏😮(N ^ 2) 平均😮(N ^ 2) 最好😮(N)
    何时时间复杂度最低:所需排序的数组是有序的,只需一次冒泡操作,其时间复杂度为:O(N)
    何时时间复杂度最高:所需排序的数组是倒序排列的,需要n次冒泡操作,其时间复杂度为:O(N^2)
    空间复杂度😮(1)
    稳定性:稳定
    原地排序
  2. 快速排序分治思想
    使用场景1.一般应用中,比其他排序快得多,适用于数组长度比较大的情况,对于小数组,快速排序比插入排序慢。2.如果数组中有大量重复元素,则用优化版快排比标准的快排效率高很多
    时间复杂度最坏😮(N ^ 2) 平均😮(NlogN) 最好😮(NlogN)
    何时时间复杂度最高:数组中有大量重复数据的时候
    空间复杂度😮(logN~N)
    稳定性:不稳定
    原地排序:每一段的快速排序都是通过交换操作是在原数组之上进行的,只需要常量级的临时空间用于交换,空间复杂度为O ( 1 ) O(1)O(1),是原地排序算法,但是由于快排本身为递归调用,所以产生的递归栈最好和平均情况下的空间复杂度为O(logn),最坏情况下的空间复杂度为O(n^2)。

4.归并排序:分治思想

  1. 使用场景1.适用于数据量特别庞大时,内部储存器不足以一次性处理这么多数据,则可适用分治的思想,将数据量分割成若干份,分别排序并归并,一般来说,归并排序与插入排序配合适用。2.若要求排序稳定,则可选用归并排序。但前面介绍的从单个记录起进行两两归并的排序算法并不值得提倡,通常可以将它和直接插入排序结合在一起使用。先利用直接插入排序求得较长的有序子序列,然后再两两归并之。因为直接插入排序是稳定的,所以改进后的归并排序仍是稳定的。3. 归并的缺点在于需要O(N)的空间复杂度,归并排序的思考更多的是解决在磁盘中的外排序问题
    时间复杂度最坏😮(NlogN) 平均😮(NlogN) 最好😮(NlogN)
    空间复杂度:O(N)
    稳定性:稳定
    非原地排序:由于归并操作需要创建n个内存空间用于存储归并的数组,所以不是原地排序算法,同时其为递归操作产生递归栈使用的空间复杂度为O(logN)
  • 24
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值