堆的定义与基本概念
堆是一种特殊的完全二叉树,也叫优先级队列,满足以下性质之一:
- 最大堆:任意节点的值大于或等于其子节点的值(根节点为最大值)。
- 最小堆:任意节点的值小于或等于其子节点的值(根节点为最小值)。
堆的存储方式
堆通常通过数组实现,利用完全二叉树的特性进行索引映射:
- 对于节点
i(从 0 开始计数):- 父节点索引:
(i - 1) // 2 - 左子节点索引:
2i + 1 - 右子节点索引:
2i + 2
- 父节点索引:
堆的操作
插入元素(上浮)向上调整多用于插入
- 将新元素添加到数组末尾。
- 比较新元素与其父节点的值,若违反堆性质则交换。
- 重复上浮过程直至满足堆性质。
删除堆顶元素(下沉)向下调整多用于构建堆和删除元素
- 交换堆顶与数组末尾元素,并删除末尾元素。
- 从堆顶开始,比较当前节点与子节点的值,若违反堆性质则与较大(最大堆)或较小(最小堆)的子节点交换。
- 重复下沉过程直至满足堆性质。
堆的构建
时间复杂度 :O(n)(自底向上调整)。
- 从最后一个非叶子节点开始(索引
n//2 - 1)。 - 对每个节点执行下沉操作,确保子树满足堆性质。
代码示例(Java)
java
import java.util.ArrayList;
import java.util.Arrays;
/**
* Created with IntelliJ IDEA.
* Description:
* User: zhany
* Date: 2025-10-24
* Time: 19:48
*/
public class Piorory {
int[] elem;
int usedSize;
public Piorory(){
this.elem = new int[10];
}
public void initElem(int[] array) {
for (int i = 0; i < array.length; i++) {
this.elem[i] = array[i];
this.usedSize++;
}
}
public void creatHeap(){
for (int parent = (this.usedSize-2)/2; parent >=0; parent--) {
siftDown(parent,this.usedSize);
}
}
//向下调整主要是用于构建堆和删除顶部元素
private void siftDown(int parent, int usedSize) {
int child = 2*parent +1;
while(child<usedSize){
if(child+1<usedSize && elem[child] <elem[child+1]){
child ++;
}
if(elem[child] >elem[parent]){
swap(elem,child,parent);
parent = child;
child = 2*parent+1;
} else{
break;
}
}
}
private void swap(int[]elem,int child, int parent) {
int tmp = elem[child];
elem[child] = elem[parent];
elem[parent] = tmp;
}
//向上主要是用于插入元素
public void shifUp(int child){
int parent = (child-1)/2;
while(parent >= 0){
if (elem[child] > elem[parent]) {
swap(elem,child,parent);
child = parent;
parent = (child -1)/2;
} else{
break;
}
}
}
public void offer(int val){
if(isFull()){
elem = Arrays.copyOf(elem,2*elem.length);
}
elem[usedSize] = val;
shifUp(usedSize);
usedSize++;
}
public boolean isFull(){
return usedSize == elem.length;
}
public boolean isEmpty(){
return usedSize == 0;
}
public int peek(){
if (isEmpty()) {
return -1;
}
return elem[0];
}
public void printHeap() {
for (int i = 0; i < usedSize; i++) {
System.out.print(elem[i] + " ");
}
System.out.println();
}
}