一、堆
1、定义:一颗包含n个节点的完全二叉树,每个节点的值大于等于父节点的值。堆顶为整棵树的最小值,则称为最小堆,反之,称为最大堆。
2、向下调整算法
从位置n/2的元素开始,设该节点为temp,若temp大于其左、右孩子中的较小者,则将该temp与较小者交换位置,调整后继续与其左右孩子比较,直至不再需要调整。从n/2的元素到堆顶元素,重复向下调整,则建堆完毕。
3、代码
public class Heap {
int size = 0;
int[] elements;
public Heap() {
}
public Heap(int maxSize) {
elements = new int[maxSize];
}
public void add(int x) {
elements[size++] = x;
}
public void createHeap() {
// 从中间节点开始,直至0节点
for (int i = (size - 1) / 2; i >= 0; i--) {
adjustDown(i);
}
}
// 父节点为x,则左孩子:2x+1,右孩子:2x+2
public void adjustDown(int start) {
int n = size;
int child = 2 * start + 1;
int temp = elements[start];
// 循环比较左、右孩子
while (child < n) {
// 取左、右孩子中的较小者,保证下标小于n
if (child + 1 < n && elements[child] > elements[child + 1])
child++;
if (temp <= elements[child])
break;
if (child % 2 == 0) {
elements[child / 2 - 1] = elements[child];
} else {
elements[child / 2] = elements[child];
}
// 指向左孩子
child = 2 * child + 1;
}
if (child % 2 == 0) {
elements[child / 2 - 1] = temp;
} else {
elements[child / 2] = temp;
}
}
}
二、优先权队列
1、堆顶元素具有最高优先权,借助堆结构,实现优先权队列。
2、插入操作
将新元素插入堆的最后,堆的大小加一,然后向上调整AdjustUp,与父节点比较,若父节点大于子节点,则交换位置,直至父节点不大于待插入元素,或到达堆顶。
3、删除操作
先取出堆顶元素,然后将堆底元素取代堆顶元素,同时让堆的大小减一,最后使用向下调整AdjustDown。
4、代码
public class PriorityQueue {
int size = 0;
int[] elements;
public PriorityQueue() {
}
public PriorityQueue(int maxSize) {
elements = new int[maxSize];
}
/**
* 构造初始数据
*
* @param x
*/
public void add(int x) {
elements[size++] = x;
}
public void createPriorityQueue() {
for (int i = (size - 1) / 2; i >= 0; i--) {
adjustDown(i, size);
}
}
/**
* 尾部插入之后向上调整
*
* @param size
*/
public void adjustUp(int size) {
int i = size - 1;
int temp = elements[i];
System.out.println(temp);
// 对于孩子节点x、y,则其父亲节点为(x-1)/2 = (y-1)/2
while (i > 0 && temp < elements[(i - 1) / 2]) {
elements[i] = elements[(i - 1) / 2];
i = (i - 1) / 2;
}
elements[i] = temp;
}
/**
* 删除之后向下调整
*
* @param start
* @param size
*/
public void adjustDown(int start, int size) {
int n = size;
int child = 2 * start + 1;
int temp = elements[start];
// 循环比较左、右孩子
while (child < n) {
// 取左、右孩子中的较小者,保证下标小于n
if (child + 1 < n && elements[child] > elements[child + 1])
child++;
if (temp <= elements[child])
break;
if (child % 2 == 0) {
elements[child / 2 - 1] = elements[child];
} else {
elements[child / 2] = elements[child];
}
// 指向左孩子
child = 2 * child + 1;
}
if (child % 2 == 0) {
elements[child / 2 - 1] = temp;
} else {
elements[child / 2] = temp;
}
}
/**
* 插入一个新元素
*
* @param x
*/
public void append(int x) {
// 堆底加入一个元素,堆的大小加一
elements[size++] = x;
// 从底部元素开始向上调整
adjustUp(size);
}
/**
* 删除头元素并返回
*
* @return
*/
public int serve() {
// 头元素赋给x
int x = elements[0];
// 底元素赋给头元素,堆的大小减一
elements[0] = elements[size--];
// 只需头元素向下调整
adjustDown(0, size);
return x;
}
/**
* 删除头元素但不返回
*/
public void peek() {
elements[0] = elements[size--];
adjustDown(0, size);
}
}