数据结构基础(19) --堆与堆排序

完全二叉树

 

首先让我们回顾一下完全二叉树的两个性质:

  性质1:具有n个结点的完全二叉树的深度为[logn](向下取整)+1。

  性质2:若对含 个结点的完全二叉树从上到下且从左至右进行 至 的编号,则对完全二叉树中任意一个编号为 的结点:

    (1) 若 i=1,则该结点是二叉树的根,无双亲,否则,编号为 [i/2](向下取整)的结点为其双亲结点;
    (2) 若 2i>n,则该结点无左孩子,否则,编号为 2i 的结点为其左孩子结点;
    (3) 若 2i+1>n,则该结点无右孩子结点,否则,编号为2i+1 的结点为其右孩子结点。

 

数组与完全二叉树

 

从上图可以看出, 如果完全二叉树从上到下且从左至右进行从0至n-1进行编号,则对完全二叉树的性质需要修改如下:

   (1) 若 i=0,则该结点是二叉树的根,无双亲,否则,编号为 [(i-1)/2](向下取整)的结点为其双亲结点;
   (2) 若 2i+1>n,则该结点无左孩子,否则,编号为 2i+1 的结点为其左孩子结点;
   (3) 若 2i+2>n,则该结点无右孩子结点,否则,编号为2i+2 的结点为其右孩子结点。


大顶堆与小顶堆

 

堆是满足下列性质的数列{r1, r2, …,rn}:


(小顶堆)


(大顶堆)

 

大顶堆的设计

  1. template <typename Type>  
  2. class MaxHeap  
  3. {  
  4. public:  
  5.     MaxHeap(int _maxSize = 10);  
  6.     virtual ~MaxHeap();  
  7.   
  8.     bool isEmpty() const;  
  9.     void push(const Type &item);  
  10.     void pop();  
  11.     const Type &top() const;  
  12.   
  13. private:  
  14.     //将堆的容量增大两倍  
  15.     void resize();  
  16.     //向上渗透  
  17.     void trickUp(int index);  
  18.     //向下渗透  
  19.     void trickDown(int index);  
  20.   
  21. private:  
  22.     Type *heapArray;  
  23.     int maxSize;  
  24.     //currentSize有两个含义:  
  25.     // 1.代表当前堆中已经存储的元素数  
  26.     // 2.代表当前完全二叉树的第一个空位  
  27.     int currentSize;  
  28. };  

大顶堆的实现

  1. //构造  
  2. template <typename Type>  
  3. MaxHeap<Type>::MaxHeap(int _maxSize)  
  4.     : maxSize(_maxSize),currentSize(0)  
  5. {  
  6.     if (maxSize < 1)  
  7.         throw std::length_error("heap size must >= 1");  
  8.   
  9.     heapArray = new Type[maxSize];  
  10. }  
  11. //析构  
  12. template <typename Type>  
  13. MaxHeap<Type>::~MaxHeap()  
  14. {  
  15.     delete []heapArray;  
  16.     heapArray = NULL;  
  17.     currentSize = 0;  
  18. }  
  19. //判空  
  20. template <typename Type>  
  21. bool MaxHeap<Type>::isEmpty() const  
  22. {  
  23.     return currentSize == 0;  
  24. }  

堆顶元素

  1. //查看堆顶元素  
  2. template <typename Type>  
  3. const Type &MaxHeap<Type>::top() const  
  4. {  
  5.     if (isEmpty())  
  6.         throw std::underflow_error("heap is empty");  
  7.   
  8.     return heapArray[0];  
  9. }  

插入元素

  1. //插入  
  2. template <typename Type>  
  3. void MaxHeap<Type>::push(const Type &item)  
  4. {  
  5.     //如果堆已满, 则需要对堆进行扩充  
  6.     if (currentSize == maxSize)  
  7.     {  
  8.         resize();  
  9.     }  
  10.     //将元素插入到堆的第一个空位置上  
  11.     heapArray[currentSize] = item;  
  12.   
  13.     //维护堆的性质:向上渗透  
  14.     trickUp(currentSize);  
  15.     ++ currentSize;  
  16. }  
  1. //向上渗透, 将刚刚插入的元素移动到合适的位置上  
  2. template <typename Type>  
  3. void MaxHeap<Type>::trickUp(int index)  
  4. {  
  5.     //根据完全二叉树的性质, 找到父节点  
  6.     int parent = (index-1)/2;  
  7.     Type bottom = heapArray[index];  
  8.   
  9.     //循环终止条件  
  10.     // 1. index = 0 //bottom元素插入到根节点  
  11.     // 2. heapArray[parent] >= bottom   //bottom插入到parent节点的一个子节点上  
  12.     while ((index > 0) && (heapArray[parent] < bottom))  
  13.     {  
  14.         //父节点下移  
  15.         heapArray[index] = heapArray[parent];  
  16.         index = parent;  
  17.         parent = (parent-1)/2;  
  18.     }  
  19.     //插入  
  20.     heapArray[index] = bottom;  
  21. }  
  1. //将堆的大小加倍  
  2. template <typename Type>  
  3. void MaxHeap<Type>::resize()  
  4. {  
  5.     int newSize = std::max(maxSize*2, 1);  
  6.     Type *newHeap = new Type[newSize];  
  7.     for (int i = 0; i < currentSize; ++i)  
  8.     {  
  9.         newHeap[i] = heapArray[i];  
  10.     }  
  11.   
  12.     delete []heapArray;  
  13.     heapArray = newHeap;  
  14.     maxSize = newSize;  
  15. }  

