一 优先级队列(堆)
通过层序遍历将二叉树放入数组中,即使用数组保存二叉树结构。
对于完全二叉树的下标关系:
leftChild = 2parent+1;
rightChild = 2parent +2;
parent = (child-1)/2;
1 堆(heap)
- 堆逻辑上是一个完全二叉树
- 堆保存在数组中
- 任意节点的值都大于其子节点的值,称为大堆
- 任意节点的值都小于其子节点的值,称为小堆
- 堆能够快速找到集合中的最值
2 通过向下调整,建立一个大堆
public class TestHeap {
public int[] elem;
public int usedSize;
public TestHeap(){
this.elem = new int[10];
this.usedSize=0;
}
//1 向下调整,建立一个大堆
public void createHeap(int[] array){
//传入一个数组,赋值给elem
for (int i = 0; i <array.length ; i++) {
this.elem[i] = array[i];
this.usedSize++;
}
//this.usedSize-1为最后一个节点,
// (最后一个节点-1)/2为最后一个子树的父节点
for(int i=(this.usedSize-1-1)/2;i>=0;i--){
//每一棵树都按照向下调整的方式进行调整为一个大堆
AdjustDown(i,this.usedSize);
}
}
public void AdjustDown(int root,int len){
//len为数组长度
int parent = root;
int child = 2*parent+1;
//child<len说明该父节点有左节点
while(child<len){
//child+1<len说明有右节点,然后比较左右孩子大小,让child指向大值
if(child+1<len&&this.elem[child]<this.elem[child+1]){
child = child+1;
}
//child是左右孩子的最大值下标
if(this.elem[child]>this.elem[parent]){
//交换
int tmp = this.elem[child];
this.elem[child]=this.elem[parent];
this.elem[parent]=tmp;
//向下调整被打乱的子树顺序
parent = child;
child = 2*parent+1;
}else{
break;
}
}
}
3 入堆(大堆)
// 3 入堆,前提是已经是一个大根堆
public boolean isFull(){
return this.usedSize==this.elem.length;
}
public void pushHeap(int val){
//elem数组如果满了则先扩容
if(isFull()){
//二倍扩容
this.elem = Arrays.copyOf(this.elem,this.elem.length*2);
}
//将入堆元素放到最后位置
this.elem[this.usedSize] = val;
this.usedSize++;
//开始向上调整,this.usedSize-1指向最后一个位置
AdjustUp(this.usedSize-1);
}
public void AdjustUp(int child) {
int parent = (child-1)/2;
while (child > 0) {
if(this.elem[child] > this.elem[parent]) {
int tmp = this.elem[child];
this.elem[child] = this.elem[parent];
this.elem[parent] = tmp;
// 向上调整 child 指向 parent
child = parent;
parent = (child-1)/2;
}else {
break;
}
}
}
4 出堆(大堆)
// 4 出堆
public boolean isEmpty(){
return this.usedSize==0;
}
public void popHeap(){
if(isEmpty()){
return;
}
//第一个元素和最后一个元素互换,用this.usedSize--剔除最后一个元素
int tmp = this.elem[0];
this.elem[0] = this.elem[this.usedSize-1];
this.elem[this.usedSize-1]=tmp;
this.usedSize--;
//向下调整,this.usedSize为数组长度,0为传入的父节点
AdjustDown(0,this.usedSize);
}
5 堆排序
// 5 堆排序,从小到大,本例中的都是大根堆
//时间复杂度n*log2n以2为底
//空间复杂度o(1)
//一次调整的时间复杂度log2n以2为底
public void heapSort() {
//end最后元素的下标
int end = this.usedSize-1;
while (end > 0) {
int tmp = this.elem[end];
this.elem[end] = this.elem[0];
this.elem[0] = tmp;
//不断的将大元素往后排,最后完成从小到大的排序
//此处end代表数组大小
AdjustDown(0,end);
end--;
}
}
6 Java中的优先级队列(默认为小堆)
PriorityQueue implements Queue
抛出异常 | 返回特殊值 | |
---|---|---|
入队列 | add(e) | offer(e) |
出队列 | remove() | poll() |
队首元素 | element() | peek() |