阅读 57

快速入门数据结构与算法之递归

前言

上一篇我们学习了数据结构与算法的顺序结构,虽然顺序结构比较多,但是都不难,下面我们将基于线性结构来学习递归算法。

定义

递归是一种解决问题的方法,其精髓在于将问题分解为规模更小的问题,持续分解,直到问题规模笑道可以用非常简单直接的方式来解决,其算法方面的明显特征就是:在算法流程中调用自身。递归简单来说就是四个字:“分解问题,调用自身”。递归就像套娃一样,我们需要先把东西放到最小的套娃中,将最小的套娃先套上,然后才能一层一层的往外套。再放个图感受一下下。

初识

我们运用上面的定义来试着解一道小题:求一个数列的和,现在让我们用递归算法来解答一下,首先,我们先解决最小规模的问题,即当一个数列只有一个数的时候,那么就直接返回这个数就行了。当问题的规模不断扩大的时候,我们就一个一个的算,不断调用自身并进行相加。代码如下:

function sum(...params) {
	if (params.length === 1) { // 最小规模
		return params[0]
	}
	return params[0] + sum2(...params.splice(1)) // 调用自身
}
console.log(sum2(1, 2, 3, 4, 5)) // 15
复制代码

是不是很简单?虽然我们顺利把它解了出来,但是最小规模还是有些抽象。我需要更细致专业的方法——递归“三定律”

  • 1.递归算法必须有一个基本结束条件
  • 2.递归算法必须能改变状态向基本结束条件演进
  • 3.递归算法必须调用自身

这样看来,上面的if语句便是基本结束条件,下面在调用自身的时候不断向基本结束条件演进。注意,函数的执行是从小规模向大规模执行的,也就是先执行的是sum(5)。

应用

介绍完递归“三定律”是不是对递归理解更加深入了呢,那么我们就大展拳脚来实战一番。

应用1:任意进制的转换

思路:用一个字符串来存储0-9A-F十六进制需要使用的16个符号,设置基本结束条件,即当给的数字已经是当前进制数时,不用再进行转换,直接返回即可。如果规模增大,调用自身传入除数,不断向基本结束条件演进,并在后面加上其余数。

实现代码如下

// 进制互相转换
function binaryConversion(number, binary) {
	const base = '0123456789ABCDEF';
	if (number < binary) { // 基本结束条件
		return base[number];
	}
	return (
		binaryConversion(number / binary, binary) + base[number % binary]; // 调用自身
	)
}
复制代码

应用2:汉诺塔

思路:先设置最小规模即基本结束条件,本题的最小规模就是一个盘子的时候,直接把它放到最右边的柱子即可,当盘子逐渐增多为n个的时候,我们都是需要两步,即将n-1个盘子先借助最后一个盘子放到中间的柱子,再把最后一个盘子放到最右边,然后把n-1个盘子借助第一个柱子放到最右边的柱子。

代码实现如下

function move(height, fromPole, withPole, toPole) {
   if (height >= 1) {
   	move(height - 1, fromPole, toPole, withPole)
   	moveResult(height, fromPole, toPole)
   	move(height - 1, withPole, fromPole, toPole)
   }
}
function moveResult(height, fromPole, toPole) {
   console.log(`disk[${height}] from ${fromPole} to ${toPole}`)
}
move(3, '#1', '#2', '#3')

/* 结果
disk[1] from #1 to #3
disk[2] from #1 to #2
disk[1] from #3 to #2
disk[3] from #1 to #3
disk[1] from #2 to #1
disk[2] from #2 to #3
disk[1] from #1 to #3
*/
复制代码

经过几个应用的练习,是不是已经基本掌握了递归算法呢?如果还觉得有些意犹未尽,可以去Leecode上再找一些题来训练,递归是一个很常用的算法,我们应该牢牢地掌握它。

小结

本篇对递归算法进行了简单的介绍和应用,希望各位能够快速入门,并且加以每日的训练,逐渐养成算法思维,一定会使你的代码能力有所提升。如果觉得作者写的不错,可以点个赞鼓励一下;如果存在错误或不足请尽管指出,作者会积极的采取意见进行改进,一起学习,一起进步。加油!!!