一、堆的定义
堆是计算机科学中一类特殊的数据结构的统称,堆通常可以被看做是一棵完全二叉树的数组对象。
堆的特性:
1)、它是完全二叉树,除了树的最后一层结点不需要是满的,其它的每一层从左到右都是满的,如果最后一层结点不是满的,那么要求左满右不满。
2)、它通常用数组来实现。
具体方法就是将二叉树的结点按照层级顺序放入数组中,根结点在位置 1(之所以不从 0 开始,是为了方便我们索引的操作),它的子结点在位置 2 和 3,而子结点的子结点则分别在位置 4.5.6 和 7,以此类推。
如果一个结点的位置为k,则它的父结点的位置为 k/2 ,而它的两个子结点的位置则分别为 2k 和 2k+1 。这样,在不使用指针的情况下,我们也可以通过计算数组的索引在树中上下移动:从 a[k] 向上一层,就令 k 等于 k/2,向下一层就令 k 等于 2k 或 2k+1。
3)、每个结点都大于等于它的两个子结点。这里要注意堆中仅仅规定了每个结点大于等于它的两个子结点,但这两个子结点的顺序并没有做规定,跟我们之前学习的二叉查找树是有区别的。
二、堆的 API 设计
类名 |
Heap<T extends Comparable<T>> |
构造方法 |
Heap(int capacity) :创建容量为 capacity 的 Heap 对象 |
成员方法 |
1、private boolean less(int i,int j) :判断堆中索引处的元素是否小于索引处的元素 2、private void exch(int i,int j) :交换堆中索引 i 和索引 j 的值 3、public T delMax() :删除堆中最大的元素,并返回这个最大元素 4、public void insert(T t) :往堆中插入一个元素 5、private void swim(int k) :使用上浮算法,使索引 k 处的元素能在堆中处于一个正确的位置 6、private void sink(int k) :使用下沉算法,使索引 k 处的元素能在堆中处于一个正确的位置 |
成员变量 |
1、private T[] items :用来存储元素的数组 2、private int N :记录堆中元素的个数 |
三、堆的实现
3.1、代码实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
| public class Heap<T extends Comparable<T>> {
private T[] items; private int N;
public Heap(int capacity){ items = (T[]) new Comparable[capacity + 1]; N = 0; }
private boolean less(int i,int j){ return items[i].compareTo(items[j]) < 0; }
private void exch(int i,int j){ T temp = items[i]; items[i] = items[j]; items[j] = temp; }
public void insert(T t){ items[++N] = t; swim(N); }
private void swim(int k){ while (k > 1){ if(less(k/2,k)){ exch(k/2,k); } k = k / 2; } }
public T delMax(){ T max = items[1]; exch(1,N); items[N] = null; N--; sink(1); return max; }
private void sink(int k){ while (2*k <= N){ int max; if(2*k + 1 < N){ if(less(2*k,2*k + 1)){ max = 2*k + 1; }else { max = 2*k; } }else { max = 2*k; } if(!less(k,max)){ break; }
exch(k,max);
k = max; } } }
|
3.2、测试
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| public class HeapTest {
public static void main(String[] args) { Heap<String> heap = new Heap<>(10); heap.insert("A"); heap.insert("B"); heap.insert("C"); heap.insert("D"); heap.insert("E"); heap.insert("F"); heap.insert("G");
String delResult; while ((delResult = heap.delMax()) != null){ System.out.print(delResult + " "); } } }
G F E D C B A
|
四、总结
本篇文章我们介绍了:
1、堆的特性:
1、它是完全二叉树
2、它主要用数组实现。访问当前 k 节点的父节点为 k/2,左子节点为 2k,右子节点为 2k + 1
3、每个节点大于等于它的两个子节点。注意和二叉树区分开来
2、堆的 API 设计,代码实现,并进行了测试用例测试
好了,本篇文章到这里就结束了,感谢你的阅读🤝