数据结构中的堆
1.堆的定义
1.堆是一种完全二叉树
2.由数组实现
3.与二叉搜索树的区别:
1.二叉搜索树的左节点一定比父节点小,右节点一定比父节点大,所以它可以使用中序遍历来显示升序
2.堆中的左右节点之间没有大小关系,但他们一定小于或大于父节点。
2.堆的操作
1.有两种排序,大根堆和小根堆。(大根堆中父节点一定比子节点大,小根堆中一定比子节点小)
2.排序时为保证堆的属性(最大最小)主要有两种操作,上浮和下沉。
3.插入
1.将当前节点放至堆的最后,也就是数组的最后,然后进行up()(上浮操作)
2.判断当前节点是否右父节点,如数组的第一个元素就没有父节点
3.判断父节点 val 是否大于/小于(最小堆/最大堆)当前节点
4.进行交换
class Heap{
//创建大小为1000的数组来存储堆,size记录数组中元素个数
int[] heap;
int size = 0 ;
int MAXSIZE = 1000;
public int init(){
heap = new int[MAXSIZE];
//进行插入操作,参数val没有定义,自行创建
insert(val);
//返回堆顶元素
return heap[0]
}
//这边以小根堆为例(最小堆)
public void insert(int val){
heap[size] = val;
up();
size++;
}
//上浮
public void up(){
//当前节点在数组的下标
int i = size;
// 父节点
int fa = (int)Math.ceil((i / 2.0 )) - 1;
//父节点存在且大于当前节点
while( fa >= 0 && heap[i] < heap[fa]){
//交换
int temp = heap[fa];
heap[fa] = heap[i];
heap[i] = temp;
//当前节点变为父节点,父节点也继续变化,直到父节点不存在或者父节点小于当前节点
i = fa;
fa = (int)Math.ceil((i / 2.0 )) - 1;
}
}
}
4.删除堆顶元素
1.交换堆顶元素和最后一个元素,数组中元素个数减一
2.进行堆排序,使用下沉down(),保证堆的属性
3.下沉首先判断是否存在子节点
4.子节点中较小的(小根堆)的节点是否还小于当前节点,小于就交换
5.不存在子节点或者子节点都大于当前节点时结束循环
public int remove(){
//将堆顶元素和最后一个元素交换,然后进行down()下沉操作保证堆的属性
// 也是小根堆的例子
int val = heap[0];
heap[0] = heap[--size];
down();
return val;
}
public void down(){
int i = 0;
//保证当前节点存在子节点
while( i * 2 + 1 < size){
//找出子结点中较小的那个
int child = i * 2 + 1;
if(child + 1 < size && heap[child] > heap[child + 1])child += 1;
//判断较小的子节点是否小于当前节点,小于就交换
if(heap[child] < heap[i]){
int temp = heap[child];
heap[child] = heap[i];
heap[i] = temp;
i = child;
}
//较小的子节点大于当前节点,说明当前节点已经处于正确的位置,结束循环
else
break;
}
}
//这里也可以使用递归,初始i为0
public void down(int i){
int child = i * 2 + 1;
int t = i;
if(child < size){
if(child + 1 < size && heap[child + 1] < heap[child])child = child + 1;
if(heap[child] < heap[i]){
int temp = heap[child];
heap[child] = heap[i];
heap[i] = temp;
i = child;
}
if(t != i)down(i);
}
}