掌握归并排序前首先理解递归行为

递归行为

“大事化小” 讲的就是一个递归的思想,把一个规模大的问题通过划分成小问题去解决,小问题继续划分

递归的联想理解

递归像是你在金字塔的顶端,要收集最底的宝藏,你每下一层看没有宝藏,找到了去往下一层的门,继续去下一层,层和层之间的楼梯都是一样的,看上去走的行程是一样的,实际上它们是不同的楼梯,等你走到底拿了宝藏,你还要一层一层再爬回去。

递归的基本思想

“有来有回” 以及常听到的 “自己调用自己”

当划分为多个子问题处理时,重要的一点是子问题解决了,才可以继续解决基于子问题的问题

举个例子

一个数组左边界是L,右边界是R,(L和R都是位置),我们想要寻找这个数组的最大值,我们现在将数组一分为二,分别找出数组左部分的最大值,和数组右部分的最大值,最后返回二者之中的最大值。
5,3,1,8,6,2
L,1,2,3,4,R

var maxArr = [5,3,1,8,6,2];
function getMax(arr,L,R){
	if(L == R){
	return arr[L];
	}
	var mid = (L+R)/2;
	var maxLeft = getMax(arr,L,mid);
	var maxRight = getMax(arr,mid+1,R);
	return max = Math.max(maxLeft,maxRight);
}
getMax(maxArr,0,maxArr.length-1);
console.log(max);

在这里插入图片描述

可以看到提示代码错误:
“Maximum call stack size exceeded” 超过最大调用栈大小

原来系统用的是栈结构来解决这个问题,不过我们先改写代码使它通过随后详细讲解。

我们将var mid = (L+R)/2;改为var mid = L + ((R - L) >> 1);
在这里插入图片描述
打印出数组最大值8

因为L,R表示下标时,L不会溢出,R不会溢出,L+R可能溢出,mid = (L+R)/2算出的mid可能是错误的,这样是不安全的,但mid = (L+(R-L)/2)<R,R不溢出,所以绝对不会有溢出问题,最后用右移运算抖机灵。

深入剖析递归行为

递归就是系统帮你压栈
递归函数getMax(arr,L,R)开始,系统准备一个栈,首先L和R相等吗,相等则说明数组只有一个元素则直接返回,否则继续。首先L=0,R=5,产生一个变量mid = 2,随后变量maxLeft需要子过程来产生,系统做的工作是把getMax(arr,0,5)以及代码跑到第几行,mid = 2等信息全部压入栈中,然后调用子过程,先当与这个函数被归挡,先跑子过程,继续跑getMax(arr,0,2),一直继续直到触发L == R,即执行 return arr[L]返回。然后进行弹栈操作,读取弹栈后的栈顶的信息,完全还原现场当时的信息,即发生到哪个子过程,代码跑到第几行,再继续执行之后的子过程,最终串起来子过程和父过程的通信。

任何递归行为都可以改成非递归
将系统压栈改成自己压栈,就变成了非递归,即迭代

递归行为的复杂度

Master公式
T(N) = aT(N/b) + O(Nd)
T(N)表示样本量为N的时间复杂度
T(N/b)表示子样本的样本量
a表示子过程发生的次数
O(Nd)表示除过子样本发生之后剩下的操作的时间复杂度

以之前的例子为例,在一个数组中寻找最大值,数组一切为2,整个数组样本量为N,左边一半,样本量为N/2,右边一般,样本量为N/2,左边跑完跑右边,样本量为N/2的过程发生了2次,跑完子过程之后,比对最大的数值然后返回,是常数量的复杂度。
即:T(N) = 2T(N/2)+O(1)

Master公式的使用

T(N) = a*T(N/b) + O(Nd)

  1. log(b,a) > d -> 复杂度为O(Nlog(b,a))
  2. log(b,a) = d -> 复杂度为O(Nd * logN)
  3. log(b,a) < d -> 复杂度为O(Nd)

划分子问题的规模一样才可以用master公式

上面的例子,a = 2, b = 2,d = 0 则O(N) = O(N)

一些补充

我们在分析一个问题写算法的时候,只关心一步,即父问题转换为子问题那一步,我们只需要知道它们大层面的关系,子问题继续转换子问题以及如何转换,转换多少次,不需要去关心。
划分是一个大范围对等的划分,例如:如果是奇数个数数组,划分为两部分,数据不对等也属于正确。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值