首页 > 其他分享 >数组的活学活用(一)

数组的活学活用(一)

时间:2022-12-12 20:12:41浏览次数:39  
标签:下标 活学活用 堆排序 二叉树 数组 排序 节点

概览

数组我们知道,是一种有序连续的数据结构,随机访问的效率高。之所以随机访问的效率高,就是因为它的每个值都有下标,可以根据下标直接找到我们想要的值。

 

既然我们已经知道了这种思想,那么我们可以用来做什么呢?

 

接下来我们就讲讲用数组的思想,或者干脆就直接用数组实现的几种巧妙的思路。

 

堆排序

首先堆是什么,我理解就是一颗完全二叉树(当然,也有说多叉树也行,但是我没有研究过。);然后每个节点的值都大于等于它的子节点的值,则为最大堆,反之为最小堆。

 

接着我们就来看看最小堆是怎么样的一个东西。首先假设有一组数(3、9、2、5、1、6、10、16、7)。那我们初始化成最小堆时是什么个样子呢?

  1. 首先是按顺序取值,也按顺序存值
  2. 存入之后判断与父节点的大小
    1. 如果小于父节点,则交换两者位置
      1. 循环此步骤
    1. 否则继续处理下一个数。
  1. 如果单纯只想要最大最小值的话,到这步其实已经结束了。因为初始化的堆已经保证了根节点就是最大或者最小值
  2. 如果要继续使堆完全排序,可以将根节点与最后一个节点交换。此时最后一个节点为排序区
  3. 然后将根节点与子节点比较,若子节点比根节点小,则取最小的一个子节点与根节点交换。交换之后继续与子节点判断,直到无需交换。
  4. 如此重复4 5步骤,即可得到一个完全排序的堆

总结一下就是:1、初始堆。2、交换根和最后一个未排序的节点,重新调整堆,再交换。如此直到最后就能得到一个完全排序的堆了。

 

初始化堆

 


所以我们可以看出,最小堆(或者最大堆)都是父节点和子节点之间的大小关系判断,兄弟节点是没有大小顺序,此时就可以取min或者max值了,如果要完全排序,则可以继续按下面的步骤处理。

 

完全堆排序

 


看,经过几轮处理之后,我们就能得到一个完全经过排序的二叉树了。

与数组的关系

说了这么多,那么与数组到底有什么关系呢?其实很简单,这是因为堆的逻辑顺序是一颗二叉树,但是物理顺序却是一个数组。

 

怎么说呢?我们在存储的时候是将堆从上到下,从左到右平铺到数组中,通过下标来判断父子节点的关系。就以初始化堆之后的二叉树为例,在数组中的存储顺序是:

 

此时存储形式有2种:
  1. 下标0存根节点
    1. 假设当前节点的下标为n,则它的父节点为 (n-1)>>1。它的两个子节点分别为:(n<<1)+1和 (n<<1)+2
  1. 下标0不存值
    1. 假设当前节点的下标为n,则它的父节点为 n>>1。它的两个子节点分别为:n<<1和 (n<<1)+1

如此,我们也知道了,可以用数组来存一颗二叉树,而且可以很方便的找到它有关联的父节点甚至祖父节点等。

总结

堆排序,常用于取最大最小值,或者优先级队列和作业调度等。像Java中的PriorityQueue就用到了堆排序,然后JUC中的ScheduledThreadPoolExecutor中也是用到了堆排序。

 

定时任务调度池的基本实现原理是:

  • 将调度任务提取到线程池之前,首先计算下一次需要执行的时间戳,通过时间戳来判断优先级,并将任务存入最小堆中,这样就确保了最先要执行的任务一定在最小堆的顶部,也就是跟节点。
  • 然后开一个定时任务,拿堆中第一个任务和当前时间进行比较:
    • 如果下一次执行的时间小于等于当前时间,则将该任务从堆中移除,并且投入线程池中执行。
    • 如果执行时间大于当前时间,则不处理,因为队列中最先应该执行的任务都还没到时间,其他任务也一定没有到执行时间。

 

到这里我们的小知识就告一段落了,今天的代码比较少,感兴趣的小伙伴可以根据司机尝试自己实现一下。那我们下期再见了~

标签:下标,活学活用,堆排序,二叉树,数组,排序,节点
From: https://www.cnblogs.com/aischen/p/16976977.html

相关文章

  • Shell数组基本概述
    1.数组基本概述01.什么是数组?数组其实也算是变量,传统的变量只能存储一个值,但数组可以存储多个值。02.数组的分类Shell数组分为普通数组和关联数组。普通数组:只能使......
  • 剑指 Offer 56 - II. 数组中数字出现的次数 II(状态转移 位运算)
      ​​剑指Offer56-II.数组中数字出现的次数II​​难度中等38在一个数组 ​​nums​​ 中除一个数字只出现一次之外,其他数字都出现了三次。请找出那个只出现一次......
  • 剑指offer 数组中的逆序对(归并排序)
    ​​剑指Offer51.数组中的逆序对​​难度困难176在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的......
  • 原地合并两个排序数组 O(1)空间复杂度,O(n)时间复杂度
    问题:给你两个从小到大的数组a,b。在不申请额外空间下,往a填充a和b合并后的排序数组(假设a的空间是足够的)。第一种方法:很直觉的思路是,我们采取和归并排序时同样的策略,每次拿出最......
  • Go语言实战之数组的内部实现和基础功能
    写在前面嗯,学习​​GO​​,所以有了这篇文章博文内容为​​《GO语言实战》​​读书笔记之一主要涉及数组相关知识世上除了爹娘,再没有人是理所应当对你好的。——烽火戏诸侯......
  • 每日算法之把数组排成最小的数
    JZ45把数组排成最小的数描述输入一个非负整数数组numbers,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个。例如输入数组[3,32,321],则打印出这三......
  • 数组名的注意事项
    intmain(){ intarr[]={1,2,3,4,5,6,7,8,9,0}; printf("%p\n",arr);//数组名是数组首个元素的地址 printf("%p\n",&arr[0]);//数组名是数组首个元素的地址 printf("......
  • 力扣852(java&python3)-山脉数组的峰顶索引(中等)
    题目:符合下列属性的数组arr称为山脉数组:arr.length>=3存在i(0<i <arr.length-1)使得:arr[0]<arr[1]<...arr[i-1]<arr[i]arr[i]>arr[i+1]>...>......
  • 笔记(数组)
    冒泡排序voidbubble_sort(intarr[],intsz){inti=0;for(i=0;i<sz-1;i++){intj=0;for(j=0;j<sz-1-i;j++){if(arr[j......
  • js 筛选数组对象的数据 并判断指定属性为空 则直接返回false
    vararr=[{name:"张三",age:20},{name:"",age:30},{name:"李四",age:25}];varresult=arr.filter(item=>......