堆是一种特别的树状结构,咱们首先来看看维基百科的上定义。java
堆(英语:Heap)是 计算机科学中的一种特别的树状 数据结构。如果知足如下特性,便可称为堆:“给定堆中任意节点 P 和 C,若 P 是 C 的母节点,那么 P 的值会小于等于(或大于等于) C 的值”。若母节点的值恒 小于等于子节点的值,此堆称为 最小堆(min heap);反之,若母节点的值恒 大于等于子节点的值,此堆称为 最大堆(max heap)。在堆中最顶端的那一个节点,称做 根节点(root node),根节点自己没有 母节点(parent node)。
总结来讲,堆是一个彻底二叉树,最多只有两个子节点,而且必须保证根节点是最大的值或者最小的值,因此对于一个堆而言,根节点是最大的值或者是最小的值。node
由于堆是一棵彻底二叉树,因此使用数组能够高效的存储数据。对于使用数组存储的方式,有两个性质很是关键,对于一个非根节点的节点i
来讲,若是它的下标为k
,那么它的父节点的下标为 (k -1)/2
,子节点的下标为2 *k +1
和2 *k + 2
git
对于任意一个无序数组而言,实现堆化的步骤以下,咱们以构建一个最大堆为例:算法
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; }
插入的算法以下:.将新增的节点放在数组的最末端,也就是数组的最后一个位置。而后计算出父节点的位置,让当前节点与父节点比较,若是父节点比较小,交换位置。重复上述步骤,直到父节点大于当前节点或者当前节点是根节点。api
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));
代码地址: https://gitee.com/devnew/Algo...this