zoukankan      html  css  js  c++  java
  • 堆排序

    一:什么是堆?
    1.堆: n个元素的序列{k1,k2,k3,.....kn}当且仅当满足以下关系是,称为堆. {ki <= k2i 且 ki <= k2i+1} 或
    {k2i <= ki 且 k2i+1 <= ki} (i = 1,2,...[n/2] ).这也是堆的一个性质.

    2.堆结构是一种数组对象堆,它可以被视为一棵完全二叉树如下图,  书中每个节点与数组中存放该节点中值的那个元素
    对应,除了最后一层,其余的每个节点都是满的.因为堆可看成是一棵完全二叉树,那它就满足一些树的性质,
    对于有n个结点的完全二叉树,对任一结点i 有:  
      1)如果 i = 1,则结点i是二叉树的根,无双亲;
        2)如果i > 1,则其双亲Parent(i)是[ i / 2];
        3)如果2i > n,则结点i 无左孩子(结点i为叶子结点);否则,其左孩子Lift_child(i) 是结点2i.
        4)如果2i + 1 > n,则结点i无右孩子;否则,其右孩子right_child(i)是结点2i + 1.
        5)其非终端结点是第[ n / 2]个元素,(非终端结点是指:完全二叉树中的最后一个带有叶子的结点).

    二:堆的分类
    堆包含: 1.大根堆. 2.小根堆.       
            1. 大根堆必须满足: {ki <= k2i , ki <= k2i+1 (i = 1,2,...[n/2] ), 大根堆排序后元素是由小到大的顺序.
            2.小根堆必须满足:  {k2i <= ki , k2i+1 <= ki} (i = 1,2,...[n/2] ).  小根堆排序后元素是由大到小的顺序.

    三:如何实现堆排序?
    1.堆排序需要解决的两个问题就是:(1)如何由一个无序序列建成一个堆? (2)如何在输出堆顶元素之后,
       调整剩余元素成为一个新的堆?
          
    2. 让一个无序序列建成一个堆的最重要的步骤就是堆调整(牢记堆性质).
        堆调整的思想:
           1).把待调整的记录当成根,然后 比较此根和其左,右孩子这三个数的大小,如果左,右孩子中还中有一个最大的,
                则把此最大值与根值交换(这是大根堆调整法,小根堆调整只需找到最小的值并与根交换就行),
           2).接着从最大值下标开始,并又以此结点为根重复1)中的步骤直到最大值下标循环的叶子结点.
            3)如果1)中比较后得到的最大值(/最小值)仍为根,则表示以此根结点的子序列已满足堆性质,就已经是堆了,

    3.建堆。
        可以自底向上地用heap_adjust来将一个数组array[1..n] (n = length[array])变成一个堆,因为,
    子数组array[(n/2+1)  ....n ]中的 元素都是树上中的叶子,每个叶子都可以看成是一个元素的堆,根据堆的性质知,根是一个最值,而自底向上调整数组,就是子根与子根 或是子根与 叶 再和父根比较 进而可保证越往上值越大(越小)。 

    假设有数组A = {1, 3, 4, 5, 7, 2, 6, 8, 0}。那么调堆的过程如下图,数组下标从0开始,A[3] = 5开始。分别与左孩子和右孩子比较大小,如果A[3]最大,则不用调整,否则和孩子中的值最大的一个交换位置,在图1中是A[7] > A[3] > A[8],所以A[3]与A[7]对换,从图1.1转到图1.2。

    4.堆排序.
            堆排序,首先应该是一个堆,即先让一个无序序列调整成一个堆,然后再进行排序.

    排序的思想:
        1)首先要清楚堆的一个性质,那就是根为最值. 因为数组中最大(或最小)元素是在根array[1]上,因此通过访问根就可以到达排序的效果. 
        2)
    可通过把它与叶子结点array[n]进行交换来达到最终的正确位置.因为叶子都在array[n/2+1 ..n]上,让第一最值根和最后一个叶子交换,然后,再进行堆调整.
        3)第2)中的交换产生两种效果:
                其一,将第一最值保存到array的最后一个元素空间中(此时已进开始进行数组就地排序了!!)
                其二,叶子结点到根后就会破坏堆性质,那就会引起堆调整反应(但,此时的调整有点变化的就是待调整堆的长度,还是原来的数组长度吗? 那肯定不是,如果还是数组长度的话,就会把叶子上的最值又调到了根上,那就会重复访问根了,所以每次交换后,待排序的长度就要减一(待排序的堆大小),使得堆调整到达交换的叶子结点.),进而将第二最值调到了根array[1]的位置.
            然后就是将次最值和倒数第二个叶子交换(将此最值保存到第一最值的前一位置),就这样重复1)步骤,直到最后一个元素.

    c++代码:

    #include <iostream>
    using namespace std;
    
    void exchange(int &a,int &b);       //交换 
    void Max_Heapify(int *,int,int);    //保持堆性质 
    void Build_Max_Heapify(int *,int);  //建堆 
    void Sort_Heap(int*,int);       // 堆排序 
    
    void exchange(int &a,int &b) 
    { 
        int t; t = a ;a = b ; b =t ; 
    } 
    
    void Max_Heapify(int *heap, int i,int heapSize)               //heapSize :堆大小  
    { 
        int l = 2*i + 1;        //左子树下标 
        int r = 2*i + 2;      //右子树下标 
        int largest;           //最大节点下标 
        if(l < heapSize && heap[l] > heap[i]) 
            largest = l; 
        else 
            largest = i; 
    
        if(r < heapSize && heap[r] > heap[largest] ) 
            largest = r; 
    
        if(largest != i) 
        { 
            exchange (heap[i],heap[largest]);   
            Max_Heapify(heap,largest,heapSize); //保持以largest为根节点的子树满足堆性质 
        } 
         
    } 
    
    void Build_Max_Heapify(int *heap,int arraySize)             
    { 
        int i = (arraySize/2)-1;   //含有子树的根节点的下标,(下标最大的根) 
    
        for(; i>=0; i--) 
            Max_Heapify(heap,i,arraySize); 
    } 
    
    void Sort_Heap(int *heap,int arraySize)            
    { 
         
        int i = arraySize-1; 
        Build_Max_Heapify(heap,i); 
         
    
        for(; i>=1 ; i--) 
        { 
            exchange(heap[i],heap[0]); 
            Max_Heapify(heap,0,i-1); 
        } 
    
    } 
    
    
    int main() 
    { 
        int a[N]={1,24,35,6,8,75,89,45,44,5,345,23}; 
         
        int i; 
    
        Sort_Heap(a,N);     
        for(i=0; i<N; i++) 
            cout << a[i]<<" "; 
        cout <<endl; 
    
        return 0; 
    } 
  • 相关阅读:
    探偵ガリレオー転写る 完了
    探偵ガリレオー転写る3
    探偵ガリレオー転写る2
    探偵ガリレオー転写る1
    探偵ガリレオ 燃えるまで
    探偵ガリレオ2
    探偵ガリレオ1
    【转】2014找工作----扎实的基础和开阔的视野是企业最看重的因素
    三种交换两个整数的方法
    计算十进制整数的二进制中的1的数目
  • 原文地址:https://www.cnblogs.com/nygfcn1234/p/3229937.html
Copyright © 2011-2022 走看看