zoukankan      html  css  js  c++  java
  • 排序系列算法——堆排序

    堆:大根堆与小根堆

          堆排序是建立在堆基础上的排序方法,首先了解一下什么是堆。

          常用的堆一般有两种,大根堆和小根堆。堆可以看做是一棵二叉树,其父节点的值总是大于(大根堆)或者小于(小根堆)子节点的值。举一个例子:

     

                             图1 不满足堆的条件                 图2大根堆                             图3 小根堆

          图1不是堆,因为不满足父节点的值大于或者小于子节点的值;

          图2是大根堆,根节点是最大值,父节点都大于或等于子节点的值;

          图3是小根堆,根节点是最小值,父节点都小于或等于子节点的值。

    堆排序

          下面以大根堆为例讲解堆排序:

          大根堆有一个很好的性质,根节点的数值总是大于其他所有节点的数值,利用这个性质,可以实现排序的工作。堆排序的步骤可以描述如下:

          1.构建大根堆。首先我们的原始数组一般情况下是不满足堆的条件,既然我们要可用大根段的性质进行排序,第一步当然是对原始数组进行处理,构建大根堆。

          2.根节点数据处理以及大根堆重构。构建了大根堆之后,根节点的数据是最大值,将该数值取出,对剩下的元素重构大根堆,这时根节点是剩下元素的最大值,取出。只要不断重复上述的操作,不断取出未排序元素的最大值,直到未排序的元素只剩一个,就完成了排序工作。

          说得有点抽象,直接用一个实际的例子说明堆排序的工作步骤:

          对一个无序的序列A={5,4,17,13,15,12,10 }按从小到大进行排序,序列的下标分别为{1,2,3,4,5,6,7},A[i]表示下标为i的元素。

          第一步:对无序的数组构造大根堆

     

    大根堆的根节点是整个序列的最大值。

           第二步

           将A[1]与A[7]互换,此时A[7]为序列的最大值,A[7]已经排序完毕,剩余的元素A[1]~A[6]形成新的未排序序列,由于此时序列不是大根堆,需要重构大根堆。


           第三步

           将A[1]与A[6]互换,此时A[6]为序列的最大值,A[6]已经排序完毕,剩余的元素A[1]~A[5]形成新的未排序序列,由于此时序列不是大根堆,需要重构大根堆。

          第四步

          将A[1]与A[5]互换,此时A[5]为序列的最大值,A[5]已经排序完毕,剩余的元素A[1]~A[4]形成新的未排序序列,由于此时序列不是大根堆,需要重构大根堆。

          第五步

          将A[1]与A[4]互换,此时A[4]为序列的最大值,A[4]已经排序完毕,剩余的元素A[1]~A[3]形成新的未排序序列,由于此时序列不是大根堆,需要重构大根堆。

          第六步

          将A[1]与A[3]互换,此时A[3]为序列的最大值,A[3]已经排序完毕,由于此时未排序的序列只剩下两个元素,而且A[0]>A[1],将A[0]与A[1]互换即可得到最终的已排序序列。

     

    C++程序实现

    从上述的排序过程可知,堆排序主要有两个过程,大根堆的构建与重构:

    1、大根堆的重构

      如何实现大根堆的重构?如果一个原有的数组满足大根堆的性质,而只有其中一个元素改变从而破坏了大根堆的性质,那么可以从该元素出发,不断”逐级下降“,让子节点小于等于父子节点,满足大根堆的性质。以一个实例说明重构的过程:

      堆排序的过程中,每一次改变的只有根节点的元素,因此只需要从根节点出发,进行如上图的操作即可实现大根堆的重构。C++代码如下:

     1 void ReBuildMaxHeap(int *array,int arraylength,int startIndex){
     2     int index=0;
     3     //int j=0;
     4     int max=0;
     5     while((2*startIndex+1)<arraylength){
     6         index = startIndex;
     7         max = array[index];
     8         if(max<(array[2*startIndex+1])){
     9             max=array[2*startIndex+1];
    10             index=2*startIndex+1;
    11         }
    12         if(2*startIndex+2<arraylength&&max<array[2*startIndex+2]){
    13             max=array[2*startIndex+2];
    14             index=2*startIndex+2;
    15         }
    16         if(index==startIndex){
    17             break;
    18         }
    19         swap(array,index,startIndex);
    20         startIndex = index;
    21     }
    22 }

    1、  构建大根堆。

      要构建大根堆,只需要遍历所有非叶子节点元素,使其所有的叶子节点均不大于足该节点元素即可。构建大根堆自低向上对数组进行遍历,如果发现父节点的值小于子节点的值,则将父节点的值与子节点的最大值进行交换,保证父节点的数据总是大于子节点的数据。如果发生了数据的交换,有可能令子节点不满足大根堆条件,需要进行会输重构大根堆。以一个实际的例子说明构建大根堆的过程:

    C++代码如下:

     1 void createHeap(int *array,int length){
     2     int max=0;
     3     int index=0;
     4     for(int i=floor(length/2)-1;i>=0;i--){
     5         index = i;
     6         max = array[i];
     7         if(max<array[2*i+1]){
     8             index=2*i+1;
     9             max = array[2*i+1];
    10         }
    11         if(2*i+2<length&&max<array[2*i+2]){
    12             index = 2*i+2;
    13             max = array[2*i+2];
    14         }
    15         if(index!=i){
    16             swap(array,index,i);
    17             ReBuildMaxValue(array,length,index);
    18         }
    19     }
    20 }

    全部源代码:

     1 #include "stdafx.h"
     2 #include <iostream>
     3 using namespace std;
     4 
     5 //两个文位置的数据交换
     6 void swap(int *array,int num1,int num2){
     7     int temp = *(array+num1);
     8     *(array+num1) = *(array+num2);
     9     *(array+num2) = temp;
    10 }
    11 
    12 //重构大根堆
    13 void ReBuildMaxValue(int *array,int arraylength,int startIndex){
    14     int index=0;
    15     //int j=0;
    16     int max=0;
    17     while((2*startIndex+1)<arraylength){
    18         index = startIndex;
    19         max = array[index];
    20         if(max<(array[2*startIndex+1])){
    21             max=array[2*startIndex+1];
    22             index=2*startIndex+1;
    23         }
    24         if(2*startIndex+2<arraylength&&max<array[2*startIndex+2]){
    25             max=array[2*startIndex+2];
    26             index=2*startIndex+2;
    27         }
    28         if(index==startIndex){
    29             break;
    30         }
    31         swap(array,index,startIndex);
    32         startIndex = index;
    33     }
    34 }
    35 
    36 //构建大根堆
    37 void createHeap(int *array,int length){
    38     int max=0;
    39     int index=0;
    40     for(int i=floor(length/2)-1;i>=0;i--){
    41         index = i;
    42         max = array[i];
    43         if(max<array[2*i+1]){
    44             index=2*i+1;
    45             max = array[2*i+1];
    46         }
    47         if(2*i+2<length&&max<array[2*i+2]){
    48             index = 2*i+2;
    49             max = array[2*i+2];
    50         }
    51         if(index!=i){
    52             swap(array,index,i);
    53             ReBuildMaxValue(array,length,index);
    54         }
    55     }
    56 }
    57 
    58 //堆排序
    59 void heapSort(int *array,int arraylength){
    60     createHeap(array,10);
    61     for(int i=arraylength-1;i>0;i--){
    62         swap(array,i,0);
    63         ReBuildMaxValue(array,i,0);
    64     }
    65 }
    66 
    67 int main(int argc, _TCHAR* argv[])
    68 {
    69     int values[10]={5,4,17,13,15,12,10,7,11,9};
    70     heapSort(values,10);
    71     for(int i=0;i<10;i++){
    72         cout<<*(values+i)<<endl;
    73     }
    74     return 0;
    75 }
  • 相关阅读:
    Socket编程实现客户端与服务器一对一聊天
    HttpClient获取页面信息与Jsoup封装获取
    代码推送
    re正则
    MySQL 的主从复制
    关于前后端的缓存
    session/cookie/token
    如何保证缓存(redis)与数据库(MySQL)的一致性
    进程与线程(程序与任务)
    QA/QC
  • 原文地址:https://www.cnblogs.com/yonghao/p/5140395.html
Copyright © 2011-2022 走看看