-
根号n段归并排序算法时间复杂度分析过程
2020-10-26 23:00:49根号n段归并排序算法时间复杂度分析过程: 1.合并 根号n向下取整 段子数组使用的是自底向上两两归并的策略 2.根号n段归并排序算法时间复杂度的数学推导 -
自然归并排序算法时间复杂度分析
2016-11-24 22:21:13最近在看一部美剧《breaking bad》,从中领会了不少东西。回头再看过去写的博客,感觉真是很糟糕。...这篇对自然归并排序算法时间复杂度的分析便是第一篇。 对于普通归并排序算法,我就不最近在看一部美剧《breaking bad》,从中领会了不少东西。回头再看过去写的博客,感觉真是很糟糕。真正自己的东西极少,大多数内容都是网上一搜一大堆的玩意,那么,这样的博客写着有什么意思呢?
从今往后,我的博客一定要写进自己的思想,就算没有创新,也一定要有独立思考求解的过程。
这篇对自然归并排序算法时间复杂度的分析便是第一篇。
对于普通归并排序算法,我就不赘述了。任何一本算法书籍都有介绍,随便用python写了一笔:
class Merge(): def __init__(self): self.tmp_arr = [0,0,0,0,0,0,0,0,0,0,0,0] def merge(self, arr, start, mid, end): for i in range(start, end+1): self.tmp_arr[i] = arr[i] j = mid + 1 k = start for i in range(start, end+1): if k > mid: arr[i] = self.tmp_arr[j] j += 1 elif j > end: arr[i] = self.tmp_arr[k] k += 1 elif self.tmp_arr[j] < self.tmp_arr[k]: arr[i] = self.tmp_arr[j] j += 1 else: arr[i] = self.tmp_arr[k] k += 1 def sort(self, arr, start, end): if end <= start: return mid = start + (end - start) / 2 self.sort(arr, start, mid) self.sort(arr, mid + 1, end) self.merge(arr, start, mid ,end) mobj = Merge() arr = [5,3,4,7,1,9,0,4,2,6,8] mobj.sort(arr, 0, len(arr)-1) for i in range(len(arr)): print arr[i]
其时间复杂度为O(nlogn),归并排序的比较是分层次来归并的(第一次是两两归并,之后再在第一次归并的基础上两两归并,每一层归并的次数为上一层除二,最终形成一二叉树,该二叉树的高即为归并次数logn。而每一层的比较次数恒等于n,所以时间复杂度求得nlogn)。自然归并排序算法是在归并排序算法基础上的改进,首先将数列中,已经有序的数分为小组,再在这些小组的基础上归并。
例如 5,3,4,7,1,9,0,4,2,6,8
则可首先得到{5},{3},{4,7},{1,9},{0,4},{2,6,8}
第一次归并得到{3,5},{1,4,7,9},{0,2,4,6,8}
第二次归并得到{1,3,4,5,7,9},{0,2,4,6,8}
可以看出,原理同样是二路归并,只不过最开始现将有序的部分划分了下。所以那一次‘划分了’多少个组,将决定以后的归并是否更顺利(树的层数更少)
普通归并排序的情况,第一次归并得到的组数为g = N/2
自然归并排序的情况,设第一次归并得到的组数为g,因为,一个数为一组的概率为1/2,两个数为一组的概率为1/4,n个数为一组的概率为2的n次方分之一。则可求得等式:
继续推导:
可知,在随机情况下,自然归并排序分的组数是与普通归并排序 无限趋近相等的。
结论:在分组数相等的基础上,继续进行二路归并,之后的‘二叉树’的高度便是一样的。所以时间复杂度同样为O(nlogn)。
然而,若已知待排序数列相对有序的情况,则自然归并排序算法是优于普通归并排序算法的。
-
归并排序时间复杂度_一文带你读懂排序算法(四):归并算法
2020-12-06 19:50:48算法思想归并排序的主要思想是分治法,排序的方法就是按照大小顺序合并两个元素,接着依次按照递归的返回顺序,不断地合并排好序的子数组,直到最后把整个数组的顺序排好。主要过程是:将n个元素从中间切开,...点击上方蓝字关注我们
归并排序的基本思想核心是分治,就是把一个复杂的问题分成两个或多个相同或相似的子问题,然后把子问题分成更小的子问题,直到子问题可以简单的直接求解,最原问题的解就是子问题解的合并。算法思想归并排序的主要思想是分治法,排序的方法就是按照大小顺序合并两个元素,接着依次按照递归的返回顺序,不断地合并排好序的子数组,直到最后把整个数组的顺序排好。主要过程是:
- 将n个元素从中间切开,分成两部分。(左边可能比右边多1个数)
- 将步骤1分成的两部分,再分别进行递归分解。直到所有部分的元素个数都为1
- 从最底层开始逐步合并两个排好序的数列
算法图解
举个例子,数组:[10,80,70,30,40]
- 分解
- 分解1
分解2
分解3
- 归并
归并1
归并2
归并3
以上是归并算法操作过程的简单图示。算法实现
代码实现:
public class MergeSort { public static void main(String[] args) { int[] arrays = {90,80,70,30,40}; mergeSort(arrays); System.out.println(Arrays.toString(arrays)); } public static void mergeSort(int[] array) { if (array == null || array.length == 0) return; int[] temp = new int[array.length]; mergeSort(array, 0, array.length - 1, temp); } // 归并 private static void mergeSort(int array[], int first, int last, int temp[]) { if (first < last) { int mid = (first + last) / 2; mergeSort(array, first, mid, temp); // 递归归并左边元素 mergeSort(array, mid + 1, last, temp); // 递归归并右边元素 mergeArray(array, first, mid, last, temp); // 再将二个有序数列合并 } } /** * 合并两个有序数列 * array[first]~array[mid]为第一组 * array[mid+1]~array[last]为第二组 * temp[]为存放两组比较结果的临时数组 */ private static void mergeArray(int array[], int first, int mid, int last, int temp[]) { int i = first, j = mid + 1; // i为第n次分解后第一组的起点, j为第n次分解后第二组的起点 int m = mid, n = last; // m为第n次分解后第一组的终点, n为第n次分解后第二组的终点 int k = 0; // k用于指向temp数组当前放到哪个位置 // 比较合并:将两个有序序列循环比较, 填入数组temp while (i <= m && j <= n) { if (array[i] <= array[j]) { temp[k++] = array[i++]; } else temp[k++] = array[j++]; } // 如果比较完毕, 第一组还有数剩下, 则全部填入temp while (i <= m) { temp[k++] = array[i++]; } // 如果比较完毕, 第二组还有数剩下, 则全部填入temp while (j <= n) { temp[k++] = array[j++]; } // 将排好序的数填回到array数组的对应位置 for (i = 0; i < k; i++) { array[first + i] = temp[i]; } }}
输出结果:
[30, 40, 70, 80, 90]
复杂度分析空间复杂度由于合并 n 个元素需要分配一个大小为 n 的额外数组,合并完成之后,这个数组的空间就会被释放,所以算法的空间复杂度就是 O(n)。归并排序也是稳定的排序算法。时间复杂度归并算法是一个不断递归的过程。
如何计算时间复杂度?
答:数组的元素个数是 n,时间复杂度是 T(n) 的函数。
把这个规模为 n 的问题分成两个规模分别为 n/2 的子问题,每个子问题的时间复杂度就是 T(n/2),那么两个子问题的复杂度就是 2×T(n/2)。当两个子问题都得到了解决,即两个子数组都排好了序,需要将它们合并,一共有 n 个元素,每次都要进行最多 n-1 次的比较,所以合并的复杂度是 O(n)。由此我们得到了递归复杂度公式:T(n) = 2×T(n/2) + O(n)。对于公式求解,不断地把一个规模为 n 的问题分解成规模为 n/2 的问题,一直分解到规模大小为 1。如果 n 等于 2,只需要分一次;如果 n 等于 4,需要分 2 次。这里的次数是按照规模大小的变化分类的。以此类推,对于规模为 n 的问题,一共要进行 log(n) 层的大小切分。在每一层里,我们都要进行合并,所涉及到的元素其实就是数组里的所有元素,因此,每一层的合并复杂度都是 O(n),所以整体的复杂度就是 O(nlogn)。排序算法 最好时间 平均时间 最坏时间 辅助存储 稳定性 备注 归并排序 O(nlog(n)) O(nlog(n)) O(nlog(n)) Ο(n) 稳定 n大时比较好 总结
归并排序需要一个跟待排序数组同等空间的临时数组,因此,使用归并排序时需要考虑是否有空间上的限制。如果没有空间上的限制,归并排序是一个不错的选择。100万的随机数字,归并排序大约耗时150毫秒。
建议:归并算法的思想很重要,其中对两个有序数组合并的操作,在很多面试题里都有用到,建议大家一定要把这个算法练熟。
—END—
扫码关注
点个“在看”表示朕
已阅
-
归并排序时间复杂度分析
2017-09-09 10:18:34归并排序时间复杂度分析主要参考了他的博文,他还讲解了其他排序的时间复杂度分析及算法实现。可以说合并排序是比较复杂的排序,特别是对于不了解分治法基本思想的同学来说可能难以理解。总时间=分解时间+解决问题...归并排序时间复杂度分析
主要参考了他的博文,他还讲解了其他排序的时间复杂度分析及算法实现。
可以说合并排序是比较复杂的排序,特别是对于不了解分治法基本思想的同学来说可能难以理解。总时间=分解时间+解决问题时间+合并时间。分解时间就是把一个待排序序列分解成两序列,时间为一常数,时间复杂度o(1).解决问题时间是两个递归式,把一个规模为n的问题分成两个规模分别为n/2的子问题,时间为2T(n/2).合并时间复杂度为o(n)。总时间T(n)=2T(n/2)+o(n).这个递归式可以用递归树来解,其解是o(nlogn).此外在最坏、最佳、平均情况下归并排序时间复杂度均为o(nlogn).从合并过程中可以看出合并排序稳定。
用递归树的方法解递归式T(n)=2T(n/2)+o(n):假设解决最后的子问题用时为常数c,则对于n个待排序记录来说整个问题的规模为cn。从这个递归树可以看出,第一层时间代价为cn,第二层时间代价为cn/2+cn/2=cn…..每一层代价都是cn,总共有logn+1层。所以总的时间代价为cn*(logn+1).时间复杂度是o(nlogn).
-
归并排序时间复杂度_每日排序算法知识(1)-时间复杂度
2020-12-06 19:50:48我去年给自己定了个今年存款3万块的小目标,掐指一算,现在还差5万...概念算法的时间复杂度是表示算法所消耗时间大小的量度,通常使用大O表示法来建立数学模型,即O(f(n)),随着n的数值增大,O(f(n))的数值增长的越...我去年给自己定了个今年存款3万块的小目标,掐指一算,现在还差5万。
又是定小目标的时间,2018年余额只有
2天
了,我参加了简书的坚持写作60天以上的活动,也算是激励自己吧。第一部分将跟大家分享算法与数据结构
相关的知识,共同学习。废说少话,day1开始。概念
算法的时间复杂度是表示算法所消耗时间大小的量度,通常使用
大O表示法
来建立数学模型,即O(f(n))
,随着n的数值增大,O(f(n))
的数值增长的越慢就越是时间复杂度低的算法大O阶推导
大O表示法
的关键在O里面的阶,推导大O阶
的步骤:1.用常数1取代运行时间中的所有加法常数。
2.在修改后的运行次数函数中,只保留最高阶项。
3.如果最高阶项存在且不是1,则去除与这个项相乘的常数。得到的结果就是大O阶。例子
常数阶
var a = 1, b = 1; //运行一次 var sum = a + b; //运行一次
运行了2次,按照推导方法,“2”是常数,应该用"1"来取代;然后就没有出现阶项,所以忽略后面两个推导步骤。所以这里的时间复杂度为
O(1)
。线性阶
for(var i = 0; i < 2*n+3; i++){ //执行了2*n+3次 sum +=n; }
执行次数为
2n+3
,按照第一步推导为2n+1
; 按照第二步推导修改为2n
(为什么呢?因为n=n1, 1=n0, 所以n的为最高阶项);第三条,2n
应该除以常数2;所以这里的时间复杂度为O(n)
。对数阶
var cout = 1; while(cout < n){ cout = cout * 2; }
假设循环次数为
x
, 则次表达式成立:2x = n, 及x = log2n, 时间复杂度为O(logn)
。平方阶
for(var i=0;i<n;i++){ for(var j=0;j<n;j++){ //时间复杂度O(1)的语句 } }
假设循环次数为n2,时间复杂度为
O(n^2)
时间复杂度的比较
常见的时间复杂度所耗费的时间大小关系:
O(1 )< O(logn) < O(n) < O(n*logn) < O(n^2) < O(n^3) < O(2^n) < O(n!) < O(n^n)
-
算法系列:(三).归并算法之>>两个升序数组的二元归并,时间复杂度O(m+n)
2018-08-22 14:20:20方法1:(利用数组作为容器): 特点: 1/结果为数组,合并后依然可以通过下标快速访问;...//两个升序数组进行升序归并(二元归并) 时间复杂度O(m+n) public class Test_AfterClass1 { public static void main(Stri... -
归并排序时间复杂度_排序算法(4)
2020-12-06 00:59:49姗姗来迟的排序算法的第四篇,本介绍归并排序算法,是不是有人会问这样的问题,现在书本上学习到的排序算法都太经典了,在实际生产环境中基本上不会直接拿来使用,如果你的上司让你实现一个归并或者快排在生成环境中... -
归并排序时间复杂度_堆排序过程、时间复杂度分析及改进
2020-12-06 19:50:47前言前面介绍过四种排序方法,其中快速排序和归并排序的平均时间复杂度都是 量级,今天要介绍堆排序,也是一种 平均复杂度的排序算法,这种排序算法是基于完全二叉树实现的,如果还不熟悉完全二叉树的同学,请自行... -
Day_12,归并排序时间复杂度计算
2020-04-13 20:36:35我们知道归并排序是利用 递归函数 进行计算的一种分治排序算法,因此对其时间复杂度也可以用递归的方式进行计算。 首先我们要知道分治算法的流程: 分解、计算(将分解后的进行排序)、合并 分解: 假设分解成a个... -
算法学习(二)对数器(python实现)、递归行为时间复杂度估算、归并排序时间复杂度
2018-09-23 17:19:051、用途:验证算法是否正确的一种方式。 2、使用: (1)有一个想测的方法func (2)实现一个绝对正确但是复杂度不好的方法RightMathod (3)实现一个随机样本产生器 (4)实现比对的方法 (5)把方法a和方法b... -
第一篇博客:对插入排序和归并排序算法时间复杂度的学习
2018-03-01 23:01:48刚看了网易公开课里的《 麻省理工学院公开课:算法导论》,受益颇深!国外学校的讲课方式确实更有趣味和深度(或许因为在学校压根没听进去过几节课),在评判一个软件的时候,有很多因素是比程序的性能让人更看重... -
排序算法时间复杂度、空间复杂度、稳定性比较
2017-07-30 21:33:22平均时间复杂度 最坏时间复杂度 空间复杂度 是否稳定 冒泡排序 :————-: :—–: :—–: :—–: 选择排序 :————-: :—–: :—–: :—–: 直接插入排序 :————-: :—–: :—–: :—–: ... -
java实现归并排序 时间复杂度O(log n) 的稳定算法
2019-11-13 21:23:16思路:对于给定的一组记录,首先将每两个长度为一的子序列进行归并,得到 n/2 个长度为一 2 或 1 的有序子序列,再将其两两归并,反复此过程,知道得到一个有序子序列。 package sortTest; public class ... -
归并排序时间复杂度_都2020年了,听说你还不会归并排序?手把手教你手写归并排序算法...
2020-12-09 14:40:34基本思想归并排序是建立在归并操作上的一种有效的排序算法,该算法是采用分治法的一个非常典型的应用。即先使每个子序列有序,再将已有序的子序列合并,得到完全有序的序列。这里给出一种递归形式的归并排序实现。... -
归并排序时间复杂度_听说你还不会归并排序?
2020-12-09 14:40:35基本思想归并排序是建立在归并操作上的一种有效的排序算法,该算法是采用分治法的一个非常典型的应用。即先使每个子序列有序,再将已有序的子序列合并,得到完全有序的序列。这里给出一种递归形式的归并排序实现。... -
理解归并排序的递归算法时间复杂度
2020-02-17 21:23:03首先这棵递归树的高度为lgn,其次,每一层的合并最差的比较效率是n-1,即O(n),从底层开始合并的话,这棵合并树总共需要合并O(nlgn) -
a*算法的时间复杂度_递归算法时间复杂度和空间复杂度分析
2020-11-27 07:53:39归并排序)快速排序quick_sort时间复杂度分析:注意:p = partition(a, l, r)这里的时间复杂度为O(n)最好情况:每次都是二分,T(n) = 2*T(n/2) + O(n) = O(nlogn)最坏情况:每次划分出一个数值,T(n) = T(n-1) + T(1... -
归并排序算法的时间复杂度
2019-07-10 17:37:12我们对n个元素进行归并排序,需要时间T(n), 那分解成两个子数组排序的时间都是T(n/2)。...归并排序的时间复杂度计算公式是: T(1) = C; n=1 时,只需要常量级的执行时间,所以表示为 C。 T(n) = 2*T(n/2... -
归并排序时间复杂度_你以为只是简单的排序?(二)
2020-12-08 01:29:20这篇文章,分享两种时间复杂度为O(nlogn)的排序算法,「归并排序」和「快速排序」。这两种排序算法适合大规模的数据排序,更加的常用一些归并排序归并排序思想归并排序核心思想:「将待排序的数据分成前后两个部分,... -
归并排序时间复杂度----主定理
2016-09-09 12:09:30这是《漫谈经典排序算法系列》第四篇,解析了归并排序。 各种排序算法的解析请参考如下: 《漫谈经典排序算法:一、从简单选择排序到堆排序的深度解析》 《漫谈经典排序算法:二、各种插入排序解析及性能... -
归并排序时间复杂度_归并排序之归与并,分与治?
2020-12-09 14:40:20归并排序 归并排序和之前的冒泡排序、插入排序和选择排序不同,其蕴含了一种分治的思想,关于分治和递归的思想之前有分享一篇文章 数据结构与算法之递归 + 分治 ,感兴趣的可以作为参考,不过在今天的图文中,同样会... -
归并排序时间复杂度_这都不会,还说自己精通 「归并排序」?
2020-12-09 14:40:18大佬请移步,小白请入坑~~归并排序的迭代实现 在正式看代码前,希望你心中清楚归并排序的递归实现方式,不熟悉也无妨,看这篇文章 图解「归并排序」算法(修订版) 文章。迭代和递归(Iteration & Recursion)本... -
算法分析——排序算法(归并排序)复杂度分析(代换法)
2018-07-19 23:07:49上篇文章中我们对归并排序的时间复杂度使用递归树法进行了简答的分析,并得出了结果归并排序的时间复杂度为,这里将使用代换法再进行一次分析。使用代换法解递归式的时候,主要的步骤有两步: 1)猜测解的结果 ... -
如何计算归并排序算法的时间复杂度?
2020-08-18 19:17:11如何计算归并排序的时间复杂度? 什么是归并排序? 归并排序的概念十分简单,就是“分而治之”的思想。这里我直接从网上找了一份对归并排序算法的比较好的介绍排序算法 。 计算时间复杂度 关键是怎么计算时间复杂度... -
算法分析——排序算法(归并排序)复杂度分析(主定理法)
2018-07-25 17:19:34前两篇文章中分别是要用递归树、代换法对归并排序的时间复杂度进行了简单的分析和证明,经过两次分析后,我们发现递归树法的特点是:可以很直观的反映出整个归并排序算法的各个过程,但因为要画出递归树所以比较麻烦... -
算法 归并排序的复杂度分析(含图解流程和Master公式)
2018-07-11 23:46:47通过图解分析归并排序流程,以及使用Master公式计算时间复杂度