• 堆排序


    堆排序(HeapSort)是利用堆积树(堆)这种数据结构设计的一种排序方法。

    特性:

    1、时间复杂度:N log N

    2、由于建初始堆所需的比较次数较多,所以堆排序不适宜于记录数较少的文件

    3、不稳定的排序方法(排序的稳定性是指如果在排序的序列中,存在前后相同的两个元素的话,排序前 和排序后他们的相对位置不发生变化)

    4、最大堆性质: A[ parent(i) ] >= A[ i ] ,  即叶子结点不大于根节点; 最小堆满足 A[ parent(i) ] <= A[ i ] 

    堆排序分三个步骤:

    1、堆的维护:其时间复杂度是O(nlog n), 

    2、堆的建立:功能是从一个无序的数组中构建一个最大堆

    3、堆排序: 时间复杂度是 O(nlog n)  功能是对一个数组进行原址排序

    伪代码:

     //堆的维护 

    MAX - HEAPIFY(A, currentNode)         
          leftNode = 2 * currentNode + 1                                                         //根节点的左孩子下标计算
          rightNode = 2 * currentNode + 2                                                       //根节点的右孩子下标计算
          if       leftNode < A.heapSize and A[leftNode] > A[currentNode])      //找出当前树种 根、左叶子和右叶子的最大值及下表
                   largest = leftNode;
          else   largest = currentNode;                                                              
          if        rightNode < A.heapSize and A[rightNode] > Ar[largest])
                    largest = rightNode;
          if        largest != currentNode                                                          // 将最大值赋值给根节点 。 并记录最大值的下标(若有交换),对交换后的根结点递归调用MaxHeap()
                    exchange A[currentNode] with A[largest]
                    MaxHeap(A,largest); //当根节点与叶子节点交换后,对堆进行维护,对交换后再对子树进行维护

    //堆的建立

     BUILD - MAX - HEAP(A)    
           A.HeapSize   =   A.length                                    //length指数组中元素个数
          for     i = [A.length/2] downto 0                             //在实际编码时,元素下标最小为0,所以,这里与算法导论书上有区别
                  MAX - HEAPIFY( A, i )

    //堆排序
    HEAPSORT(A)              
          BUILD - MAX - HEAP(A)                            //  将无序数组用堆排序,此时,数组中的最大元素总是在 A[0]中
               for    i  =  A.length downto 0
                      exchange A[0] with A[i]                  // 通过将A[0] 与 A[n]交换,可以使该元素放在正确的位置,并使HeapSize-1
                      A.HeapSize = A.HeapSize -1
                     MAX - HEAPIFY(A,0)

    以下,将堆建立成为一个类,用三个成员函数完成三个功能。用最大堆排序代码:

    #include<iostream>
    #include"math.h"
    using namespace std;
    template<class T>
    class Heap
    {
    public: 
        int HeapSize;
        T* Arry;
        void MaxHeap(int i);                           //维护堆
        void buildHeap(T* arry, int heapSize);         //建立堆
        void HeapSort(T* arry, int heapSize);          //堆排序
    };
    
    template<class T>
    void Heap<T>::MaxHeap(int currentNode)
    {
        int largest;
        int leftNode = 2 * currentNode + 1;
        int rightNode = 2 * currentNode + 2;
        //找出当前树种 根、左叶子和右叶子的最大值及下表,将最大值赋值给根节点。并记录最大值的下标(若有交换),对交换后的根结点递归调用MaxHeap()
        if (leftNode < HeapSize&&Arry[leftNode] > Arry[currentNode]) 
            largest = leftNode;
        else
            largest = currentNode;
        if (rightNode < HeapSize&&Arry[rightNode] > Arry[largest])
            largest = rightNode;
        if (largest != currentNode)
        {
            T temp = Arry[currentNode];
            Arry[currentNode] = Arry[largest];
            Arry[largest] = temp;
            this->MaxHeap(largest);            //当根节点与叶子节点交换后,对堆进行维护,对交换后再对子树进行维护
        }
    }
    template<class T>
    void Heap<T>::buildHeap(T* arry, int heapSize)              //建立堆
    {
        this->HeapSize = heapSize;
        Arry = new T[heapSize];                       //将数据读入到堆中
        for (int i = 0; i < heapSize; i++)
            Arry[i] = arry[i];
        int degree = log(heapSize) / log(2);        //求二叉树的深度-1,由于倒数第一层叶子节点没有叶子,在维护时要从倒数第二层开始遍历
        for (int i = pow(2, degree)-1; i>=0; i--)
            this->MaxHeap(i);
    }
    
    template<class T>
    void Heap<T>::HeapSort(T* arry, int heapSize)          //堆排序,将用堆排序好的数据输出到数组
    {
        buildHeap(arry, heapSize);                  //建立堆,此时,数组中的最大元素总是在 Arry[0]中
        for (int i = heapSize - 1; i > 0; i--)      // 通过将Arry[0] 与 Arry[n]交换,可以使该元素放在正确的位置,并使HeapSize-1
        {
            T temp = this->Arry[0];           
            this->Arry[0] = this->Arry[i];      
            this->Arry[i] = temp;
            this->HeapSize--;
            MaxHeap(0);
        }
    }

    测试代码:

    int main()
    {
        int arry[] = { 21, 1200, 9, 1, 5, 8, 19, 4, 7, 10, 15, 17, 21, 41, 51, 61, 81, 71, 91, 100 };
        Heap<int>hs;
        hs.HeapSort(arry, 20);
        for (int i = 0; i < 20; i++)
            cout << hs.Arry[i] << " ";
        cout << endl;
        cout << "BigThink" << endl;
        system("pause");
        return 0;
    }
    View Code
  • 相关阅读:
    Gradle 10分钟上手指南
    java并发编程学习: 原子变量(CAS)
    java并发编程学习: 守护线程(Daemon Thread)
    java并发编程学习: 阻塞队列 使用 及 实现原理
    java并发编程学习: ThreadLocal使用及原理
    java并发编程学习:如何等待多个线程执行完成后再继续后续处理(synchronized、join、FutureTask、CyclicBarrier)
    ZooKeeper 笔记(5) ACL(Access Control List)访问控制列表
    gradle项目与maven项目相互转化
    rpc框架之 thrift连接池实现
    java并发编程学习:用 Semaphore (信号量)控制并发资源
  • 原文地址:https://www.cnblogs.com/hello-gogo/p/7095283.html
Copyright © 2020-2023  润新知