内容简介:二叉堆是一种特殊的堆,二叉堆是完全二元树(二叉树)或者是近似完全二元树(二叉树)。最大堆:父结点的键值总是大于或等于任何一个子节点的键值;最小堆:父结点的键值总是小于或等于任何一个子节点的键值。
二叉堆是一种特殊的堆,二叉堆是完全二元树(二叉树)或者是近似完全二元树(二叉树)。
二叉堆有两种:最大堆和最小堆。
最大堆:父结点的键值总是大于或等于任何一个子节点的键值;
最小堆:父结点的键值总是小于或等于任何一个子节点的键值。
对于二叉堆,如下有几种操作
插入节点
二叉堆的节点插入,插入位置是完全二叉树的最后一个位置。比如我们插入一个新节点,值是 0。
这时候,我们让节点0的它的父节点5做比较,如果0小于5,则让新节点“上浮”,和父节点交换位置。
继续用节点0和父节点3做比较,如果0小于3,则让新节点继续“上浮”。
继续比较,最终让新节点0上浮到了堆顶位置。
删除节点
二叉堆的节点删除过程和插入过程正好相反,所删除的是处于堆顶的节点。比如我们删除最小堆的堆顶节点1。
这时候,为了维持完全二叉树的结构,我们把堆的最后一个节点10补到原本堆顶的位置。
接下来我们让移动到堆顶的节点10和它的左右孩子进行比较,如果左右孩子中最小的一个(显然是节点2)比节点10小,那么让节点10“下沉”。
继续让节点10和它的左右孩子做比较,左右孩子中最小的是节点7,由于10大于7,让节点10继续“下沉”。
这样一来,二叉堆重新得到了调整。
构建二叉堆
构建二叉堆,也就是把一个无序的完全二叉树调整为二叉堆,本质上就是让所有非叶子节点依次下沉。
我们举一个无序完全二叉树的例子:
首先,我们从最后一个非叶子节点开始,也就是从节点10开始。如果节点10大于它左右孩子中最小的一个,则节点10下沉。
接下来轮到节点3,如果节点3大于它左右孩子中最小的一个,则节点3下沉。
接下来轮到节点1,如果节点1大于它左右孩子中最小的一个,则节点1下沉。事实上节点1小于它的左右孩子,所以不用改变。
接下来轮到节点7,如果节点7大于它左右孩子中最小的一个,则节点7下沉。
节点7继续比较,继续下沉。
这样一来,一颗无序的完全二叉树就构建成了一个最小堆。
堆的代码实现
二叉堆一般用数组来表示。如果根节点在数组中的位置是1,第n个位置的子节点分别在2n和 2n+1。因此,第1个位置的子节点在2和3,第2个位置的子节点在4和5。以此类推。这种基于1的数组存储方式便于寻找父节点和子节点。
如上图所示二叉堆所示用数组方式表示为 | 1 | 5 | 2 | 6 | 7 | 3 | 8 | 9 | 10 |
堆得代码表示
/** * 上浮调整 * * @param array 待调整的堆 */ public static void upAdjust(int[] array) { int childIndex = array.length - 1; int parentIndex = (childIndex - 1) / 2; // temp保存插入的叶子节点值,用于最后的赋值 int temp = array[childIndex]; while (childIndex > 0 && temp < array[parentIndex]) { //无需真正交换,单向赋值即可 array[childIndex] = array[parentIndex]; childIndex = parentIndex; parentIndex = (parentIndex - 1) / 2; } array[childIndex] = temp; } /** * 下沉调整 * * @param array 待调整的堆 * @param parentIndex 要下沉的父节点 * @param length 堆的有效大小 */ public static void downAdjust(int[] array, int parentIndex, int length) { // temp保存父节点值,用于最后的赋值 int temp = array[parentIndex]; int childIndex = 2 * parentIndex + 1; while (childIndex < length) { // 如果有右孩子,且右孩子小于左孩子的值,则定位到右孩子 if (childIndex + 1 < length && array[childIndex + 1] < array[childIndex]) { childIndex++; } // 如果父节点小于任何一个孩子的值,直接跳出 if (temp <= array[childIndex]) break; //无需真正交换,单向赋值即可 array[parentIndex] = array[childIndex]; parentIndex = childIndex; childIndex = 2 * childIndex + 1; } array[parentIndex] = temp; } /** * 构建堆 * * @param array 待调整的堆 */ public static void buildHeap(int[] array) { // 从最后一个非叶子节点开始,依次下沉调整 int parent = array.length / 2 - 1; for (int i = parent; i >= 0; i--) { downAdjust(array, i, array.length); } } public static void main(String[] args) { int[] array = new int[]{1, 3, 2, 6, 5, 7, 8, 9, 10, 0}; upAdjust(array); System.out.println(Arrays.toString(array)); array = new int[]{7, 1, 3, 10, 5, 2, 8, 9, 6}; buildHeap(array); System.out.println(Arrays.toString(array)); } [0, 1, 2, 6, 3, 7, 8, 9, 10, 5] [1, 5, 2, 6, 7, 3, 8, 9, 10] 复制代码
堆排序
堆 排序 算法的步骤:
1、把无序数组构建成二叉堆。
2、循环删除堆顶元素,移到集合尾部,调节堆产生新的堆顶。
public static void heapSort(int[] array) { // 1.把无序数组构建成二叉堆。 for (int i = (array.length - 2) / 2; i >= 0; i--) { downAdjust(array, i, array.length); } System.out.println(Arrays.toString(array)); // 2.循环删除堆顶元素,移到集合尾部,调节堆产生新的堆顶。 for (int i = array.length - 1; i > 0; i--) { // 最后一个元素和第一元素进行交换 int temp = array[i]; array[i] = array[0]; array[0] = temp; // 下沉调整最大堆 downAdjust(array, 0, i); } } 复制代码
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- 图形化排序算法比较:快速排序、插入排序、选择排序、冒泡排序
- 排序算法下——桶排序、计数排序和基数排序
- 算法之常见排序算法-冒泡排序、归并排序、快速排序
- 【JS面试向】选择排序、桶排序、冒泡排序和快速排序简介
- 计数排序vs基数排序vs桶排序
- 排序算法--冒泡排序
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Flash ActionScript 3.0从入门到精通
章精设、胡登涛 / 清华大学出版社 / 2008-10-1 / 69.00元
Flash ActionScript 3.0的出现,不仅从形式上改变了ActionScript,而且从本质上改变了ActionScript,使ActionScript 3.0成为了真正的面向对象编程语言。 本书从最简单的编程知识出发,带领读者走进编程的大门,是一本不可多得的ActionScript 3.0入门书。本书在注重基础的同时,从更高的层次来介绍ActionScript 3.0的面向对......一起来看看 《Flash ActionScript 3.0从入门到精通》 这本书的介绍吧!