堆-堆排序

    堆排序,与归并排序一样,时间复杂度为O(nlgn),与插入排序一样,具有空间原址性:任何时候都只需要常数个额外的元素空间存储临时数据。(二叉)堆是一个数组,可以被看成一个近似的完全二叉树,树上的每一个结点对应数组中的一个元素。除了最底层外,该树是完全充满的,而且是从左向右填充。表示堆的数组A有两个属性:A.length为数组元素的个数,A.heap-size表示有多少个堆元素存储在数组中。树的根结点为A[0],容易得到父结点、左孩子和右孩子的下标:

二叉堆分为最大堆和最小堆。结点的值都要满足堆序性质,最大堆中,堆中的最大元素存放在根结点中;并且,在任一子树中,该子树所包含的所有结点的值都不大于该子树根结点的值,最小堆性质相反。
堆的基本过程:
Max-Heapify过程:时间复杂度为O(lgn),是维护最大堆性质的关键。Build-Max-Heap过程:具有线性时间复杂度,功能是从无序的输入数据数组中构造一个最大堆。HeapSort过程:时间复杂度为O(nlgn),功能是对一个数据进行原址排序。Max-Heap-Insert、Heap-Extract-Max、Heap-Increase-Key和Heap-Maximum过程:时间复杂度为O(lgn),功能是利用堆实现一个优先队列。

Max-Heapify的输入为一个数组A和一个下标i,通过让A[i]的值在最大堆中“逐级下降",从而使得以下标i为根结点的子树重新遵循最大堆的性质,可通过递归和非递归两种方式实现,代码如下:
 1 void
 2 percDownRecursion(int a[],int i, int n)   // max-heapify 下滤 维护最大堆性质 递归方式
 3 {
 4     int left = left(i);
 5     int right = right(i);
 6     int large;
 7     if(left < n && a[left] > a[i])
 8         large = left;
 9     else
10         large = i;
11     if(right < n && a[right] > a[large])
12         large = right;
13     if(large != i){
14         swap(a[i],a[large]);
15         percDownRecursion(a,large,n);
16     }
17 }
 1 void percDown(int a[],int i, int n)      //max-heapify 下滤 维护最大堆性质 非递归方式
 2 {
 3         int child;
 4     int tmp;
 5
 6     for(tmp = a[i]; left(i) < n; i = child)
 7     {
 8         child = left(i);
 9         if(child != n-1 && a[child + 1] > a[child])
10             child++;
11         if(tmp < a[child])
12             a[i] = a[child];
13         else
14             break;
15     }
16     a[i] = tmp;
17 }

建堆,可以用自底向上的方法利用过程Max-Heapify把一个大小为n的数组A转换为最大堆,A[n/2]后的元素都是树的叶结点,每个叶结点都可以看成只包含一个元素的堆,时间复杂度为O(n)。。

1 void buildMaxHeap(int a[], int n)
2 {
3     for(int i = n/2; i >= 0; i--) // build heap 构建最大堆
4         percDownRecursion(a,i,n);
5 }

堆排序,堆排序算法利用Build-Max-Heap将输入数组A建成最大堆,因为数组中的最大元素总在根结点A[0]中,通过把它与A[n-1]进行互换,可以让该元素放到正确的位置,缩减堆的大小并进行下滤,从而在A[0...n-2]上构造一个新的最大堆。堆排序算法会不断重复这一过程,直到堆的大小从n-1降到1。

 1 void
 2 heapSort(int a[], int n)
 3 {
 4         buildMaxHeap(a,n);
 5     for(int i = n-1; i > 0; i--)
 6     {
 7         swap(a[0],a[i]);
 8         percDownRecursion(a,0,i); //或者调用percDown(a,0,i)
 9     }
10 }

例子:

1 int main()
2 {
3    int a[] = {97,53,59,26,41,58,31};
4    int size = 7;
5    heapSort(a,size);
6    for(int i=0; i < size; ++i)
7      printf("%d ",a[i]);
8    printf("\n");
9  }

输出:

时间: 2024-10-02 04:15:08

堆-堆排序的相关文章

【数据结构】排序番外篇 堆,堆排序与其前身选择排序

