vlambda博客
学习文章列表

算法设计思想--分而治之(一文搞懂归并排序和快速排序)

前端算法题,我们使用的是JavaScript进行解题。如果直接看答案无法理解里面解题思路,可以联系号主获取账户密码登录网址www.aimath.top,里面有详细的内容解释喔:


我们经常在浏览器搜索信息,但你知道浏览器厂商是如何提高搜索信息效率吗?接下来,我们学习两个重要排序方法:归并排序和快速排序。

一、学完这篇,你可以收获什么?


  • 算法思想:分而治之

  • 归并排序

  • 快速排序


二、归并排序


在学习归并排序之前,我们先了解分而治之思想。


1、分而治之


分而治之是算法设计的一种思想。


它将一个问题成多个和原问题相似的小问题,递归解决小问题,再将结果并以解决原来的问题。


典型例子:归并排序和快速排序


2、归并排序


由于归并排序性能不错,因此火狐浏览器sort方法使用的是归并排序算法。


我们可以从这个网站https://visualgo.net/zh/sorting形象看出归并排序是如何进行的。


归并排序是一种分而治之算法。思想是想将数组切割成两大半,然后先递归第1大半,继续将第1半切割成两半,直到将数组切成只有一个元素的数组,然后再合并,合并成较大数组;紧接着再递归第2大半,原理如上。最后,将两大半排序好的数组合并,即可完成递归。


如图所示:


算法设计思想--分而治之(一文搞懂归并排序和快速排序)


按照以上思路,我们先将将数组丢进递归函数持续分成两半 → 接着比较队头大小,小的先出队,以此类推。


Array.prototype.mergeSort = function() { // 定义一个递归函数将数组转换 const rec = (arr) => { // 第一部分,拆分数组 // 如果传进来数组只有一个,或者递归只剩一个数组,那么直接返回arr if (arr.length === 1) return arr; // 1、解构获取arr长度→目的是将数组分成两半 const { length } = arr; const mid = Math.floor(length / 2) // 2、将数组分成左右两部分 const left = arr.slice(0, mid); const right = arr.slice(mid, arr.length); // 3、将左右数组继续丢进递归函数rec进行拆分。 const orderLeft = rec(left); const orderRight = rec(right); // 4、新建一个空数组存储比较大小后的值 const res = []; // 第二部分,比较大小 // 左边和右边数组都有值情况下,不断比较大小 while(orderLeft.length || orderRight.length){ // 若左边数组有值,右边数组有值,那么此时我们要比较他们的队头,并把较小值出队 if(orderLeft.length && orderRight.length) { // 队头下标为0就可以拿到。如果左边的队头小于右边队头,则左边队头出队,否则右边的队头出队。 res.push(orderLeft[0] < orderRight[0] ? orderLeft.shift() : orderRight.shift()) }else if(orderLeft.length) { res.push(orderLeft.shift()) }else if (orderRight.length) { res.push(orderRight.shift()) } } return res } const res = rec(this) // forEach获取索引值和索引 res.forEach((n, i) => { this[i] = n; });}const arr = Array(5,4,3,2,1)arr.mergeSort()console.log(arr)


从以上解题思路,我们看看归并排序是怎么进行分而治之的:


分:把数组从中间一分为二 → 解:递归地对两个子数组进行归并排序 → 

合:合并有序子数组

 

三、快速排序


快速排序性能与归并排序性能是一样的,谷歌浏览器使用的sort方法是快速排序


同样的,我们可以从这个网站https://visualgo.net/zh/sorting形象看出归并排序是如何进行的。


我们截图进行分析:


第一步,将数组分成两半:


算法设计思想--分而治之(一文搞懂归并排序和快速排序)


算法设计思想--分而治之(一文搞懂归并排序和快速排序)


第二步,先搞左边数组,同上步操作:


算法设计思想--分而治之(一文搞懂归并排序和快速排序)


算法设计思想--分而治之(一文搞懂归并排序和快速排序)



按照如上思路,我们解题方法如下:


Array.prototype.quickSort = function() { // 核心递归逻辑 const rec = (arr) => { // 终结递归,否则递归是没有尽头的; if(arr.length <= 1) return arr; console.log(arr.length) // 逻辑递归操作 const left = []; const right = []; const mid = arr[0]; for(let i = 1; i < arr.length; i += 1) { if(arr[i] < mid){ left.push(arr[i]); }else { right.push(arr[i]); } } return [...rec(left), mid, ...rec(right)]; }; const res = rec(this); res.forEach((n, i) => { this[i] = n })}
const arr = [4, 3, 2, 1, 8, 7, 6, 5]arr.quickSort()console.log(arr)


按照分而治之思想,我看快速排序是怎么进行解题的:

分:选基准,按基准把数组分成两个子数组 → 解:递归地对两个子数组进行快速排序 → 合:对两个子数组进行合并

下期预告:动态规划思想是如何解决问题的?它又是怎样在我们实际生活中应用~