zoukankan      html  css  js  c++  java
  • 常用排序算法(六)堆排序

    堆排序

    概要

    本章介绍排序算法中的堆排序。

    目录
    1. 堆排序介绍
    2. 堆排序图文说明
    3. 堆排序的时间复杂度和稳定性
    4. 堆排序实现
    4.1 堆排序C实现
    4.2 堆排序C++实现
    4.3 堆排序Java实现

    转载请注明出处:http://www.cnblogs.com/skywang12345/p/3602162.html


    更多排序和算法请参考:数据结构与算法系列 目录

    堆排序介绍

    堆排序(Heap Sort)是指利用堆这种数据结构所设计的一种排序算法。
    因此,学习堆排序之前,有必要了解堆!若读者不熟悉堆,建议先了解(建议可以通过二叉堆左倾堆斜堆二项堆斐波那契堆等文章进行了解),然后再来学习本章。

    我们知道,堆分为"最大堆"和"最小堆"。最大堆通常被用来进行"升序"排序,而最小堆通常被用来进行"降序"排序。
    鉴于最大堆和最小堆是对称关系,理解其中一种即可。本文将对最大堆实现的升序排序进行详细说明。

    最大堆进行升序排序的基本思想:
    ① 初始化堆:将数列a[1...n]构造成最大堆。
    ② 交换数据:将a[1]和a[n]交换,使a[n]是a[1...n]中的最大值;然后将a[1...n-1]重新调整为最大堆。 接着,将a[1]和a[n-1]交换,使a[n-1]是a[1...n-1]中的最大值;然后将a[1...n-2]重新调整为最大值。 依次类推,直到整个数列都是有序的。

    下面,通过图文来解析堆排序的实现过程。注意实现中用到了"数组实现的二叉堆的性质"。
    在第一个元素的索引为 0 的情形中:
    性质一:索引为i的左孩子的索引是 (2*i+1);
    性质二:索引为i的左孩子的索引是 (2*i+2);
    性质三:索引为i的父结点的索引是 floor((i-1)/2);

    例如,对于最大堆{110,100,90,40,80,20,60,10,30,50,70}而言:索引为0的左孩子的所有是1;索引为0的右孩子是2;索引为8的父节点是3。

    堆排序图文说明

    堆排序(升序)代码

    复制代码
    /* 
     * (最大)堆的向下调整算法
     *
     * 注:数组实现的堆中,第N个节点的左孩子的索引值是(2N+1),右孩子的索引是(2N+2)。
     *     其中,N为数组下标索引值,如数组中第1个数对应的N为0。
     *
     * 参数说明:
     *     a -- 待排序的数组
     *     start -- 被下调节点的起始位置(一般为0,表示从第1个开始)
     *     end   -- 截至范围(一般为数组中最后一个元素的索引)
     */
    void maxheap_down(int a[], int start, int end)
    {
        int c = start;            // 当前(current)节点的位置
        int l = 2*c + 1;        // 左(left)孩子的位置
        int tmp = a[c];            // 当前(current)节点的大小
        for (; l <= end; c=l,l=2*l+1)
        {
            // "l"是左孩子,"l+1"是右孩子
            if ( l < end && a[l] < a[l+1])
                l++;        // 左右两孩子中选择较大者,即m_heap[l+1]
            if (tmp >= a[l])
                break;        // 调整结束
            else            // 交换值
            {
                a[c] = a[l];
                a[l]= tmp;
            }
        }
    }
    
    /*
     * 堆排序(从小到大)
     *
     * 参数说明:
     *     a -- 待排序的数组
     *     n -- 数组的长度
     */
    void heap_sort_asc(int a[], int n)
    {
        int i;
    
        // 从(n/2-1) --> 0逐次遍历。遍历之后,得到的数组实际上是一个(最大)二叉堆。
        for (i = n / 2 - 1; i >= 0; i--)
            maxheap_down(a, i, n-1);
    
        // 从最后一个元素开始对序列进行调整,不断的缩小调整的范围直到第一个元素
        for (i = n - 1; i > 0; i--)
        {
            // 交换a[0]和a[i]。交换后,a[i]是a[0...i]中最大的。
            swap(a[0], a[i]);
            // 调整a[0...i-1],使得a[0...i-1]仍然是一个最大堆。
            // 即,保证a[i-1]是a[0...i-1]中的最大值。
            maxheap_down(a, 0, i-1);
        }
    }
    复制代码

    heap_sort_asc(a, n)的作用是:对数组a进行升序排序;其中,a是数组,n是数组长度。
    heap_sort_asc(a, n)的操作分为两部分:初始化堆 和 交换数据。
    maxheap_down(a, start, end)是最大堆的向下调整算法。

    下面演示heap_sort_asc(a, n)对a={20,30,90,40,70,110,60,10,100,50,80}, n=11进行堆排序过程。下面是数组a对应的初始化结构:

    1 初始化堆

    在堆排序算法中,首先要将待排序的数组转化成二叉堆。
    下面演示将数组{20,30,90,40,70,110,60,10,100,50,80}转换为最大堆{110,100,90,40,80,20,60,10,30,50,70}的步骤。

    1.1 i=11/2-1,即i=4

    上面是maxheap_down(a, 4, 9)调整过程。maxheap_down(a, 4, 9)的作用是将a[4...9]进行下调;a[4]的左孩子是a[9],右孩子是a[10]。调整时,选择左右孩子中较大的一个(即a[10])和a[4]交换。

    1.2 i=3

    上面是maxheap_down(a, 3, 9)调整过程。maxheap_down(a, 3, 9)的作用是将a[3...9]进行下调;a[3]的左孩子是a[7],右孩子是a[8]。调整时,选择左右孩子中较大的一个(即a[8])和a[4]交换。

    1.3 i=2


    上面是maxheap_down(a, 2, 9)调整过程。maxheap_down(a, 2, 9)的作用是将a[2...9]进行下调;a[2]的左孩子是a[5],右孩子是a[6]。调整时,选择左右孩子中较大的一个(即a[5])和a[2]交换。

    1.4 i=1


    上面是maxheap_down(a, 1, 9)调整过程。maxheap_down(a, 1, 9)的作用是将a[1...9]进行下调;a[1]的左孩子是a[3],右孩子是a[4]。调整时,选择左右孩子中较大的一个(即a[3])和a[1]交换。交换之后,a[3]为30,它比它的右孩子a[8]要大,接着,再将它们交换。

    1.5 i=0


    上面是maxheap_down(a, 0, 9)调整过程。maxheap_down(a, 0, 9)的作用是将a[0...9]进行下调;a[0]的左孩子是a[1],右孩子是a[2]。调整时,选择左右孩子中较大的一个(即a[2])和a[0]交换。交换之后,a[2]为20,它比它的左右孩子要大,选择较大的孩子(即左孩子)和a[2]交换。

    调整完毕,就得到了最大堆。此时,数组{20,30,90,40,70,110,60,10,100,50,80}也就变成了{110,100,90,40,80,20,60,10,30,50,70}。

    第2部分 交换数据

    在将数组转换成最大堆之后,接着要进行交换数据,从而使数组成为一个真正的有序数组。
    交换数据部分相对比较简单,下面仅仅给出将最大值放在数组末尾的示意图。

    上面是当n=10时,交换数据的示意图。
    当n=10时,首先交换a[0]和a[10],使得a[10]是a[0...10]之间的最大值;然后,调整a[0...9]使它称为最大堆。交换之后:a[10]是有序的!
    当n=9时, 首先交换a[0]和a[9],使得a[9]是a[0...9]之间的最大值;然后,调整a[0...8]使它称为最大堆。交换之后:a[9...10]是有序的!
    ...
    依此类推,直到a[0...10]是有序的。

     

    堆排序的时间复杂度和稳定性

    堆排序时间复杂度
    堆排序的时间复杂度是O(N*lgN)。
    假设被排序的数列中有N个数。遍历一趟的时间复杂度是O(N),需要遍历多少次呢?
    堆排序是采用的二叉堆进行排序的,二叉堆就是一棵二叉树,它需要遍历的次数就是二叉树的深度,而根据完全二叉树的定义,它的深度至少是lg(N+1)。最多是多少呢?由于二叉堆是完全二叉树,因此,它的深度最多也不会超过lg(2N)。因此,遍历一趟的时间复杂度是O(N),而遍历次数介于lg(N+1)和lg(2N)之间;因此得出它的时间复杂度是O(N*lgN)。

    堆排序稳定性
    堆排序是不稳定的算法,它不满足稳定算法的定义。它在交换数据的时候,是比较父结点和子节点之间的数据,所以,即便是存在两个数值相等的兄弟节点,它们的相对顺序在排序也可能发生变化。
    算法稳定性 -- 假设在数列中存在a[i]=a[j],若在排序之前,a[i]在a[j]前面;并且排序之后,a[i]仍然在a[j]前面。则这个排序算法是稳定的!

    堆排序实现

    下面给出堆排序的三种实现:C、C++和Java。这三种实现的原理和输出结果都是一样的,每一种实现中都包括了"最大堆对应的升序排列"和"最小堆对应的降序排序"。
    堆排序C实现
    实现代码(heap_sort.c)

      1 /**
      2  * 堆排序:C 语言
      3  *
      4  * @author skywang
      5  * @date 2014/03/12
      6  */
      7 
      8 #include <stdio.h>
      9 
     10 // 数组长度
     11 #define LENGTH(array) ( (sizeof(array)) / (sizeof(array[0])) )
     12 #define swap(a,b) (a^=b,b^=a,a^=b)
     13 
     14 /* 
     15  * (最大)堆的向下调整算法
     16  *
     17  * 注:数组实现的堆中,第N个节点的左孩子的索引值是(2N+1),右孩子的索引是(2N+2)。
     18  *     其中,N为数组下标索引值,如数组中第1个数对应的N为0。
     19  *
     20  * 参数说明:
     21  *     a -- 待排序的数组
     22  *     start -- 被下调节点的起始位置(一般为0,表示从第1个开始)
     23  *     end   -- 截至范围(一般为数组中最后一个元素的索引)
     24  */
     25 void maxheap_down(int a[], int start, int end)
     26 {
     27     int c = start;            // 当前(current)节点的位置
     28     int l = 2*c + 1;        // 左(left)孩子的位置
     29     int tmp = a[c];            // 当前(current)节点的大小
     30     for (; l <= end; c=l,l=2*l+1)
     31     {
     32         // "l"是左孩子,"l+1"是右孩子
     33         if ( l < end && a[l] < a[l+1])
     34             l++;        // 左右两孩子中选择较大者,即m_heap[l+1]
     35         if (tmp >= a[l])
     36             break;        // 调整结束
     37         else            // 交换值
     38         {
     39             a[c] = a[l];
     40             a[l]= tmp;
     41         }
     42     }
     43 }
     44 
     45 /*
     46  * 堆排序(从小到大)
     47  *
     48  * 参数说明:
     49  *     a -- 待排序的数组
     50  *     n -- 数组的长度
     51  */
     52 void heap_sort_asc(int a[], int n)
     53 {
     54     int i;
     55 
     56     // 从(n/2-1) --> 0逐次遍历。遍历之后,得到的数组实际上是一个(最大)二叉堆。
     57     for (i = n / 2 - 1; i >= 0; i--)
     58         maxheap_down(a, i, n-1);
     59 
     60     // 从最后一个元素开始对序列进行调整,不断的缩小调整的范围直到第一个元素
     61     for (i = n - 1; i > 0; i--)
     62     {
     63         // 交换a[0]和a[i]。交换后,a[i]是a[0...i]中最大的。
     64         swap(a[0], a[i]);
     65         // 调整a[0...i-1],使得a[0...i-1]仍然是一个最大堆。
     66         // 即,保证a[i-1]是a[0...i-1]中的最大值。
     67         maxheap_down(a, 0, i-1);
     68     }
     69 }
     70 
     71 /* 
     72  * (最小)堆的向下调整算法
     73  *
     74  * 注:数组实现的堆中,第N个节点的左孩子的索引值是(2N+1),右孩子的索引是(2N+2)。
     75  *     其中,N为数组下标索引值,如数组中第1个数对应的N为0。
     76  *
     77  * 参数说明:
     78  *     a -- 待排序的数组
     79  *     start -- 被下调节点的起始位置(一般为0,表示从第1个开始)
     80  *     end   -- 截至范围(一般为数组中最后一个元素的索引)
     81  */
     82 void minheap_down(int a[], int start, int end)
     83 {
     84     int c = start;            // 当前(current)节点的位置
     85     int l = 2*c + 1;        // 左(left)孩子的位置
     86     int tmp = a[c];            // 当前(current)节点的大小
     87     for (; l <= end; c=l,l=2*l+1)
     88     {
     89         // "l"是左孩子,"l+1"是右孩子
     90         if ( l < end && a[l] > a[l+1])
     91             l++;        // 左右两孩子中选择较小者
     92         if (tmp <= a[l])
     93             break;        // 调整结束
     94         else            // 交换值
     95         {
     96             a[c] = a[l];
     97             a[l]= tmp;
     98         }
     99     }
    100 }
    101 
    102 /*
    103  * 堆排序(从大到小)
    104  *
    105  * 参数说明:
    106  *     a -- 待排序的数组
    107  *     n -- 数组的长度
    108  */
    109 void heap_sort_desc(int a[], int n)
    110 {
    111     int i;
    112 
    113     // 从(n/2-1) --> 0逐次遍历每。遍历之后,得到的数组实际上是一个最小堆。
    114     for (i = n / 2 - 1; i >= 0; i--)
    115         minheap_down(a, i, n-1);
    116 
    117     // 从最后一个元素开始对序列进行调整,不断的缩小调整的范围直到第一个元素
    118     for (i = n - 1; i > 0; i--)
    119     {
    120         // 交换a[0]和a[i]。交换后,a[i]是a[0...i]中最小的。
    121         swap(a[0], a[i]);
    122         // 调整a[0...i-1],使得a[0...i-1]仍然是一个最小堆。
    123         // 即,保证a[i-1]是a[0...i-1]中的最小值。
    124         minheap_down(a, 0, i-1);
    125     }
    126 }
    127 
    128 void main()
    129 {
    130     int i;
    131     int a[] = {20,30,90,40,70,110,60,10,100,50,80};
    132     int ilen = LENGTH(a);
    133 
    134     printf("before sort:");
    135     for (i=0; i<ilen; i++)
    136         printf("%d ", a[i]);
    137     printf("
    ");
    138 
    139     heap_sort_asc(a, ilen);            // 升序排列
    140     //heap_sort_desc(a, ilen);        // 降序排列
    141 
    142     printf("after  sort:");
    143     for (i=0; i<ilen; i++)
    144         printf("%d ", a[i]);
    145     printf("
    ");
    146 }

    堆排序C++实现
    实现代码(HeapSort.cpp)

      1 /**
      2  * 堆排序:C++
      3  *
      4  * @author skywang
      5  * @date 2014/03/11
      6  */
      7 
      8 #include <iostream>
      9 using namespace std;
     10 
     11 /* 
     12  * (最大)堆的向下调整算法
     13  *
     14  * 注:数组实现的堆中,第N个节点的左孩子的索引值是(2N+1),右孩子的索引是(2N+2)。
     15  *     其中,N为数组下标索引值,如数组中第1个数对应的N为0。
     16  *
     17  * 参数说明:
     18  *     a -- 待排序的数组
     19  *     start -- 被下调节点的起始位置(一般为0,表示从第1个开始)
     20  *     end   -- 截至范围(一般为数组中最后一个元素的索引)
     21  */
     22 void maxHeapDown(int* a, int start, int end)
     23 {
     24     int c = start;            // 当前(current)节点的位置
     25     int l = 2*c + 1;        // 左(left)孩子的位置
     26     int tmp = a[c];            // 当前(current)节点的大小
     27     for (; l <= end; c=l,l=2*l+1)
     28     {
     29         // "l"是左孩子,"l+1"是右孩子
     30         if ( l < end && a[l] < a[l+1])
     31             l++;        // 左右两孩子中选择较大者,即m_heap[l+1]
     32         if (tmp >= a[l])
     33             break;        // 调整结束
     34         else            // 交换值
     35         {
     36             a[c] = a[l];
     37             a[l]= tmp;
     38         }
     39     }
     40 }
     41 
     42 /*
     43  * 堆排序(从小到大)
     44  *
     45  * 参数说明:
     46  *     a -- 待排序的数组
     47  *     n -- 数组的长度
     48  */
     49 void heapSortAsc(int* a, int n)
     50 {
     51     int i,tmp;
     52 
     53     // 从(n/2-1) --> 0逐次遍历。遍历之后,得到的数组实际上是一个(最大)二叉堆。
     54     for (i = n / 2 - 1; i >= 0; i--)
     55         maxHeapDown(a, i, n-1);
     56 
     57     // 从最后一个元素开始对序列进行调整,不断的缩小调整的范围直到第一个元素
     58     for (i = n - 1; i > 0; i--)
     59     {
     60         // 交换a[0]和a[i]。交换后,a[i]是a[0...i]中最大的。
     61         tmp = a[0];
     62         a[0] = a[i];
     63         a[i] = tmp;
     64         // 调整a[0...i-1],使得a[0...i-1]仍然是一个最大堆。
     65         // 即,保证a[i-1]是a[0...i-1]中的最大值。
     66         maxHeapDown(a, 0, i-1);
     67     }
     68 }
     69 
     70 /* 
     71  * (最小)堆的向下调整算法
     72  *
     73  * 注:数组实现的堆中,第N个节点的左孩子的索引值是(2N+1),右孩子的索引是(2N+2)。
     74  *     其中,N为数组下标索引值,如数组中第1个数对应的N为0。
     75  *
     76  * 参数说明:
     77  *     a -- 待排序的数组
     78  *     start -- 被下调节点的起始位置(一般为0,表示从第1个开始)
     79  *     end   -- 截至范围(一般为数组中最后一个元素的索引)
     80  */
     81 void minHeapDown(int* a, int start, int end)
     82 {
     83     int c = start;            // 当前(current)节点的位置
     84     int l = 2*c + 1;        // 左(left)孩子的位置
     85     int tmp = a[c];            // 当前(current)节点的大小
     86     for (; l <= end; c=l,l=2*l+1)
     87     {
     88         // "l"是左孩子,"l+1"是右孩子
     89         if ( l < end && a[l] > a[l+1])
     90             l++;        // 左右两孩子中选择较小者
     91         if (tmp <= a[l])
     92             break;        // 调整结束
     93         else            // 交换值
     94         {
     95             a[c] = a[l];
     96             a[l]= tmp;
     97         }
     98     }
     99 }
    100 
    101 /*
    102  * 堆排序(从大到小)
    103  *
    104  * 参数说明:
    105  *     a -- 待排序的数组
    106  *     n -- 数组的长度
    107  */
    108 void heapSortDesc(int* a, int n)
    109 {
    110     int i,tmp;
    111 
    112     // 从(n/2-1) --> 0逐次遍历每。遍历之后,得到的数组实际上是一个最小堆。
    113     for (i = n / 2 - 1; i >= 0; i--)
    114         minHeapDown(a, i, n-1);
    115 
    116     // 从最后一个元素开始对序列进行调整,不断的缩小调整的范围直到第一个元素
    117     for (i = n - 1; i > 0; i--)
    118     {
    119         // 交换a[0]和a[i]。交换后,a[i]是a[0...i]中最小的。
    120         tmp = a[0];
    121         a[0] = a[i];
    122         a[i] = tmp;
    123         // 调整a[0...i-1],使得a[0...i-1]仍然是一个最小堆。
    124         // 即,保证a[i-1]是a[0...i-1]中的最小值。
    125         minHeapDown(a, 0, i-1);
    126     }
    127 }
    128 
    129 int main()
    130 {
    131     int i;
    132     int a[] = {20,30,90,40,70,110,60,10,100,50,80};
    133     int ilen = (sizeof(a)) / (sizeof(a[0]));
    134 
    135     cout << "before sort:";
    136     for (i=0; i<ilen; i++)
    137         cout << a[i] << " ";
    138     cout << endl;
    139 
    140     heapSortAsc(a, ilen);            // 升序排列
    141     //heapSortDesc(a, ilen);        // 降序排列
    142 
    143     cout << "after  sort:";
    144     for (i=0; i<ilen; i++)
    145         cout << a[i] << " ";
    146     cout << endl;
    147 
    148     return 0;
    149 }

    堆排序Java实现
    实现代码(HeapSort.java)

      1 /**
      2  * 堆排序:Java
      3  *
      4  * @author skywang
      5  * @date 2014/03/11
      6  */
      7 
      8 public class HeapSort {
      9 
     10     /* 
     11      * (最大)堆的向下调整算法
     12      *
     13      * 注:数组实现的堆中,第N个节点的左孩子的索引值是(2N+1),右孩子的索引是(2N+2)。
     14      *     其中,N为数组下标索引值,如数组中第1个数对应的N为0。
     15      *
     16      * 参数说明:
     17      *     a -- 待排序的数组
     18      *     start -- 被下调节点的起始位置(一般为0,表示从第1个开始)
     19      *     end   -- 截至范围(一般为数组中最后一个元素的索引)
     20      */
     21     public static void maxHeapDown(int[] a, int start, int end) {
     22         int c = start;            // 当前(current)节点的位置
     23         int l = 2*c + 1;        // 左(left)孩子的位置
     24         int tmp = a[c];            // 当前(current)节点的大小
     25 
     26         for (; l <= end; c=l,l=2*l+1) {
     27             // "l"是左孩子,"l+1"是右孩子
     28             if ( l < end && a[l] < a[l+1])
     29                 l++;        // 左右两孩子中选择较大者,即m_heap[l+1]
     30             if (tmp >= a[l])
     31                 break;        // 调整结束
     32             else {            // 交换值
     33                 a[c] = a[l];
     34                 a[l]= tmp;
     35             }
     36         }
     37     }
     38 
     39     /*
     40      * 堆排序(从小到大)
     41      *
     42      * 参数说明:
     43      *     a -- 待排序的数组
     44      *     n -- 数组的长度
     45      */
     46     public static void heapSortAsc(int[] a, int n) {
     47         int i,tmp;
     48 
     49         // 从(n/2-1) --> 0逐次遍历。遍历之后,得到的数组实际上是一个(最大)二叉堆。
     50         for (i = n / 2 - 1; i >= 0; i--)
     51             maxHeapDown(a, i, n-1);
     52 
     53         // 从最后一个元素开始对序列进行调整,不断的缩小调整的范围直到第一个元素
     54         for (i = n - 1; i > 0; i--) {
     55             // 交换a[0]和a[i]。交换后,a[i]是a[0...i]中最大的。
     56             tmp = a[0];
     57             a[0] = a[i];
     58             a[i] = tmp;
     59             // 调整a[0...i-1],使得a[0...i-1]仍然是一个最大堆。
     60             // 即,保证a[i-1]是a[0...i-1]中的最大值。
     61             maxHeapDown(a, 0, i-1);
     62         }
     63     }
     64 
     65     /* 
     66      * (最小)堆的向下调整算法
     67      *
     68      * 注:数组实现的堆中,第N个节点的左孩子的索引值是(2N+1),右孩子的索引是(2N+2)。
     69      *     其中,N为数组下标索引值,如数组中第1个数对应的N为0。
     70      *
     71      * 参数说明:
     72      *     a -- 待排序的数组
     73      *     start -- 被下调节点的起始位置(一般为0,表示从第1个开始)
     74      *     end   -- 截至范围(一般为数组中最后一个元素的索引)
     75      */
     76     public static void minHeapDown(int[] a, int start, int end) {
     77         int c = start;            // 当前(current)节点的位置
     78         int l = 2*c + 1;        // 左(left)孩子的位置
     79         int tmp = a[c];            // 当前(current)节点的大小
     80 
     81         for (; l <= end; c=l,l=2*l+1) {
     82             // "l"是左孩子,"l+1"是右孩子
     83             if ( l < end && a[l] > a[l+1])
     84                 l++;        // 左右两孩子中选择较小者
     85             if (tmp <= a[l])
     86                 break;        // 调整结束
     87             else {            // 交换值
     88                 a[c] = a[l];
     89                 a[l]= tmp;
     90             }
     91         }
     92     }
     93 
     94     /*
     95      * 堆排序(从大到小)
     96      *
     97      * 参数说明:
     98      *     a -- 待排序的数组
     99      *     n -- 数组的长度
    100      */
    101     public static void heapSortDesc(int[] a, int n) {
    102         int i,tmp;
    103 
    104         // 从(n/2-1) --> 0逐次遍历每。遍历之后,得到的数组实际上是一个最小堆。
    105         for (i = n / 2 - 1; i >= 0; i--)
    106             minHeapDown(a, i, n-1);
    107 
    108         // 从最后一个元素开始对序列进行调整,不断的缩小调整的范围直到第一个元素
    109         for (i = n - 1; i > 0; i--) {
    110             // 交换a[0]和a[i]。交换后,a[i]是a[0...i]中最小的。
    111             tmp = a[0];
    112             a[0] = a[i];
    113             a[i] = tmp;
    114             // 调整a[0...i-1],使得a[0...i-1]仍然是一个最小堆。
    115             // 即,保证a[i-1]是a[0...i-1]中的最小值。
    116             minHeapDown(a, 0, i-1);
    117         }
    118     }
    119 
    120     public static void main(String[] args) {
    121         int i;
    122         int a[] = {20,30,90,40,70,110,60,10,100,50,80};
    123 
    124         System.out.printf("before sort:");
    125         for (i=0; i<a.length; i++)
    126             System.out.printf("%d ", a[i]);
    127         System.out.printf("
    ");
    128 
    129         heapSortAsc(a, a.length);            // 升序排列
    130         //heapSortDesc(a, a.length);        // 降序排列
    131 
    132         System.out.printf("after  sort:");
    133         for (i=0; i<a.length; i++)
    134             System.out.printf("%d ", a[i]);
    135         System.out.printf("
    ");
    136     }
    137 }

    它们的输出结果:

    before sort:20 30 90 40 70 110 60 10 100 50 80 
    after  sort:10 20 30 40 50 60 70 80 90 100 110 
  • 相关阅读:
    一套简单通用的Java后台管理系统(SpringBoot +Security + Layui实现一套权限管理后台模板)
    org.thymeleaf.exceptions.TemplateInputException: Error resolving template [cart/getCurrentUserCartItem], template might not exist or might not be accessible by any of the configured Template Resolvers
    ARTS-WEEK-009
    ARTS-WEEK-008
    从一次外卖到对oauth2.0的思考
    网络滴神,TCP!
    浪里来浪里去!网络协议如何成就网上冲浪?
    IO、NIO实现简单聊天室,附带问题解析
    IntelliJ IDEA 中使用 Lambok (注解无效问题的解决)
    M5310-A 版本
  • 原文地址:https://www.cnblogs.com/alantu2018/p/8465502.html
Copyright © 2011-2022 走看看