zoukankan      html  css  js  c++  java
  • 经典算法回顾之堆排序【选择排序】

    堆排序与快速排序、归并排序都是时间复杂度为O(NlogN)的常见排序算法。堆排序是一种利用堆的性质进行排序的算法。


    最大堆(最小堆与之类似)是一种比较特殊的完全二叉树,它满足两个特性:
      1. 父节点的值总是大于等于任何一个子节点的值。
      2. 每个节点的左子树和右子树都是一个最大堆。
      【若根的下标从1开始,则节点i的左孩子下标为2i,右孩子下标为2i+1】


    堆排序过程为:
      1. 建立最大堆
      2. 将堆顶元素与最后一个元素交换,将交换后的序列调整为新堆,重复该过程,知道有序元素为n-1个


    故,堆排序的基本框架为

    1 void HeapSort(int a[], int size)
    2 {
    3     BuildHeap(a, size);
    4     for(int i = size; i >= 2; i--)
    5     {
    6         swap(a[1], a[i]);//交换堆顶和最后一个元素,即每次将剩余元素中的最大者放到最后面
    7         HeadAdjust(a ,1 ,i-1);//重新调整,将余下元素调成大顶堆
    8     }
    9 }        

     
    完整代码如下:

      1 #include "stdafx.h"
      2 #include <iostream>
      3 using namespace std;
      4 
      5 /*堆排序
      6  *时间复杂度:O(NlogN)
      7  *堆是完全二叉树;且有大小堆之分
      8  *注意:数组从1开始,因为这样才满足;对于节点i,其左孩子是2*i,右孩子是2*i+1
      9  *应用:最大堆排序用来从小到大排序数列
     10  *扩展:堆经常被用来求一个数列中的第K大的数,只需要建立一个大小为K的最小堆,堆顶就是第K大的数;
     11  *        (如:选前k个数建最小堆,若后面的数比堆顶小,舍弃;若比堆顶大,舍弃堆顶,将数据插入
     12  *            调整最小堆)!!!想清楚
     13  *            求数列中第K小的数,建立大小为K的最大堆,堆顶就是第K小的数。复杂度为O(NlogK)
     14  *            //参见《编程之美》Chapter5的第五节
     15 */
     16 
     17 #include "stdafx.h"
     18 #include <algorithm>//std::swap()
     19 #include <iostream>
     20 
     21 using namespace std;
     22 
     23 void HeapAdjust(int a[], int i, int size)
     24 //a为堆数组,i为当前要调整的节点,以下标i为堆顶,将剩余size个元素调整为堆(即节点数为size)
     25  
     26 {
     27        int lchild = 2 * i;//i节点左右孩子节点序号
     28        int rchild = 2 * i + 1;
     29        int max = i;//临时变量,记录最大值的下标
     30  
     31        if(i <= size / 2)//对叶节点i进行调整
     32        {
     33               if(lchild <= size && a[lchild] > a[max])//注意边界检查,包括size
     34                      max = lchild;
     35               if(rchild <= size && a[rchild] > a[max])
     36                      max = rchild;
     37               if(max != i)//需调整
     38               {
     39                      swap(a[i], a[max]);
     40                      HeapAdjust(a, max, size); //避免调整后以下标max为父节点的子树不是堆
     41               }
     42        }
     43 }
     44 
     45 /*
     46 void HeapAdjust(int a[], int i, int size)
     47 //堆调整非递归实现
     48 {
     49     a[0] = a[i];//用空闲位置a[0]临时记录当前节点的值
     50     int lchild = 2 * i;
     51     int max = i;//临时变量,记录最大值的下标
     52 
     53     while( lchild <= size )
     54     {
     55         if(lchild <= size && a[lchild] > a[max])//注意边界检查,包括size
     56             max = lchild;
     57         if((lchild + 1 <= size) && a[lchild+1] > a[max])
     58             max = lchild+1;
     59         if(max == i)
     60             break;//无需调整
     61         else
     62         {
     63             //a[i] = a[max];//!!
     64             swap(a[i],a[max]);
     65             i = max;//!!
     66             lchild = i * 2; //!!
     67         }        
     68     }
     69     //a[i] = a[0];//!!被调整节点的值被放入最终位置
     70 }
    
     71 */
     72 
     73 
     74 void BuildHeap(int a[], int size)//建堆
     75 {
     76     for(int i = size/2; i >= 1; --i)//非叶节点最大序号值为size/2 
     77         HeapAdjust(a, i, size);
     78 }
     79 
     80 void HeapSort(int a[],int size)//堆排序
     81 {
     82     BuildHeap(a,size);
     83     for(int i=size;i>=2;--i)//到2!
     84     {
     85         swap(a[1],a[i]);//交换堆顶和最后一个元素,即每次将剩余元素中的最大者放到最后面
     86         HeapAdjust(a,1,i-1);//重新调整,将余下元素调成大顶堆
     87     }
     88 }
     89 
     90 int main(int argc, char *argv[])
     91 {
     92     //int a[] = {0,16,20,3,11,17,8};
     93     int a[100];
     94     cout << "请输入要排序的数字个数:" ;
     95     int size;
     96     while(cin >> size && size>0 && size < 100)
     97     {
     98         for(int i=1; i <= size; ++i)//注意从下标1开始存数据
     99             cin >> a[i];
    100         HeapSort(a,size);
    101         for(int i=1; i <= size; ++i)
    102             cout << a[i] << " ";
    103         cout << endl;
    104         cout << "请输入要排序的数字个数:" ;
    105     }
    106     return 0;
    107 }
    View Code

    参考:http://www.cnblogs.com/dolphin0520/archive/2011/10/06/2199741.html

      

  • 相关阅读:
    Django 初探--Django的开发服务器及创建数据库(笔记)
    Django初探--开发环境搭建(笔记)
    python文件处理--笔记
    python-property、docstring--笔记
    python之Lambda函数---笔记
    参数拆分-- 笔记
    python—带形状的词云图
    python—压缩文件
    python—dataframe用法
    python—mysql数据库读取表1获取name作为参数,传入访问表2获取age,结果存入excel
  • 原文地址:https://www.cnblogs.com/dreamrun/p/4365387.html
Copyright © 2011-2022 走看看