【算法和数据结构】大顶堆定义和封装,堆排序(C++实现)

      在前面的几篇文章中,介绍了线性表的三种数据结构:链表、队列和栈。他们因为各自的特性,都可以方便的支持某一种运算。比如链表相比于数组,其插入和删除的时间代价更为优化。

       除了这些数据结构之外,今天和大家分享需要支持如下两种运算的数据结构:插入元素和寻找最大元素。这两种运算的数据 结构称为优先队列,其有效实现便是通过。下面给出大顶堆的定义:

      一个(二叉)堆是一棵几乎完全的二叉树,它的每个节点都满足如下特性:存储在父节点中的数据项键值不小于存储在节点中数据项键值。

      从上述特性中,我们可以知道:沿着每条路径,元素的键值以非升序排列。定义如下在堆上的运算:

  • int deleteMax():删除最大值并返回
  • void insertElement(int x):插入数据x到堆中
  • int deleteElement(int i):删除其中i数据项并返回
  • void makeHeap():将普通数组转换为大顶堆
  • void heapSort():堆排序,将堆中数据按升序排列

      我们用数组H来表示堆,则有:

  • 根节点存储在H[1]中
  • 对于某个节点H[j],若其拥有左右子节点,则左子节点在H[2j]中,右子节点在H[2j+1]中
  • H[j]的父节点如果不是根节点,则在H[(int)j/2]中

       在正式实现上述定义的运算之前,先介绍两个辅助运算,这两个辅助运算又是不可或缺、尤为重要的:sift-up和sift-down运算。

  • sift-up运算:假设对于某个H[i],其键值大于父节点键值时,这样就不满足大顶堆的特性,故而需要进行动态维护。sift-up运算就是沿着H[i]到根节点的唯一路径将其移动到合适的位置上。具体方法就是:在沿着路径的每一步上,将H[i]和其父节点H[(int)i/2]比较,若不满足堆特性,则交换以使其满足。
  • sift-down运算:对于i<=(int)n/2,若H[i]中元素键值小于H[2i]和H[2i+1]的最大值,则违反堆的特性,需要动态维护。实现过程与sift-up类似,不再赘述。

       以下给出大顶堆的C++实现,通过类封装上述操作:

class MaxHeap
{
private:
    int *heap;
    int heapSize;

public:
    MaxHeap(int numOfElenment)
    {
        heapSize = numOfElenment;
        int length = heapSize + 1;
        heap = new int[length];
    }
    ~MaxHeap()
    {
        delete[]heap;
    }

    void initialHeap()
    {
        heap[0] = -1;
        for (int i = 1;i <= heapSize;i++)
            cin >> heap[i];
        makeHeap();
    }
    //to input an array and build a max heap
    void printHeap()
    {
        for (int i = 1;i <= heapSize;i++)
            cout << heap[i] << " ";
        cout << endl;
    }
    //tp print the heap
    int getHeapSize()
    {
        return heapSize;
    }
    //return heap size
    void swapValues(int i, int j)
    {
        int middleVariable = 0;
        middleVariable = heap[i];
        heap[i] = heap[j];
        heap[j] = middleVariable;
    }
    //to swap heap[i] and heap[j]
    void siftUp(int i)
    {
        bool done = false;
        if (i == 1)
            return;
        //a root
        do
        {
            if (heap[i] > heap[(int)(i / 2)])
                swapValues(i, (int)(i / 2));
            else
                done = true;
            i = (int)(i / 2);
        } while (i != 1 && done == false);
    }
    //to sift-up heap[i]
    void siftDown(int i)
    {
        bool done = false;
        if (2 * i > heapSize)
            return;
        //leaf
        do
        {
            i = i * 2;
            if ((i + 1 <= heapSize) && (heap[i + 1] > heap[i]))
                i += 1;
            if (heap[(int)(i / 2)] < heap[i])
                swapValues(i, (int)(i / 2));
            else
                done = true;
        } while ((2 * i <= heapSize) && done == false);
    }
    //to sift-down heap[i]
    void insertElement(int x)
    {
        heapSize += 1;
        heap[heapSize] = x;
        siftUp(heapSize);
    }
    //to insert x to the heap
    int deleteElement(int i)
    {
        int x = heap[i];
        int y = heap[heapSize];
        heapSize -= 1;
        if (i == heapSize + 1)
            return x;
        heap[i] = y;
        if (y >= x)
            siftUp(i);
        else
            siftDown(i);
        return x;
    }
    //to delete heap[i] and return it
    int deleteMax()
    {
        int x = heap[1];
        deleteElement(1);
        return x;
    }
    //to delete the max value and return it
    void makeHeap()
    {
        for (int i = (int)(heapSize / 2);i > 0;i--)
        {
            siftDown(i);
        }
    }
    //to transfer "heap" to a max heap
    void heapSort()
    {
        int heapSizeTemp = heapSize;
        for (int j = heapSize;j > 1;j--)
        {
            swapValues(1, j);
            heapSize--;
            siftDown(1);
        heapSize = heapSizeTemp;
    }
    //to sort heap[] asc
};

点击这里下载源码。

你可能感兴趣的:(编程语言)