一、完全二叉树
理解堆之前先了解完全二叉树。
如果一个树是满的,它属于完全二叉树。如果一个树不满,但它处于正在变满的路上(从左往右),也属于完全二叉树。
从左往右依次变满,属于
跳过左孩子,直接右孩子,不属于
从零出发的一个连续数组,可以被认为是一个完全二叉树。(脑子中想象的)
这个数组想象出来的完全二叉树,i位置的左子孩子:2*i+1,右子孩子2*i+2,父节点(i-1)/2
二、堆
(1)是完全二叉树
(2)大根堆:每一颗子树的最大值都是头结点的值。
小根堆:每一颗子树的最小值都是头结点的值
(3)也可以叫优先级队列,可以随时加数,可以保持堆结构,可以返回最大值
系统中实现的堆(优先级队列)
大根堆(重写比较器)
任何一个子树违规,都不算堆。
用size来控制想象成完全二叉树的连续数组,控制堆的大小
用数组实现一个堆结构:
1、用户给我数字num,加入到数组中,我要使这个数组维持堆的结构(大根堆或者小根堆 )
(用户不停的往数组里面加值,我们要使这个数组维持堆结构,用heapsize来控制我们想象成堆的位数,以及插入数组的下标 ,如果插入的数破坏了堆结构,网上看,比较交换 。)
heapinsert:(上升过程)有数新加入到堆中。
一开始heapsize=0(一开始数组中没有任何一个数被我想象到堆里面),后面来一个数,heapsize++,填到堆位置,然后维持大根堆或者小根堆,(向上比较,交换)
2、返回数组中最大值,且删掉它(下沉过程)
最大值位置肯定是0位置,因为是大根堆。然后0位置与最后一个位置交换,heapsize--,最后那个数在我们脑补的完全二叉树中就没有了。但是此时经过了交换,二叉树不满足大根堆。因此从头结点开始往下,找到左右两个子孩子最大的数,和自己比较,谁大谁做头结点。
向下找,左右孩子的最大值,比自己大就交换
3、如果这个堆中,某一个位置的数突然被改变了,那么怎么才能让这个堆保持堆结构
这个位置的数顺序执行heapinsert和heapify
三、堆排序
第一种
第二种
四、与堆有关的题目
变成有序且每个位置的数移动距离不超过k。
若k=5
根据移动距离不超过k这个限制条件,只有0-5范围内的数才可能来到0位置。把0-5这6个数放到优先级队列中去,弹出最小值放到0位置。把6位置的数放到队列中去,弹出一个最小值放到1位置。依次往下
距离不超过k来依次找最小值,想到用堆,控制堆的大小
先把0-k的数方法小根堆中去,然后弹出一个数放到0位置,加一个进去然后又弹出来一个放到下一个位置