优先级队列--堆
程序员文章站
2024-02-11 21:17:16
...
二叉树和数组–结合(堆)
一:存储方式
使用数组保存二叉树结构,方式即将二叉树用层序遍历方式放入数组中。一般只适合表示完全二叉树,因为非完全二叉树会有空间的浪费。这种方式的主要用法就是堆的表示。
二: 下标关系
已知双亲(parent)的下标,则:
左孩子(left)下标 = 2 * parent + 1;
右孩子(right)下标 = 2 * parent + 2;
已知孩子(不区分左右)(child)下标,则:
双亲(parent)下标 = (child - 1) / 2;
堆
一:概念
- 堆逻辑上是一棵完全二叉树
- 堆物理上是保存在数组中
- 满足任意结点的值都大于其子树中结点的值,叫做大堆,或者大根堆,或者最大堆
- 反之,则是小堆,或者小根堆,或者最小堆
- 堆的基本作用是,快速找集合中的最值,
- 用于堆排序
二:下面代码详细展示了 建堆 入队列 出队列 堆排序 等 堆的操作
import java.util.Arrays;
public class Heat {
public int[] elem;
public int usedSize;
public Heat(){
this.elem = new int[20];
this.usedSize = 0;
}
/**
* 向下调整 一次调整
* @param root:每次调整的这棵树的根节点下标
*/
public void adjustDown(int root,int len) {
int parent = root;
int child = 2*parent+1;
while (child < len) {
//判断是否有右孩子 且谁最大
if(child+1 < len && elem[child] <
elem[child+1]) {
child = child+1;
}
//child肯定是左右孩子的最大值下标
if(elem[child] > elem[parent]) {
int tmp = elem[child];
elem[child] = elem[parent];
elem[parent] = tmp;
parent = child;
child = 2*parent+1;
}else {
//达到有序状态
break;
}
}
}
//建堆
public void createHeap(int[] array) {
for (int i = 0; i < array.length; i++) {
this.elem[i] = array[i];
this.usedSize++;
}
for (int i = (this.usedSize-1-1)/2; i >= 0; i--) {
adjustDown(i,this.usedSize);
}
}
//向上调整
public void adjustUp(int child) {
int parent = (child-1)/2;
while (child > 0) {
if(this.elem[child] > this.elem[parent]) {
int tmp = elem[child];
elem[child] = elem[parent];
elem[parent] = tmp;
child = parent;
parent = (child-1)/2;
}else {
break;
}
}
}
//堆是否满了
public boolean isFull(){
return this.usedSize == this.elem.length;
}
/**
* 入队列
* 1. 首先按尾插方式放入数组
* 2. 比较其和其双亲的值的大小,如果双亲的值大,则满足堆的性质,插入结束
* 3. 否则,交换其和双亲位置的值,重新进行 2、3 步骤
* 4. 直到根结点
* @param val
*/
public void pushHeap(int val) {
if(isFull()) {
this.elem = Arrays.copyOf
(this.elem,this.elem.length*2);
}
this.elem[this.usedSize] = val;
this.usedSize++;//11
adjustUp(usedSize-1);
}
public boolean isEmpty() {
return this.usedSize == 0;
}
/**
* 出队列
* 为了防止破坏堆的结构,删除时并不是直接将堆顶元素删除,
* 而是用数组的最后一个元素替换堆顶元素,然后通过向下调整方式重新调整成堆
*/
public void popHeap() {
//0、堆为空 的时候\
if(isEmpty()) {
return;
}
//1、根顶元素和最后一个元素进行交换
int tmp = this.elem[0];
this.elem[0] = this.elem[this.usedSize-1];
this.elem[this.usedSize - 1] = tmp;
this.usedSize--;
//2、向下调整,只需要调整0号下标这棵树
adjustDown(0,this.usedSize);
}
//得到堆顶元素
public int getPop() {
if(isEmpty()) {
return -1;
}
return this.elem[0];
}
public void display() {
for (int i = 0; i < this.usedSize; i++) {
System.out.print(this.elem[i] +" ");
}
System.out.println();
}
//堆排序
public void heapSort(){
int end = this.usedSize -1;
while(end > 0){
int tmp = this.elem[0];
this.elem[0] = this.elem[end];
this.elem[end] = tmp;
adjustDown(0,end);
end--;
}
}
}
上一篇: 堆的原理以及实现
下一篇: 浅析堆的基本操作以及堆排序