当前位置:首页 > 科技  > 软件

教你利用二叉树的思想,轻松解决合并排序和快速

来源: 责编: 时间:2023-10-30 17:23:50 229观看
导读排序在我们的的工程应用中无处不见,也有着非常重要的作用,比如你随意点开一个搜索引擎,搜索的结构就是经过排序而来。各种电商网站的秒杀活动,用户点击秒杀后,服务器会根据用户的请求时间进行排序。在我们的用的文档表格中

排序在我们的的工程应用中无处不见,也有着非常重要的作用,比如你随意点开一个搜索引擎,搜索的结构就是经过排序而来。各种电商网站的秒杀活动,用户点击秒杀后,服务器会根据用户的请求时间进行排序。在我们的用的文档表格中,也存在各种排序。VJv28资讯网——每日最新资讯28at.com

所以排序真的是无处不见,因此,面试中出现关于排序的算法题也就不足为奇了。这篇文章通过面试中最经常出现的两种排序算法进行深度展开。VJv28资讯网——每日最新资讯28at.com

  • 合并排序
  • 快速排序

本文你将收获相应的思想和代码模板。VJv28资讯网——每日最新资讯28at.com

1.合并排序

合并排序本质上与二叉树的后序遍历非常类似的。VJv28资讯网——每日最新资讯28at.com

// 递归function postOrder(root, array = []) {  if (root === null) return null;  postOrder(root.left, array);  postOrder(root.right, array);  array.push(root.val)}

后序遍历有个三个重要的特点:VJv28资讯网——每日最新资讯28at.com

  • 拿到子树的信息;
  • 利用子树的信息;
  • 整合树的信息;

这三个特点对应到合并排序就是:VJv28资讯网——每日最新资讯28at.com

  • 拿到子数组的信息;
  • 利用子数组的信息;
  • 排序出数组的信息。

利用伪代码来表示就是:VJv28资讯网——每日最新资讯28at.com

function 后序遍历/合并排序:    子结构划分    sub = 子结构(子树/子数组)    full = 整合(sub)

这个伪代码总结为三个关键点:VJv28资讯网——每日最新资讯28at.com

  • 划分子结构
  • 获取子结构的信息
  • 利用子结构的信息整合成结果

划分子结构

二叉树,子树的划分已经在数据结构里面约定好了:VJv28资讯网——每日最新资讯28at.com

root.leftroot.right

数组,子结构的划分,如果想到达最优的效率,那么将数组切为平均的两半效率应该是最高的。VJv28资讯网——每日最新资讯28at.com

const mid = begin + ((end - begin)>>1)数组a = [begin, mid) => 表示左子数组数组a = [mid, end) => 表示右子数组

获取子结构的信息

二叉树,获取子树的信息的利用就是遍历左右子节点的信息。VJv28资讯网——每日最新资讯28at.com

postOrder(root.left)postOrder(root.right)

合并排序,获取子数组的信息就是对左子数组和右子数组进行排序。对子数组的排序,只需要递归就可以了。VJv28资讯网——每日最新资讯28at.com

merge(a, begin, mid)merge(a, mid, end)

利用子结构的信息整合成结果

二叉树,结果的合成就是将节点值添加到结果中。VJv28资讯网——每日最新资讯28at.com

array.push(root.val)

合并排序,结果的合成,我们需要将两个有序的子数组,合并成一个大的有序的数组。VJv28资讯网——每日最新资讯28at.com

let i = begin;let j = mid;let to = begin;// 将两个数组合并,判断条件是,只有左右子数组中还有元素while(i < mid || j < end) {  // 读取左数组的元素:  //   - 左数组还存在元素并且左数组的开头元素小于右数组的开头元素  //    - 右数组没有元素  if ((i < mid && a[i] < a[j]) || j >=end) {    // t 为临时数组    t[to++] = a[i++];  } else {  // 读取右数组的元素    t[to++] = a[j++];    }}

最后

最后,处理边界:VJv28资讯网——每日最新资讯28at.com