堆 优先队列:特殊的"队列",取出元素的顺序是依照元素的优先权(关键字)大小,而不是元素进入队列的先后顺序 堆是优先队列的完全二叉树表示. 堆的两个特性: ①结构性:用数组表示的完全二叉树 ②有序性:任意结点的关键字是其子树所有结点的最大值,叫最大堆(或最小值,叫最小堆)(注意从根结点到任意结点路径上结点序列的有序性) 下面举一个最大堆的例子. /** 最大堆的操作 */ typedef struct HeapStruct *MaxHeap; struct HeapStruct { E

算法导论学习之堆+堆排序+堆构成优先队列

注:堆分为最大堆和最小堆两种,下面我们讨论的堆都是指的最大堆,最小堆的性质与其是类似的. 堆数据结构是一种数组对象,可以被视为一棵完全二叉树(这棵二叉树除最后一层外,其余每层都是填满的):我们用一个数组来存储一个堆,表示堆的数组有两个属性:length[A]表示的是数组中的元素个数,headsize[A]表示堆中元素个数(也就是说数组中的元素不一定都是堆中的元素). 下面不加证明的给出一些堆的性质: 对于任何一个节点,其父节点为i/2(i>1):左儿子:2*i,右儿子:2*i+1; 对于最大堆每

数据结构 二叉堆 &amp; 堆排序

二叉堆,是一个满二叉树,满足堆的性质.即父节点大于等于子节点(max heap)或者是父节点小于等于子节点(min heap).二叉堆的如上性质常用于优先队列(priority queue)或是用于堆排序. 由于max heap 与min heap类似,下文只针对min heap进行讨论和实现. 如上图,是根据字母的ASCII码建立的最小堆. 我们用数组对满二叉树采用宽度优先遍历存储堆结构,如下图所示: 从数组下标1开始存储堆,这样的处理方式可以得到如下性质: 1.堆中的每个父节点k,他的两个子

最大(小)堆和堆排序简介

(注:本文的相关叙述和图片摘自<数据结构与算法分析新视角>(周幸妮等),因此本文只是我的一个复习记录,详细的论述请参考该书.) 1. 最大(小)堆 对于一个完全二叉树来说,如果所有的结点(叶子结点除外)的值都大于(小于)其左右孩子结点的值,那么这个完全二叉树就被成为一个大(小)根堆.如下图所示.按照堆的定义可以发现,堆顶结点(二叉树的根结点)一定对应整个序列中的最大(小)记录.这样一来,可以设计一种排序思路,每次将堆的堆顶记录输出,同时调整剩余的记录,使它们从新排成一个堆.重复这个过程,就能最

堆排序(Heap Sort)的C语言实现

堆排序(Heap Sort)具体步骤为 将无序序列建成大顶堆(小顶堆):从最后一个非叶子节点开始通过堆调整HeapAdjust()变成小顶堆或大顶堆 将顶部元素与堆尾数组交换,此是末尾元素就是最大值,顶部元素不满足堆,故要将顶部元素在剩余的i-1个元素中调整为堆 反复第2步.直至所有顶点被输出,序列变成从小到大的有序序列 C语言实现(编译器Dev-c++5.4.0,源代码后缀.cpp) 原创文章,转载请注明来自钢铁侠Mac博客http://www.cnblogs.com/gangtiexia 1

Java 实现堆排序

堆 堆排序和合并排序一样,是一种时间复杂度为O(nlgn)的算法,同时和插入排序一样,是一种就地排序算法(不需要额外的存储空间).堆排序需要用到一种被称为最大堆的数据结构,与java或者lisp的gc不一样,这里的堆是一种数据结构,他可以被视为一种完全二叉树,即树里面除了最后一层其他层都是填满的.也正是因为这样,树里面每个节点的子女和双亲节点的序号都可以根据当前节点的序号直接求出. Parent(i)=i/2 Left(i)=2*i Right(i)=2*i+1 如上图所示,1位置的子女节点分别

数据结构 堆排序原理及其实现

堆:堆是具有特殊性质的二叉树 每个结点都大于其左右儿子的的二叉树叫大顶堆 每个结点都小于其左右儿子的二叉树叫做小顶堆 堆排序图解: 给定一个整形数组a[]={16,7,3,20,17,8},对其进行堆排序. 首先根据该数组元素构建一个完全二叉树,得到 然后需要构造初始堆,则从最后一个非叶节点开始调整,调整过程如下: 20和16交换后导致16不满足堆的性质,因此需重新调整 这样就得到了初始堆. 即每次调整都是从父节点.左孩子节点.右孩子节点三者中选择最大者跟父节点进行交换(交换之后可能造成被交换的

排序系列算法——堆排序

堆:大根堆与小根堆 堆排序是建立在堆基础上的排序方法,首先了解一下什么是堆. 常用的堆一般有两种,大根堆和小根堆.堆可以看做是一棵二叉树,其父节点的值总是大于(大根堆)或者小于(小根堆)子节点的值.举一个例子: 图1 不满足堆的条件                 图2大根堆                             图3 小根堆 图1不是堆,因为不满足父节点的值大于或者小于子节点的值: 图2是大根堆,根节点是最大值,父节点都大于或等于子节点的值: 图3是小根堆,根节点是最小值,父

『算法设计_伪代码』堆排序

建立堆 堆排序 堆内某个元素值变大(优先级提升)后调整堆 插入元素到堆尾 原文地址:https://www.cnblogs.com/hellcat/p/9255337.html