码迷,mamicode.com
首页 > 其他好文 > 详细

二叉堆

时间:2014-11-19 20:16:13      阅读:174      评论:0      收藏:0      [点我收藏+]

标签:style   blog   http   io   ar   color   os   使用   sp   

二叉堆

 

 

我们知道堆栈是一种LIFO(后进先出)结构,队列是一种FIFO(先进先出)结构,而二叉堆是一种最小值先出的数据结构,因此二叉堆很适合用来做排序

二叉树的性质:二叉堆是一棵完全二叉树,且任意一个结点的键值总是小于或等于其子结点的键值,

二叉堆采用数组来存储(按广度优先遍历的顺序),而没有像普通的树结构使用指针来表示节点间的关系。

如下图所示:

bubuko.com,布布扣

 

如图,最小的一个元素就是数组第一个元素。

将二叉堆按最广优先遍历的顺序编号从0到N-1,根据完全二叉树的性质,则第n个结点的子结点分别是2n+1和2n+2,其父结点是(n-1)/2。并且,叶子结点的下标是从 (N-1)/2开始,一直到N-1。这样,对于数组中的任意一个元素,我们可以很方便的计算出它的父节点、孩子节点所在的位置(即数组下标)。

 


插入

如果要在二叉堆中插入或删除一个元素,必须保证堆性质仍能满足。

假如要在上面的二叉堆里插入一个键值为2的新元素,那只需在数组末尾加入这个元素,然后尽可能把这个元素往上挪,直到挪不动,经过了这种复杂度为Ο(logn)的操作,二叉堆还是二叉堆。如下图:

bubuko.com,布布扣

 

 

插入过程:

如上图,将键值为2的元素放在数组最后一个位置(下标为12,下标从0开始计数),

其父节点是下标为5的元素,且其键值为6>2,不满足堆性质,将两个元素交换;

现在键值为2的新元素的下标变成了5,其父节点是下标为2的元素,该元素键值为5>2,继续交换!

 

 


 

删除

删除操作一定是踢出数组的第一个元素,这么来第一个元素以前的位置就成了空位,我们需要把这个空位挪至叶子节点,然后把数组最后一个元素插入这个空位,把这个“空位”尽量往上挪,如下图所示:

bubuko.com,布布扣

最后意:删除和插入一样,都是O(n)的时间复杂度。

 

 

 


C++的一个实现:

#include <iostream>

using namespace std;

#define SWAP_TWO_INT(a, b) a^=b; b^=a; a^=b;

class CBinaryHeap
{
    public:
        CBinaryHeap(int iSize = 100);
        ~CBinaryHeap();

        //Return 0 means failed.
        int Enqueue(int iVal);
        int Dequeue(int &iVal);
        int GetMin(int &iVal);

        void PrintQueue();

    protected:
        int *m_pData;
        int m_iSize;
        int m_iAmount;
};

CBinaryHeap::CBinaryHeap(int iSize)
{
    m_pData = new int[iSize];
    m_iSize = iSize;
    m_iAmount = 0;
}

CBinaryHeap::~CBinaryHeap()
{
    delete[] m_pData;
}

int CBinaryHeap::Enqueue(int iVal)
{
    if (m_iAmount == m_iSize)
        return 0;

    //Put this value to the end of the array.
    m_pData[m_iAmount++] = iVal;

    int iIndex = m_iAmount - 1;

    while (m_pData[iIndex] < m_pData[(iIndex-1)/2]) {

        SWAP_TWO_INT(m_pData[iIndex], m_pData[(iIndex-1)/2])

        iIndex = (iIndex-1)/2;
    }

    return 1;
}

int CBinaryHeap::Dequeue(int &iVal)
{
    if(m_iAmount==0)
        return 0;

    iVal = m_pData[0];
    int iIndex = 0;
    while (iIndex*2<m_iAmount)
    {
        int iLeft = (iIndex*2+1 < m_iAmount)?(iIndex*2+1):0;
        int iRight = (iIndex*2+2 < m_iAmount)?(iIndex*2+2):0;
        if(iLeft && iRight) // Both left and right exists.
        {
            if(m_pData[iLeft]<m_pData[iRight])
            {
                SWAP_TWO_INT(m_pData[iIndex], m_pData[iLeft])
                    iIndex = iLeft;
            }
            else
            {
                SWAP_TWO_INT(m_pData[iIndex], m_pData[iRight])
                    iIndex = iRight;
            }
        }
        else if(iLeft) //The iRight must be 0
        {
            SWAP_TWO_INT(m_pData[iIndex], m_pData[iLeft])
                iIndex = iLeft;
            break;
        }
        else
        {
            break;
        }
    }

    //Move the last element to the blank position.
    //Of course, if it is the blank one, forget it.
    if(iIndex!=m_iAmount-1)
    {
        m_pData[iIndex] = m_pData[m_iAmount-1];

        //Try to move this element to the top as high as possible.
        while(m_pData[iIndex] < m_pData[(iIndex-1)/2])
        {
            //Swap the two value
            SWAP_TWO_INT(m_pData[iIndex], m_pData[(iIndex-1)/2])
                iIndex = (iIndex-1)/2;
        }
    }

    --m_iAmount;
    return 1;
}

int CBinaryHeap::GetMin(int &iVal)
{
    if (m_iAmount==0)
        return 0;
    iVal = m_pData[0];
    return 1;
}

void CBinaryHeap::PrintQueue()
{
    int i;
    for (i=0; i<m_iAmount; i++) {
        cout<<m_pData[i]<<"\t";
    }
    cout<<endl;
}

int main()
{
    int iVal;
    CBinaryHeap bh;

    bh.Enqueue(4);
    bh.Enqueue(1);
    bh.Enqueue(3);
    bh.Enqueue(2);
    bh.Enqueue(6);
    bh.Enqueue(5);

    bh.PrintQueue();

    bh.Dequeue(iVal);
    bh.Dequeue(iVal);

    bh.PrintQueue();

    return 0;
}

 

 

 

 

 

 

 

 

 

最大堆:父结点的键值总是大于或等于任何一个子结点的键值;最大堆常用于排序算法。
最小堆:父结点的键值总是小于或等于任何一个子结点的键值;最小堆常用于优先队列。

 

二叉堆

标签:style   blog   http   io   ar   color   os   使用   sp   

原文地址:http://www.cnblogs.com/chenny7/p/4108954.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!