二叉树的边界就是节点不能为空。VJv28资讯网——每日最新资讯28at.com

if (root === null) return null;

合并排序的边界就是:VJv28资讯网——每日最新资讯28at.com

  • 当 b >= e,说明这个区间是一个空区间,没有必要再排序;
  • 当 b + 1 === e,说明只有一个元素,也没有必要排序。
if (b > e || b + 1 >= e) {  return }

小结

二叉树,代码如下。VJv28资讯网——每日最新资讯28at.com

function postOrder(root, array = []) {  // 边界处理  if (root === null) return null;  // 第一步:划分子结构,二叉树在结构上已经划分了子结构 root.left、root.right 可以直接通过树的子节点拿  // 第二步:获取子结构信息(递归的方式)  postOrder(root.left, array);  postOrder(root.right, array);  // 第三步:整合子结构信息  array.push(root.val)}

合并排序,如何切分左右子数组?如何进行合并,合并时注意循环的条件,以及稳定排序的写法?都是在写算法时需要注意的。整体代码如下:VJv28资讯网——每日最新资讯28at.com

function merge(a, t, b, e) { // 边界处理  if (b > e || b + 1 >= e) {    return   } /*********************核心代码****************************/  // 第一步:划分子结构  const mid = b + ((e-b)>>1);  // 第二步:获取子结构信息(递归的方式)  merge(a, t, b, mid); // 左边子结构  merge(a, t, mid, e); // 右边子结构  // 第三步:整合子结构信息  let i = b;  let j = mid;  let to = b;  // 注意:下面是一个很重要的模板❤❤❤❤❤❤❤❤❤❤❤❤ // 将两个数组合并,判断条件是,只有左右子数组中还有元素  while(i < mid || j < e) {    // 读取左数组的元素:    //   - 左数组还存在元素并且左数组的开头元素小于右数组的开头元素    //    - 右数组没有元素   if ((i < mid && a[i] < a[j]) || j >=e) {      t[to++] = a[i++];    } else {    // 读取右数组的元素      t[to++] = a[j++];      }  } /*********************核心代码****************************/  // 将合并的结果拷贝到源数组中  for (let i = b; i < e; i++) {    a[i] = t[i];  }}function mergeSort(nums) {  if (nums === null || nums.length === 0) {    return;  }  merge(nums, [], 0, nums.length)  return nums;}

2.快速排序

快速排序和合并排序一样,可以利用二叉树的思想来解决,合并排序本质上与二叉树的后序遍历非常类似的,而快速排序本质上与二叉树的前序遍历非常类似的。VJv28资讯网——每日最新资讯28at.com

前序遍历:VJv28资讯网——每日最新资讯28at.com

// 递归function preOrder(root, array = []) {  if (root === null) return null;  array.push(root.val);  postOrder(root.left, array);  postOrder(root.right, array);}

后序遍历有个三个重要的特点:VJv28资讯网——每日最新资讯28at.com

  • 整合树的信息;
  • 拿到子树的信息;
  • 利用子树的信息;

这三个特点对应到合并排序就是:VJv28资讯网——每日最新资讯28at.com

  • 排序出数组的信息。
  • 拿到子数组的信息;
  • 利用子数组的信息;

利用伪代码来表示就是:VJv28资讯网——每日最新资讯28at.com

function 前序遍历/快速排序():    子结构划分    获取根节点信息;    将根节点的信息传递左右子树/左右子数组;

这个伪代码总结为三个关键点:VJv28资讯网——每日最新资讯28at.com

  • 划分子结构
  • 根节点的信息处理
  • 将根节点的信息,传递给左右子树/左右子数组。

划分子结构

二叉树,子树的划分已经在数据结构里面约定好了:VJv28资讯网——每日最新资讯28at.com

root.leftroot.right

数组,子结构的划分,选择一个数 X,并且利用这个数,将数组分成三部分:VJv28资讯网——每日最新资讯28at.com

  • 小于 X 的部分;
  • 等于 X 的部分;
  • 大于 X 的部分;
利用 x 将数组分为三份左子数组 = [小于 x 的部分] = [b, l)根节点 = [等于 x 的部分] = [l, i)右子数组 = [大于 x 的部分] = [i, e)

根节点的信息处理

二叉树,根节点就是当前节点,节点的处理也即是收集节点信息。VJv28资讯网——每日最新资讯28at.com

// 根节点信息处理array.push(root.val);

排序算法的"根节点"也就是选择的元素,并且排序算法会通过划分的子结构和选中的元素来进行排序处理也就是上面说的特殊处理;对于排序算法来说,"根节点"和划分子结构息息相关。VJv28资讯网——每日最新资讯28at.com

if (a[i] < x) {    // 小于 x 的部分} else if (a[i] === x) {    // 等于 x 的部分} else {    // 大于 x 的部分}

将根节点的信息,传递给左右子树/左右子数组

二叉树,通过递归的方式处理左右子树。VJv28资讯网——每日最新资讯28at.com

// 二叉树的前序遍历拿左右子树的信息preOrder(root.left);preOrder(root.right);

而排序算法需要分别对左子数组和右子数组进行排序,那么类似的对子数组的排序应该也只需要递归就可以了。VJv28资讯网——每日最新资讯28at.com

// 快速排序去拿左右子数组的信息qsort(a, b, l);qsort(a, i, e);

最后

最后,不管是二叉树还是快速排序都要考虑一下边界:VJv28资讯网——每日最新资讯28at.com

二叉树的边界就是节点不能为空。VJv28资讯网——每日最新资讯28at.com

if (root === null) return null;

快速排序的边界就是:VJv28资讯网——每日最新资讯28at.com

  • 当 b >= e,说明这个区间是一个空区间,没有必要再排序;
  • 当 b + 1 === e,说明只有一个元素,也没有必要排序。
if (b > e || b + 1 >= e) {  return;}

小结

二叉树,代码如下。VJv28资讯网——每日最新资讯28at.com

function preOrder(root, array = []) {  // 边界处理  if (root === null) return null;  // 第一步:划分子结构,二叉树在结构上已经划分了子结构 root.left、root.right 可以直接通过树的子节点拿  // 第二步:根节点的信息处理  array.push(root.val)  // 第三步:将根节点的信息,传递给左右子树/左右子数组(递归的方式)  postOrder(root.left, array);  postOrder(root.right, array);}

对于快速排序来说,如何划分子结构?如何到达最优的效率?都是在写算法时需要注意的。整体代码如下:VJv28资讯网——每日最新资讯28at.com

// 交换数组中两个元素的值 function swap(A, i, j) {  const t = A[i];  A[i] = A[j];  A[j] = t;}function qsort(a, begin, end) {    // 边界情况   if (b > e || b + 1 >= e) {     return    } /*********************核心代码****************************/ // 第一步:划分子结构    const mid = b + ((end - begin) >> 1); // 第二步:获取根节点信息 x const x = a[mid]; // 根据 x 将数组一分为三 【三路切分】 let l = begin; let i = begin; let r = end - 1;    while(i < r) {        if (a[i] < x) {            // 小于 x 的部分            swap(a, l++, i++);        } else if (a[i] === x) {            // 等于 x 的部分            i++;        } else {            // 大于 x 的部分            swap(a, r--, i);        }    } // 第三步:将根节点的信息传递左右子子树 qsort(a, b, l); qsort(a, i, e); /*********************核心代码****************************/}// 主函数,将数组nums排序 function quickSort(nums) {  if (nums == null)    return;  qsort(nums, 0, nums.length);}

总结

通过合并排序和快速排序,可以得出结论,数组其实是另外一种形式的二叉树,只不过有时候需要我们动态地把左/右子树给切分出来,不同的切分方式,可以解决不同的问题。大家也可以自己思考和尝试,看看还能不能发现更多排序的特点和巧妙用法,并且将它们总结下来。欢迎大家一起在评论区交流。VJv28资讯网——每日最新资讯28at.com

参考

  • https://leetcode.cn/problems/median-of-two-sorted-arrays/solutions/258842/xun-zhao-liang-ge-you-xu-shu-zu-de-zhong-wei-s-114/
  • https://kaiwu.lagou.com/course/courseInfo.htm?courseId=685#/detail/pc?id=6697
  • https://juejin.cn/post/7286307632193273915
  • https://juejin.cn/post/7287914116296458275
  • https://juejin.cn/post/7287473826060304445

本文链接://www.dmpip.com//www.dmpip.com/showinfo-26-15858-0.html教你利用二叉树的思想,轻松解决合并排序和快速

声明:本网页内容旨在传播知识,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。邮件:2376512515@qq.com

上一篇: 可以提取图像文本的五大 Python 库

下一篇: 了解Springboot起步依赖及其实现原理

标签:
  • 热门焦点
  • 一加Ace2 Pro官宣:普及16G内存 引领24G

    一加Ace2 Pro官宣:普及16G内存 引领24G

    一加官方今天继续为本月发布的新机一加Ace2 Pro带来预热,公布了内存方面的信息。“淘汰 8GB ,12GB 起步,16GB 普及,24GB 引领,还有呢?#一加Ace2Pro#,2023 年 8 月,敬请期待。”同时
  • 影音体验是真的强 简单聊聊iQOO Pad

    影音体验是真的强 简单聊聊iQOO Pad

    大公司的好处就是产品线丰富,非常细分化的东西也能给你做出来,例如早先我们看到了新的vivo Pad2,之后我们又在iQOO Neo8 Pro的发布会上看到了iQOO的首款平板产品iQOO Pad。虽
  • 多线程开发带来的问题与解决方法

    多线程开发带来的问题与解决方法

    使用多线程主要会带来以下几个问题:(一)线程安全问题  线程安全问题指的是在某一线程从开始访问到结束访问某一数据期间,该数据被其他的线程所修改,那么对于当前线程而言,该线程
  • 一篇文章带你了解 CSS 属性选择器

    一篇文章带你了解 CSS 属性选择器

    属性选择器对带有指定属性的 HTML 元素设置样式。可以为拥有指定属性的 HTML 元素设置样式,而不仅限于 class 和 id 属性。一、了解属性选择器CSS属性选择器提供了一种简单而
  • JVM优化:实战OutOfMemoryError异常

    JVM优化:实战OutOfMemoryError异常

    一、Java堆溢出堆内存中主要存放对象、数组等,只要不断地创建这些对象,并且保证 GC Roots 到对象之间有可达路径来避免垃 圾收集回收机制清除这些对象,当这些对象所占空间超过
  • 使用AIGC工具提升安全工作效率

    使用AIGC工具提升安全工作效率

    在日常工作中,安全人员可能会涉及各种各样的安全任务,包括但不限于:开发某些安全工具的插件,满足自己特定的安全需求;自定义github搜索工具,快速查找所需的安全资料、漏洞poc、exp
  • 造车两年股价跌六成,小米的估值逻辑变了吗?

    造车两年股价跌六成,小米的估值逻辑变了吗?

    如果从小米官宣造车后的首个交易日起持有小米集团的股票,那么截至2023年上半年最后一个交易日,投资者将浮亏59.16%,同区间的恒生科技指数跌幅为52.78%
  • 华为发布HarmonyOS 4:更好玩、更流畅、更安全

    华为发布HarmonyOS 4:更好玩、更流畅、更安全

    在8月4日的华为开发者大会2023(HDC.Together)大会上,HarmonyOS 4正式发布。自2019年发布以来,HarmonyOS一直以用户为中心,经历四年多的发展HarmonyOS已
  • 华为将推出盘古数字人大模型 可帮助用户12小时完成数字人生成

    华为将推出盘古数字人大模型 可帮助用户12小时完成数字人生成

    在今日举行的2023年华为云数字文娱AI创新峰会上,华为云全球Marketing与销售服务总裁石冀琳表示,华为云将在后续推出盘古数字人大模型,可帮助用户12小
Top
Baidu
map