【数据结构 五】---堆
来源:互联网 发布:校园网络直播系统 编辑:程序博客网 时间:2024/05/21 11:09
在算法的总结过程中,主要是快速排序算法,发现了堆排序,然后之前对堆的概念也不是非常清楚,所以这里做一个总结,帮助自己快速上手来辅助算法的学习。2017.7.15,在总结的过程中用到了以下几个博客的知识,在此感谢:CSDN的http://blog.csdn.net/wypblog/article/details/8076324和博客园的http://www.cnblogs.com/JVxie/p/4859889.html
堆的定义
最大(最小)堆是一棵每一个节点的键值都不小于(大于)其孩子(如果存在)的键值的树。大顶堆是一棵完全二叉树,同时也是一棵最大树。小顶堆是一棵完全完全二叉树,同时也是一棵最小树。
完全二叉树:若设二叉树的深度为h,除第 h 层外,其它各层 (1~h-1) 的结点数都达到最大个数,第 h 层所有的结点都连续集中在最左边,这就是完全二叉树。
注意:
1,堆中任一子树亦是堆。
2,以上讨论的堆实际上是二叉堆(Binary Heap),类似地可定义k叉堆。
下图分别给出几个最大堆(大根堆)和最小堆(小根堆)的例子:
最大堆:根结点的键值是所有堆结点键值中最大者,且每个结点的值都比其孩子的值大。
最小堆:根结点的键值是所有堆结点键值中最小者,且每个结点的值都比其孩子的值小。
一些基本术语
A用于表示堆的数组,下标从1开始,一直到n
parent(t):节点t的父节点,即floor(t/2)
leftchild(t):节点t的左孩子节点,即:2*t
rightchild(t):节点t的右孩子节点,即:2*t+1
heapsize(A):堆A当前的元素数目
需要了解的二叉树信息
深度h为该层的元素(根节点)t的log2(t),例如第0层就是log2(1)=0.
数组放入完全二叉树的时候遵循以上下标格式,例如
下标从1到9分别加入:{8,5,2,10,3,7,1,4,6}。
但此时的完全二叉树并不是一个堆
堆的基本操作
堆支持以下的基本操作:
•build: 建立一个空堆;
•insert: 向堆中插入一个新元素;
•update:将新元素提升使其符合堆的性质;
•get:获取当前堆顶元素的值;
•delete:删除堆顶元素;
•heapify:使删除堆顶元素的堆再次成为堆。
某些堆实现还支持其他的一些操作,如斐波那契堆支持检查一个堆中是否存在某个元素。
堆的应用
堆排序
堆最常见的应用是堆排序,时间复杂度为O(N lg N)。如果是从小到大排序,用大顶堆;从大到小排序,用小顶堆。
在进行堆排序之前,首先要创建一个堆:该操作主要是将数组A转化成一个大顶堆。思想是,先找到堆的最后一个非叶子节点(即为第n/2个节点),然后从该节点开始,从后往前逐个调整每个子树,使之称为堆,最终整个数组便是一个堆。创建过程如下:
public void buildheap(int[] array, int heapsize) { // 建堆函数 for (int i = heapsize / 2; i >= 1; i--) { heapify(array, i, heapsize); } }public void heapify(int[] array, int i, int heapsize) { // 堆调整函数(这里使用的是最大堆),也就是根是大于左右子树的 int leftchild = 2 * i + 1; // 左孩子索引 int rightchild = 2 * i + 2; // 右孩子索引 int largest = 0; // 选出当前结点与左右孩子之中的最大值 if (leftchild < heapsize && array[leftchild] > array[i]) { // 当前节点的左孩子比当前节点大 largest = leftchild; } else largest = i; if (rightchild < heapsize && array[rightchild] > array[largest]) { largest = rightchild; } // 以上的两个if判断出三者之中最大的,没有管谁是第二大的 if(largest!=i){ exchange(array, i, largest); // 把当前结点和它的最大(直接)子节点进行交换 heapify(array,largest,heapsize);//注意这里的递归操作是以防 } }
创建好一个大顶!大顶堆后要开始进行交换,每次将堆顶和最后一个换了,换了之后数组剩下的继续重现建堆。接着重复以上的步骤
public void heapsort(int[] array, int heapsize) { buildheap(array, heapsize); // 建好了堆(大顶堆) for (int i = heapsize; i >= 2; i--) { exchange(array, 1, i); // 将堆顶元素(当前最大值)与堆的最后一个元素互换(该操作很有可能把后面元素的稳定性打乱,所以堆排序是不稳定的排序算法) heapsize--; // 从堆中去掉最后一个元素 heapify(array, 1, heapsize); // 从新的堆顶元素开始进行堆调整 } }
完整的代码如下
package 比较排序;public class HeapSort { public static void main(String[] args) { int[] array = { 5, 2, 9, 4, 7, 6, 1, 3, 8 };// 从小到大堆排序 int len = array.length; int heapsize = len; // 堆的大小也就是数组长度 new HeapSort().heapsort(array, heapsize); System.out.println("堆排序结果:"); for (int i = 0; i < len; i++) { System.out.print(array[i]); } } public void heapsort(int[] array, int heapsize) { buildheap(array, heapsize); // 建好了堆(大顶堆) // ================================================ for (int i = 0; i < heapsize; i++) { System.out.print(array[i]); }// 测试点,打印堆: // ==================================================== for (int i = heapsize; i > 1; i--) { // 堆顶和堆底互换,堆顶的索引是1,但是对应数组array[0] exchange(array, 0, i - 1); // 将堆顶元素(当前最大值)与堆的最后一个元素互换(该操作很有可能把后面元素的稳定性打乱,所以堆排序是不稳定的排序算法) heapsize--; // 从堆中去掉最后一个元素 heapify(array, 0, heapsize); // 从新的堆顶元素开始进行堆调整, } } public void buildheap(int[] array, int heapsize) { // 建堆函数 for (int i = heapsize / 2; i >= 1; i--) { // 注意,这里的i用的是堆的标号方式,从1开始。但在堆里的索引1对应数组array[0],所以传入的为i-1 heapify(array, i - 1, heapsize); } } public void exchange(int[] array, int i, int j) // 交换A[i]和A[j] { int temp = array[i]; array[i] = array[j]; array[j] = temp; } public void heapify(int[] array, int i, int heapsize) { // 堆调整函数(这里使用的是最大堆),也就是根是大于左右子树的 int leftchild = 2 * i + 1; // 左孩子索引 int rightchild = 2 * i + 2; // 右孩子索引 int largest = 0; // 选出当前结点与左右孩子之中的最大值 if (leftchild < heapsize && array[leftchild] > array[i]) { // 当前节点的左孩子比当前节点大 largest = leftchild; } else largest = i; if (rightchild < heapsize && array[rightchild] > array[largest]) { largest = rightchild; } // 以上的两个if判断出三者之中最大的,没有管谁是第二大的 if (largest != i) { exchange(array, i, largest); // 把当前结点和它的最大(直接)子节点进行交换 heapify(array, largest, heapsize); } }}
- 【数据结构 五】---堆
- 【数据结构 五】---堆
- 数据结构之排序(五)堆排序
- 浅谈算法和数据结构: 五 优先级队列与堆排序
- 浅谈算法和数据结构: 五 优先级队列与堆排序
- 浅谈算法和数据结构: 五 优先级队列与堆排序
- 浅谈算法和数据结构: 五 优先级队列与堆排序
- 浅谈算法和数据结构: 五 优先级队列与堆排序
- 浅谈算法和数据结构: 五 优先级队列与堆排序
- 浅谈算法和数据结构: 五 优先级队列与堆排序
- 浅谈算法和数据结构: 五 优先级队列与堆排序
- 数据结构:堆
- 数据结构-堆
- 堆数据结构
- 堆数据结构
- 数据结构:堆
- 数据结构-堆
- 数据结构-堆
- 264. Ugly Number II
- 【数据结构 三】---栈
- centos 调教日记
- 【数据结构 四】---队列
- Protel入门教程
- 【数据结构 五】---堆
- mongo数据库基本操作--python篇
- 【数据结构 六】---树
- 【数据结构 七】---字符串
- 无符号整型数用二进制串表示,求此串中1的个数
- TreeSet的基本用法
- windows 下执行composer self-update出错zlib_decode(): data error
- 【数据结构 八】---集合类
- JavaScript高阶函数 reduce方法的应用和原理分析