数据结构之堆
定义
堆是一种特别的树状结构,我们首先来看看维基百科的上定义。
堆(英语:Heap)是计算机科学中的一种特别的树状数据结构。若是满足以下特性,即可称为堆:“给定堆中任意节点 P 和 C,若 P 是 C 的母节点,那么 P 的值会小于等于(或大于等于) C 的值”。若母节点的值恒小于等于子节点的值,此堆称为最小堆(min heap);反之,若母节点的值恒大于等于子节点的值,此堆称为最大堆(max heap)。在堆中最顶端的那一个节点,称作根节点(root node),根节点本身没有母节点(parent node)。总结来说,堆是一个完全二叉树,最多只有两个子节点,并且必须保证根节点是最大的值或者最小的值,所以对于一个堆而言,根节点是最大的值或者是最小的值。
存储
因为堆是一棵完全二叉树,所以使用数组可以高效的存储数据。对于使用数组存储的方式,有两个性质非常关键,对于一个非根节点的节点i
来说,如果它的下标为k
,那么它的父节点的下标为 (k -1)/2
,子节点的下标为2 *k +1
和2 *k + 2
基本操作
- 堆化
- 插入
- 删除
堆化
对于任意一个无序数组而言,实现堆化的步骤如下,我们以构建一个最大堆为例:
- 找到第一个非叶子节点,对这个节点的左子树和右子树与节点比较,将大的元素放置到父节点的位置,直到父节点已经是最大值或者改节点已经是叶子节点。
- 依次对所有的非叶子节点进行第一步的操作
private Heap(int[] data) { int last_p = data.length - 1; //i是第一个非叶子节点 for (int i = (last_p - 1) / 2; i >= 0; i--) { heapify(data, i, last_p); } this.data = data; } private void heapify(int[] data, int start, int end) { int value = data[start]; int current_p = start; //左孩子 int left_p = 2 * current_p + 1; while (left_p <= end) { //右节点大于左节点 if (left_p < end && data[left_p] < data[left_p + 1]) { //移动位置到右节点 left_p++; } //当前的父节点已经是最大值 if (data[left_p] < value) { break; } else { //子节点上移到父节点的位置 data[current_p] = data[left_p]; current_p = left_p; left_p = current_p * 2 + 1; } } data[current_p] = value; }
插入
插入的算法如下:.将新增的节点放在数组的最末端,也就是数组的最后一个位置。然后计算出父节点的位置,让当前节点与父节点比较,如果父节点比较小,交换位置。重复上述步骤,直到父节点大于当前节点或者当前节点是根节点。
public int insert(int value) { checkSize(); int position = data.length - 1; data[position] = value; int current_p = position; int parent_p = (position - 1) / 2; while (current_p > 0) { if (data[parent_p] > value) { break; } else { data[current_p] = data[parent_p]; current_p = parent_p; parent_p = (current_p - 1) / 2; } } data[current_p] = value; return position; }
删除
删除的算法如下:将数组最后一个节点与当前需要删除的节点替换,删除最后一个节点,对于替换的节点来说,相当于进行了依次插入操作,不过这次是从上往下的插入。算法与remove相同,也是比较最大的值进行替换,直到不满足条件为止。
删除根节点 public int remove() { int root = data[0]; int last = data[data.length - 1]; data[0] = last; data = Arrays.copyOf(data, data.length - 1); if (data.length == 0) { return root; } //从顶点开始调整 int current_p = 0; int l = current_p * 2 + 1; int value = data[current_p]; while (l < data.length) { if (l < data.length - 1 && data[l] < data[l + 1]) { l++; //右孩子大 } if (data[l] <= value) { break; } else { data[current_p] = data[l]; current_p = l; l = current_p * 2 + 1; } } data[current_p] = value; return root; }
应用
堆应用比较多的一个用处就是堆排序,对于一个数组进行堆化之后,第一个数组是最大的值,然后交换第一个数和最后一个数,这样最大的数就落在了最后一个数组的位置。缩小数组,重复之前的步骤,最后就得到了一个排序好的数组。
int[] data = new int[] {20, 40, 80, 33, 111, 47, 21, 90, -1}; HeapSort hs = new HeapSort(); hs.heap_array(data, data.length - 1); for (int i = 0; i < data.length - 1; i++) { int tmp = data[0]; data[0] = data[data.length - 1 - i]; data[data.length - 1 - i] = tmp; hs.heap_array(data, data.length - 2 - i); } System.out.println(Arrays.toString(data));
相关推荐
LauraRan 2020-09-28
范范 2020-07-30
mingyunxiaohai 2020-07-28
mingyunxiaohai 2020-07-19
koushr 2020-11-12
zhangxiafll 2020-11-13
kikaylee 2020-10-31
范范 2020-10-28
MILemon 2020-10-22
hugebawu 2020-10-12
shenwenjie 2020-09-24
omyrobin 2020-09-23
guangcheng 2020-09-22
qiangde 2020-09-13
hanyujianke 2020-08-18
晨曦之星 2020-08-14
xiesheng 2020-08-06
KAIrving 2020-08-02