C++中优先级队列

优先级队列的基本概念:

之前已经提到了队列(queue),队列是一种先进先出(First in First out,FIFO)的数据类型。每次元素的入队都只能添加到队列尾部,出队时从队列头部开始出。

优先级队列(priority_queue)其实,不满足先进先出的条件,更像是数据类型中的“堆”。优先级队列每次出队的元素是队列中优先级最高的那个元素,而不是队首的元素。这个优先级可以通过元素的大小等进行定义。 比如定义元素越大优先级越高,那么每次出队,都是将当前队列中最大的那个元素出队。个人感觉这就是所谓“优先级”的定义。

现在看优先级队列是不是就是“堆”了,如果最大的元素优先级最高,那么每次出队的就是当前队列中最大的元素,那么队列实际就相当于一个大根堆,每次将堆根节点元素弹出,重新维护大根堆,就可以实现一个优先级队列。


使用优先级队列

在这里插入图片描述
优先级队列是一个类模板,Compare是比较的方式,默认是大根堆(就是元素值越大,优先级越高);如果使用C++基本数据类型,可以直接使用自带的less和greater这两个仿函数(默认使用的是less,就是构造大根堆)。使用自定义的数据类型的时候,可以重写比较函数,也可以进行运算符重载(less重载小于“<”运算符,构造大根堆;greater重载大于“>”运算符,构造小根堆)。

priority_queue<int, vector<int>, less<int>> priQueMaxFirst
	 priQueMaxFirst.push(3);
	 priQueMaxFirst.push(2);
	 priQueMaxFirst.push(6);
	 priQueMaxFirst.push(4);
	 priQueMaxFirst.push(8);
	 priQueMaxFirst.push(9);
	 priQueMaxFirst.push(0);
	 while (!priQueMaxFirst.empty())
	 {
		 cout << priQueMaxFirst.top() << " ";
		 priQueMaxFirst.pop();
	 }
	 cout << endl;

在这里插入图片描述


模拟实现优先级队列

1.首先确定模拟的内容,构建好代码初期框架

namespace zxy
{
  template <class T, class Container = vector<T>, class Compare = less<T>>

  class priority_queue
  {
  public:
    priority_queue();
    
    template <class InputIterator>
    priority_queue(InputIterator first, InputIterator last);
    
    bool empty();
    
    size_t size();

    T& top();

    void push(const T& x);

    void pop();

  private:
    Container _con;
    Compare cmp;
  };
};

2.实现接口
push()

思路:首先我们需要往容器中插入数据,优先级队列既然是一个堆,那么就需要进行堆的调整,我们使用向上调整算法建堆

//向上调整算法
        void AdJustUp(size_t child)
        {
            size_t parent = (child - 1) / 2;
            while (child > 0)
            {
                if (cmp(_con[parent], _con[child]))
                {
                    swap(_con[parent], _con[child]);
                    child = parent;
                    parent = (child - 1) / 2;
                }
                else
                {
                    break;
                }
            }
        }

        void push(const T& x)
        {
            //尾插数据
            _con.push_back(x);
            //向上调整建堆
            AdJustUp(_con.size()-1);
        }

pop()

思路:这里我们要想清楚pop()和top()的操作区别,pop()是删除堆顶的元素,top()是返回堆顶数据。那么pop()就需要进行进行调整操作,因为我得到堆顶数据之后,堆顶的数据对我而言就没用了,那么就需要删除堆顶数据。堆里面的删除数据不是简单的头删,如果是头删,那么对于顺序容器来说就需要把后面的数据挪动到前面,这样时间消耗太高。所以,在堆里面的删除数据是将堆顶数据与堆尾数据进行交换,然后删除堆尾的数据(此时堆尾的数据就是原来堆顶的数据),从堆顶开始重新向下调整堆

