16 - 12 - 18 十大排序算法总结(三) 之 归并排序
来源:互联网 发布:微信小说系统源码 编辑:程序博客网 时间:2024/05/22 00:09
七、归并排序
堆排序的效率确实高,充分利用了完全二叉树的深度是(log2n+1)(下取整)的特性。
所以效率较高,但是其本身的构建变焦复杂,那有没有更简单的(完全二叉树)方法呢.
ex:{16,7,13,10,9,15,3,2,5,8,12,1,11,4,6}两两归并:!
上图 ↑ 就是一棵倒立的二叉树。
直观排序效果 ↓ :
// 归并排序,使用递归void MergeSort(SqList *L){ MSort(L->r, L ->r, 0, L->length-1);}// 将SR[s..t]归并排序为TR1[s..t]void MSort(int SR[],int TR1[],int s,int t) //L->r, L-r, 0, L->length-1 是实参{ int m; int TR2[MAXSIZE]; if (s == t) TR1[s] = SR[s]; else { // 将SR[s..t](r[0~length-1])平分为SR[s...m-1]和SR[m...t] (r[1~m] & r[m~length-1]) m = (s + t) / 2+1; MSort(SR, TR2, s, m-1); MSort(SR, TR2, m, t); // 将TR2[s..m-1]和TR2[m..t]归并到TR1[s..t] Merge(TR2, TR1, s, m-1, t); }}// 将有序的SR[i..m]和SR[m+1..n]归并为有序的TR[i..n]void Merge(int SR[], int TR[], int i, int m, int n){ int j, k, l; for (j = m+1, k = i; i <= m && j <= n; k++){ // 将SR中记录由小到大并入TR if (SR[i] < SR[j]) TR[k] = SR[i++]; else TR[k] = SR[j++]; } if (i <= m){ for (l = 0; l <= m - i; l++) // 将剩余的SR[i..m]复制到TR TR[k + l] = SR[i + l]; } if (j <= n){ for (l = 0; l <= n - j; l++) // 将剩余的SR[j..n-1]复制到TR TR[k + l] = SR[j + l]; }}
归并性功能分析:
总的时间复杂度(最好,最坏,平均都是)为:O(n*logn);
由于归并排序在归并过程中需要与原序列一样的空间来
存放归并结果、以及递归时深度为log2n的 栈空间,因此
空间复杂度为O(n+logn)
另外,归并排序是使用两两比较,不存在跳跃,
这在Merge()中的语句 if ( SR[i] 小于 SR[j] ) 可以看出
所以归并排序是一个稳定的排序算法。
总体来说,归并排序是一个比较占用内存,但效率高且稳定的算法。
下面介绍一个非递归版本的归并排序算法实现。
// 非递归版本的归并排序void MergeSort2(SqList *L){ // 申请额外空间 int* TR = (int *)malloc(L->length * sizeof(int)); int k = 1; while (k < L->length){ MergePass(L->r, TR, k, L->length); // 子序列长度加倍 k = 2 * k; MergePass(TR, L->r, k, L->length); k = 2 * k; }}// 将SR[]中相邻长度为s的子序列两两归并到TR[]void MergePass(int SR[], int TR[], int s, int n){ int i = 0; int j; while (i <= n - 2 * s){ // 两两归并 Merge(SR, TR, i, i + s - 1, i + 2 * s - 1); i = i + 2 * s; } if (i < n - s + 1) // 归并最后两个子序列 Merge(SR, TR, i, i + s - 1, n - 1); else{ // 若最后剩下单个子序列 for (j = i; j <= n - 1; j++) TR[j] = SR[j]; }}// 将有序的SR[i..m]和SR[m+1..n]归并为有序的TR[i..n]void Merge(int SR[], int TR[], int i, int m, int n){ int j, k, l; for (j = m+1, k = i; i <= m && j <= n; k++){ // 将SR中记录由小到大并入TR if (SR[i] < SR[j]) TR[k] = SR[i++]; else TR[k] = SR[j++]; } if (i <= m){ for (l = 0; l <= m - i; l++) // 将剩余的SR[i..m]复制到TR TR[k + l] = SR[i + l]; } if (j <= n){ for (l = 0; l <= n - j; l++) // 将剩余的SR[j..n-1]复制到TR TR[k + l] = SR[j + l]; }}
非递归版本的归并排序算法避免了递归时深度为log2nlog2n的栈空间,空间复杂度是O(n)O(n),并且避免递归也在时间性能上有一定的提升。应该说,使用归并排序时,尽量考虑用非递归方法。
1 0
- 16 - 12 - 18 十大排序算法总结(三) 之 归并排序
- 十大排序算法之归并排序算法
- 16 - 12 - 17 十大排序算法总结(二) 之 桶排序,堆排序
- 16 - 12 - 17 十大排序算法总结(一) 之 冒泡,简选,直插,希尔排序
- 16 - 12 - 19 十大排序算法总结(四) 之 快速排序
- 三大排序算法(快速排序,归并排序,堆排序)
- 十大排序算法总结
- 十大排序算法总结
- 十大排序算法总结
- 排序算法总结之归并排序
- 排序算法总结之归并排序
- 排序算法总结之归并排序
- 十大排序算法之插入排序
- 十大排序算法之计数排序
- 排序算法总结之快速排序、归并排序、shell排序
- 排序算法三归并排序
- 十大基础实用算法之归并排序和二分查找
- go语言十大排序算法总结
- 常用技术代码或问题快现-不断更新中
- 机器学习之异常检测
- HTML
- visio studio code 简介
- Python字典和集合
- 16 - 12 - 18 十大排序算法总结(三) 之 归并排序
- java.lang.NoSuchMethodError: antlr.collections.AST.getLine()I 解决方法
- 在CentOS 7上通过Apache和mod_wsgi运行Django应用
- Xcode 启动页面关闭 不显示
- 数组交换
- Matlab与线性代数 -- 矩阵的左右翻转、上下翻转和矩阵的逆时针旋转90操作
- Starting MySQL.. ERROR! The server quit without updating PID file
- 初始化块和静态初始化块
- 图片无限轮播