当前位置: 首页 > news >正文

排序(归并排序,非比较排序)

归并排序

归并排序(MERGE-SORT)是建⽴在归并操作上的⼀种有效的排序算法,该算法是采⽤分治法(Divide and Conquer)的⼀个⾮常典型的应⽤。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成⼀个有序表,称为⼆路归并。

算法分析

分解:利用mid=(left+right)/2求出中间值,利用左侧[left,mid],右侧[mid+1,right]的划分,分解的结束条件是数组的长度为1时。

递归合并:数组递归的结束条件时当left>=right,类似与二叉树的尾插,然后对左右两侧的数组进行比大小后合并,依次上返回。

 算法特性

‧ 时间复杂度为 O(n log n):划分产生高度为 log n 的递归树,每层合并的总操作数量 为 n ,因此总体时间复杂度为 O(n log n) 。

‧ 空间复杂度为 O(n):递归深度为 log n,使用 O(log n) 大小的栈帧空间。合并操作需 要借助辅助数组实现,使用 O(n) 大小的额外空间。

‧ 稳定排序:在合并过程中,相等元素的次序保持不变。   

源代码

//归并排序
void _MergeSort(int* arr, int left, int right, int* tem)
{//递归if (left >= right){return;}int mid = (left + right) / 2;_MergeSort(arr, left, mid, tem);_MergeSort(arr, mid + 1, right, tem);//合并int bagan1 = left, bagan2 = mid + 1;int end1 = mid, end2 = right;int index = bagan1;while (bagan1 <= end1 && bagan2 <= end2){if (arr[bagan1] < arr[bagan2]){tem[index++] = arr[bagan1++];}else{tem[index++] = arr[bagan2++];}}//越界情况//2越界的情况while (bagan1<=end1){tem[index++] = arr[bagan1++];}//1越界的情况while (bagan2 <= end2){tem[index++] = arr[bagan2++];}for (int i = left; i <=right; i++){arr[i] = tem[i];}
}
void MergeSort(int* arr, int n)
{//开辟空间int* tem = (int*)malloc(sizeof(int) * n);_MergeSort(arr, 0, n-1,  tem);free(tem);
}

计数排序

算法分析

计数排序⼜称为鸽巢原理,是对哈希直接定址法的变形应⽤。操作步骤:

 1)统计相同元素出现次数

 2)根据统计的结果将序列回收到原来的序列中

如何解决空间浪费的情况:

因为,我记数排序要先开辟空间,把值放进去,但是当最大值较大,数据所在的区间又较为密集的时候,就会出现上述状况,造成空间的浪费。因此我们利用max-min算出所要开辟的空间的范围,从而避免空间的浪费。

如何进行存储负数:

我们知道负数在数组中是无法表示的,这时我们可能会想到,取绝对值,但是如果出现一个负数的绝对值后的值正好和原数组中某一个数一样是不是就会出现错误。解决方案:让最小的负数减去本身即可。

时间复杂度,空间复杂度

 空间复杂度:O(range)

时间复杂度:O(N +range),但是有同学会想难度不是时间复杂度:O(N*range)?

这里面内层循环就是n个数据循环n次,外层是一次遍历所以这里的时间复杂度是n+range,而不是range*n;

计数排序的特性

  1. 计数排序在数据范围集中时,效率很⾼,但是适⽤范围及场景有限。
  2. 只使用整数不适应小数。
  3. 稳定性高

源代码

//计数排序
void CountSort(int* arr, int n)
{//先确定范围int min = arr[0], max = arr[0];for (int i = 1; i < n; i++){if (arr[i] < min){min = arr[i];}if (arr[i] > max){max = arr[i];}}int range = max - min + 1;//开辟空间int* tem = (int*)malloc(sizeof(int) * range);if (tem == NULL){perror("malloc fail!!!");exit(1);}//初始化,利用memset函数memset(tem, 0, sizeof(int) * range);//for (int i = 0; i < n; i++){tem[arr[i] - min]++;}int index = 0;for (int i = 0; i < range; i++){//解决数据的重复出现,只要不为零就会输出,直到变为零位置while (tem[i]--){arr[index++] = i + min;}}
}

总结

稳定性:假定在待排序的记录序列中,存在多个具有相同的关键字的记录,若经过排序,这些记录的 相对次序保持不变,即在原序列中,r[i]=r[j],且r[i]在r[j]之前,⽽在排序后的序列中,r[i]仍在r[j]之 前,则称这种排序算法是稳定的;否则称为不稳定的。

数据结构结构初阶的排序基本上总结完毕了,这里我学了冒泡,插入,选择,快排,希尔,堆,归并,计数排序,这几种排序在时间复杂度,空间复杂度以及稳定性上各有各的优点。下面我们用一张图进行总结。


http://www.mrgr.cn/news/2699.html

相关文章:

  • Java面试篇(多线程相关专题)
  • 六、什么是SEO优化(搜索引擎优化)?SPA单页面应用如何实现SEO优化?
  • RCE编码绕过--php://filter妙用
  • Linux驱动开发基础(中断)
  • 【YOLO5 项目实战】(4)红外目标检测
  • [C++] map、set的 红黑树 封装(一)
  • python从入门到精通:数据容器
  • AI -- Machine Learning
  • Python基础:函数
  • 悬浮翻译软件下载哪一个?免费悬浮翻译工具评测
  • 第一批AI原住民开始变现:9岁小学生,用大模型写书赚1个w
  • 开发军用LabVIEW程序注意事项
  • 黑神话悟空对服务器有什么要求
  • 手写一个打印PDF方法,完美解决跨域问题
  • 【论文阅读】Retargeting and Respecializing GPU Workloads for Performance Portability
  • 详解华为项目管理,附华为高级项目管理内训材料
  • SwiftUI中 Swift Data 对象关联查询
  • 20240820模拟面试
  • LangGPT结构化提示词
  • Java学习框架