void AdJustDown(int parent)
        {
            int child = parent * 2 + 1;
            //寻找大孩子
            while (child < _con.size())
            {
                if (child + 1 < _con.size() && cmp(_con[child],_con[child + 1])) child++;
                if (cmp(_con[parent], _con[child]))
                {
                    swap(_con[parent], _con[child]);
                    parent = child;
                    child = parent * 2 + 1;
                }
                else
                    break;
            }

        }

        void pop()
        {
            //heap.pop()删除的是堆顶的数据,底层实现对应的就是首尾交换-》尾删数据-》向下调整
            swap(_con[0], _con[_con.size() - 1]);
            _con.pop_back();
            AdJustDown(0);
        }

仿函数

仿函数实际上是一个类,类里面只是重载了()运算符,在对象调用的时候看起来像函数调用

template <class T>
struct Less
{
    //重载()运算符 -》仿函数
    bool operator()(const T& x, const T& y)  // <   大堆
    {
        return x < y;
    }
};

template <class T>
struct Geater
{
    //重载()运算符 -》仿函数
    bool operator()(const T& x, const T& y)  // >   小堆
    {
        return x > y;
    }
};


源代码->需要仔细品味

#pragma once
#include 
#include 
#include 
#include 
#include 
using namespace std;

template <class T>
struct Less
{
    //重载()运算符 -》仿函数
    bool operator()(const T& x, const T& y)  // <   大堆
    {
        return x < y;
    }
};

template <class T>
struct Geater
{
    //重载()运算符 -》仿函数
    bool operator()(const T& x, const T& y)  // >   小堆
    {
        return x > y;
    }
};

namespace zxy
{
    template <class T, class Container = vector<T>, class Compare = Less<T>>
    class priority_queue  //默认是 大堆 -》  Less  -》  < 
    {
    public:
        priority_queue()
        {
            ;
        }
        template <class InputIterator>
        priority_queue(InputIterator first, InputIterator last)
        {
            _con(first, last);
            for (int i = (_con.size() - 2) / 2; i >= 0; i--)
            {
                AdJustDown(i);
            }
        }
        bool empty() 
        {
            return _con.empty();
        }
        size_t size() 
        {
            return _con.size();
        }
        T& top()
        {
            return _con[0];
        }

        //向上调整算法
        void AdJustUp(size_t child)
        {
            size_t parent = (child - 1) / 2;
            while (child > 0)
            {
                if (cmp(_con[parent], _con[child]))
                {
                    swap(_con[parent], _con[child]);
                    child = parent;
                    parent = (child - 1) / 2;
                }
                else
                {
                    break;
                }
            }
        }

        void push(const T& x)
        {
            //尾插数据
            _con.push_back(x);
            //向上调整建堆
            AdJustUp(_con.size()-1);
        }

        void AdJustDown(int parent)
        {
            int child = parent * 2 + 1;
            //寻找大孩子
            while (child < _con.size())
            {
                if (child + 1 < _con.size() && cmp(_con[child],_con[child + 1])) child++;
                if (cmp(_con[parent], _con[child]))
                {
                    swap(_con[parent], _con[child]);
                    parent = child;
                    child = parent * 2 + 1;
                }
                else
                    break;
            }

        }

        void pop()
        {
            //heap.pop()删除的是堆顶的数据,底层实现对应的就是首尾交换-》尾删数据-》向下调整
            swap(_con[0], _con[_con.size() - 1]);
            _con.pop_back();
            AdJustDown(0);
        }
    private:
        Container _con;
        Compare cmp;
    };

};


#include "priority_queue .h"


int main()
{
	//zxy::priority_queue, Geater> pq;
	zxy::priority_queue<int> pq;

	 pq.push(3);
	 pq.push(2);
	 pq.push(6);
	 pq.push(4);
	 pq.push(8);
	 pq.push(9);
	 pq.push(0);
	 while (!pq.empty())
	 {
		 cout << pq.top() << " ";
		 pq.pop();
	 }
	 cout << endl;
	return 0;
}

你可能感兴趣的:(C++,c++)