Priority Queue learning summary

Ordinary queue, follow the rules of FIFO, add and query elements, but for many cases, we want to find in the sequence of elements in line with our requirements ( 比如序列中最大的元素), this time, whether ordinary linear or linear table table special kind of stack or queue, the card will find the range specified element in the event complexity level of O (n), in fact, we can find the time to achieve reduced complexity O (1), it is through priority queues achieve!


We need to do is to impart one element 优先级: time (for example, if we always want to come up with the queue largest element in use), we create a queue, it will be the highest priority elements on the first team, the last wish the time to the first team can directly take away the element. That whole priority queue is created in descending order of priority out.

So, how do we achieve this vision?
To achieve the above in mind, we need to create a maximum heap ( 因为建最小堆是同样的道理,所以之一最大堆为例来说明), as shown below:

Here Insert Picture DescriptionNot difficult to see, is the biggest corresponding maximum heap priority queue, by complete binary tree, select the complete binary tree reason:
easy to operate, if you create a memory array that is fully binary tree to the root node at index 0, the following descendants left right index 1,2,3 ... can be found:

左孩子节点下标 = 2×对应根节点下标+1 
右孩子节点下标 = 2×对应根节点下标+2

父亲节点下标 = (孩子节点-1)/2

When we enter data into the array, the data is first added to the last position in the array, and then compared the leaf node and its parent node size according to the above formula, if greater than the parent node, it will move down the parent node, sub also mention node until you find the newly added up to big elements than the current parent node, the node will be added later this entire trip. This allows the entire array to store the data in the form of the maximum of the priority queue.

PS.这样只保证了根为整个队列的最大元素,并不能保证离根远的叶子节点一定小于其他离根近叶子节点

If a team, it will return the maximum element, then you want to remove the largest element in the queue, then you need to readjust the structure of the heap, and how to adjust it?
The root transferred last element in the array, and delete the last position corresponding start starts at the root 下沉, that is,

  • The root node data is compared with the leaf node, and if less than all the leaf node, then leaf node and the maximum data exchange;
  • If a child is larger than the root node, then it and the corresponding sub-node can be exchanged.
  • Sinking ... to know to meet the large root than any of its child nodes.

In summary, the additive element to the stack of the time complexity is O (log (n)), remove elements from the queue time complexity of O (log (n)), to traverse the entire sequence than O (n) this time complexity is smaller.


#include <iostream>
#include<vector>
#include<iterator>
using namespace std ;
#define MAX 65535
//最大堆实现
//保证子节点不大于其对应的父节点的值
//设置元素个数接口
//是否为空的接口
//获取父亲节点的接口

class Dui
{

private :

    vector<int>p ;
    int last ;

public :
    Dui()
    {
    }
    ~Dui(){}

public :

    void print()
    {
        int i ;
        while(1)
        {
            cin >> i ;
            if(i == -1)
            {
                break ;
            }
            add(i) ;
        }

        cout << "这是一个最大堆" << endl ;
        for(int i=0 ; i <= last; i++)
        {

            cout << p[i] <<endl ;
        
        }

        cout << "当前最大堆顶部元素是" << endl ;
        cout << getMax() << endl ;
        cout << "堆尾元素" << endl ;
        cout << p[last] <<endl ;
    }
    //往堆中添加元素
    void add(int e)
    {
        p.push_back(e) ;
        last = p.size() - 1 ;
        siftUp();
    }
    
    //交换父子节点信息
    void swap( int& t1, int& t2 )
    {   
        int s ;
        s = t1 ;
        t1 = t2 ;
        t2 = s ;
    }
    
    //获取堆的规模
    int get_size()
    {
        return last+1 ;
    }

    //获取其父亲节点的下表
    int getParent(int index)
    {
        return (index-1)/2 ;
    }

    //将添加的元素移动到正确的位置
    void siftUp()
    {
        //堆中的子节点不能大于其父结点的值
        int f = getParent(last) ;          
        int cur = last ;

        while(cur >0 && p[f] < p[cur])
        {
            swap(p[f], p[cur]) ;
            cur = getParent(cur);
            f = getParent(cur) ;
        }
    }
    
    //获取其左孩子的下标
    int get_right_child(int index)
    {
        return index*2+2 ;
    }

    //获取其右孩子的下标
    int get_left_child(int index)
    {
        return index*2+1 ;
    }

    //从堆顶开始比较父亲节点和字节点的大小
    //要是父亲节点比其子节点要小的话,交换两者的值
    void change(int& left, int& right, int& cur, int& swaps)
    {
          swap(p[swaps], p[cur]) ;
          cur = swaps ;
          left = get_left_child(swaps) ;  
          right = get_right_child(swaps) ;
    }

    //从堆顶调整使整个堆保持为完全二叉树
    void siftDown()
    {
        int cur = 0 ;
        int left = get_left_child(0) ;
        int right = get_right_child(0) ;

        while(left < last&&(p[cur] < p[left]||p[cur] < p[right]))
        {
            
            if(left == last && right >last )
            {
                  if(p[right] > p[cur])  
                  {
                      swap(p[right], p[cur]) ;
                      break ;
                  }
            } 
            //如果左右节点都比其父亲节点大,找最大的那个进行交换
            else if(p[cur] < p[left] && p[cur] < p[right])
            {
                if(p[left] < p[right])
                {
                    change(left, right, cur, right) ;
                }

                else
                {
                    change(left, right, cur, left) ;
                }
            }
            else
            {
                if(p[left] > p[cur])
                {
                    change(left, right, cur, left) ;
                }
                else
                {
                    change(left, right, cur, left) ;
                }
            }
        }
    }

    //从堆中取出最大元素
    int getMax()
    {
        //获取到最大元素
        int max_ = p[0] ;
        cout << max_ <<endl ;
        int ll = p[last] ;
        //将最后一个元素获取到
        p[0] = ll ;
        siftDown() ;
        remove_last() ;
        return max_ ;
    }

    //将最后一个元素删除掉
    void remove_last()
    {
        p.pop_back() ;
        last -- ;
    }
};
///test 例子
int main()
{
    Dui dd ;
    dd.print() ; 
    return 0;
}

Guess you like

Origin blog.csdn.net/qq_41681241/article/details/88740827