删除堆顶元素

  1. //删除  
  2. template <typename Type>  
  3. void MaxHeap<Type>::pop()  
  4. {  
  5.     if (isEmpty())  
  6.         throw std::underflow_error("heap is empty");  
  7.   
  8.     //只有一个元素  
  9.     if (currentSize == 1)  
  10.     {  
  11.         heapArray[0].~Type();  
  12.         currentSize = 0;  
  13.         return ;  
  14.     }  
  15.   
  16.     //显示释放堆顶元素  
  17.     heapArray[0].~Type();  
  18.     //直接将最有一个元素放到堆顶,  
  19.     //并且currentSize-1  
  20.     heapArray[0] = heapArray[-- currentSize];  
  21.   
  22.     //此时如果破坏了堆的性质:向下渗透  
  23.     trickDown(0);  
  24. }  
  1. //向下渗透  
  2. template <typename Type>  
  3. void MaxHeap<Type>::trickDown(int index)  
  4. {  
  5.     int largeChild;  
  6.     Type top = heapArray[index];  
  7.   
  8.     // 只需到达完全二叉树的最后一层  
  9.     // 的上一层即可  
  10.     // 循环的终止条件:  
  11.     // 1. index已经到达了最后一层(index >= currentSize/2 :找到了一个比较合适的位置)  
  12.     // 2. 在堆的中间找到了一个合适的位置(top >= heapArray[largeChild])  
  13.     while (index < currentSize/2)  
  14.     {  
  15.         int leftChild = (index*2)+1;  
  16.         int rightChild = leftChild + 1;  
  17.   
  18.         //如果有右儿子节点, 而且右儿子节点还大于左儿子节点  
  19.         if (rightChild < currentSize && heapArray[rightChild] > heapArray[leftChild])  
  20.             largeChild = rightChild;  
  21.         else  
  22.             largeChild = leftChild;  
  23.   
  24.         if (top >= heapArray[largeChild])  
  25.             break;  
  26.   
  27.         //不然的话, 则需继续向下渗透  
  28.         heapArray[index] = heapArray[largeChild];  
  29.         // index需要向下搜索  
  30.         index = largeChild;  
  31.     }  
  32.     //插入  
  33.     heapArray[index] = top;  
  34. }  

堆排序

  堆排序就是将元素一个一个插入到堆中, 然后再一个一个的取出来;

  1. //堆排序  
  2. template <typename Type>  
  3. void heapSort(Type *begin, Type *end)  
  4. {  
  5.     int size = end-begin;  
  6.     MaxHeap<Type> maxHeap(size);  
  7.     //存入堆中  
  8.     for (Type *current = begin; current < end; ++ current)  
  9.         maxHeap.push(*current);  
  10.   
  11.     //从堆中取出  
  12.     while (begin != end)  
  13.     {  
  14.         *begin = maxHeap.top();  
  15.         ++ begin;  
  16.         maxHeap.pop();  
  17.     }  
  18. }  
  19.   
  20. template <typename Type>  
  21. void heapSort(Type *array, int arraySize)  
  22. {  
  23.     return heapSort(array, array+arraySize);  
  24. }  

-测试代码:

  1. int main()  
  2. {  
  3.     int array[20];  
  4.     for (int i = 0; i < 20; ++i)  
  5.     {  
  6.         array[i] = rand()%100;  
  7.         cout << array[i] << ' ';  
  8.     }  
  9.   
  10.     heapSort(array, 20);  
  11.   
  12.     cout << endl;  
  13.     for (int i = 0; i < 20; ++i)  
  14.     {  
  15.         cout << array[i] << ' ';  
  16.     }  
  17.     cout << endl;  
  18.   
  19.     return 0;  


原文地址:http://blog.csdn.net/zjf280441589/article/details/42682141

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值