c++ - priority_queue使用和模拟实现


一、priority_queue接口使用

1、函数接口与作用

接口作用
priority_queue< T >构造一个空优先队列
priority_queue< T >(迭代区间)通过迭代区间构造一个优先队列
push(val)val入队
pop()出队
size()队列的元素个数
top()取出队头元素的引用
empty()判断栈是否为空

2、指定排序规则
在定义优先队列时指定,如果不指定就默认倒序(大堆)。
如何指定:

在这里插入图片描述

比较仿函数写法:

//比较仿函数
template <class T>
class cmp
{
public:
	//返回bool,两个参数
	bool operator()(T& x, T& y)
	{
		//比较........
		return x > y;
	}
};

3、使用

void priority_queue_test()
{
	//通过迭代器区间构造
	vector<int> v{ 1,2,5,3,8 };

	//默认大堆
	priority_queue<int> q(v.begin(),v.end());


	//判断是否为空
	while (!q.empty())
	{
		//取队头元素
		cout << q.top() << " ";
		//出队
		q.pop();
	}
	cout << endl;
}

在这里插入图片描述

二、 priority_queue模拟实现

1、 priority_queue是一个适配器,默认封装了vector容器,所以我们模拟时也使用vector容器。
在这里插入图片描述
2、priority_queue框架

//第一个是数据类型,第二个是容器类型(默认vector),第三个仿函数类的类型(默认大堆)
 template <class T,class Container = vector<T> , class Compare = less<T>>
 class priority_queue
 {
 public:
 void push(T x);
 //....
 private:
     Container c;
  }

3、比较仿函数类的实现
大堆:

template <class T>
class less
{
public:
    bool operator()(const T& a, const T& b)
    {
        return a < b;
    }
};

小堆:

template <class T>
class greater
{
public:
    bool operator()(const T& a, const T& b)
    {
        return a > b;
    }
};

4、插入、删除
(1)push
这里直接复用vector容器的push_back接口,但是我们需要将优先级最高的放到第一个位置,所以还需要使用一个堆的向上调整算法,该算法需要配合比较仿函数使用。

//向上调整算法
void Adjust_Up(size_t child)
{
    size_t father = (child - 1) / 2;
    T tmp = c[child];
    //仿函数类
    Compare cmp;

    while (child > 0)
    {
        //使用仿函数判断
        if(cmp(c[father], tmp))
        {
            c[child] = c[father];
            child = father;
            father = (child - 1) / 2;
        }
        else
            break;
    }

    c[child] = tmp;
}

 void push(const T& x)
 {
 //利用vector的接口
     c.push_back(x);
//使用向上调整算法
     Adjust_Up(size() - 1);
 }

(2)pop
我们需要将第一个位置的元素删掉,为了保证效率,需要将其与最后一个元素交换,再进行尾删(这样效率比直接删除第一个位置高),最后使用向下调整算法即可保持优先级最高的在第一个位置了。

//先下调整算法
 void Adjust_Down()
 {
     size_t father = 0;
     size_t child = father * 2 + 1;
     T tmp;
     //仿函数对象
     Compare cmp;
     if (size() > 0)
         tmp = c[0];
     else return;

     while (child < size())
     {
     //使用仿函数比较
         if (child + 1 < size() && cmp(c[child],c[child + 1]))
             child++;
     //使用仿函数比较
         if(cmp(tmp, c[child]))
         {
             c[father] = c[child];
             father = child;
             child = father * 2 + 1;
         }
         else
             break;
     }
      c[father] = tmp;
 }
 //删除
  void pop()
  {
  //先交换
      std::swap(c[0], c[size() - 1]);
  //再尾删
      c.pop_back();
  //最后向下调整
      Adjust_Down();
  }

5、其他接口
都是复用vector接口实现

//判断是否为空
 bool empty() const
 {
     return c.empty();
 }
//大小
 size_t size() const
 {
     return c.size();
 }
//取队头元素引用
 T& top() 
 {
     return c[0];
 }

6、构造函数

//默认构造
priority_queue()
 {};
//使用迭代器区间构造,直接复用push这个接口即可
 template <class InputIterator>
 priority_queue(InputIterator first, InputIterator last)
 {
     while (first != last)
     {
         push(*first);
         ++first;
     }
 }

三、模拟代码总览

namespace xu
{
   template <class T>
   class less
   {
   public:
       bool operator()(const T& a, const T& b)
       {
           return a < b;
       }
   };

   template <class T>
   class greater
   {
   public:
       bool operator()(const T& a, const T& b)
       {
           return a > b;
       }
   };


    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)
        {
            while (first != last)
            {
                push(*first);
                ++first;
            }
        }

        void Adjust_Up(size_t child)
        {
            size_t father = (child - 1) / 2;
            T tmp = c[child];
            Compare cmp;

            while (child > 0)
            {
                //if (c[father] < tmp)
                if(cmp(c[father], tmp))
                {
                    c[child] = c[father];
                    child = father;
                    father = (child - 1) / 2;
                }
                else
                    break;
            }

            c[child] = tmp;
        }


        void Adjust_Down()
        {
            size_t father = 0;
            size_t child = father * 2 + 1;
            T tmp;
            Compare cmp;
            if (size() > 0)
                tmp = c[0];
            else return;

            while (child < size())
            {
                //if (child + 1 < size() && c[child] < c[child + 1])
                if (child + 1 < size() && cmp(c[child],c[child + 1]))
                    child++;

                //if (tmp < c[child])
                if(cmp(tmp, c[child]))
                {
                    c[father] = c[child];
                    father = child;
                    child = father * 2 + 1;
                }
                else
                    break;
            }

             c[father] = tmp;
        }

        bool empty() const
        {
            return c.empty();
        }

        size_t size() const
        {
            return c.size();
        }

        T& top() 
        {
            return c[0];
        }

        void push(const T& x)
        {
            c.push_back(x);

            Adjust_Up(size() - 1);
        }

        void pop()
        {
            std::swap(c[0], c[size() - 1]);
            c.pop_back();

            Adjust_Down();
        }

    private:
        Container c;
    };

};

测试:

void test01()
{
	//默认构造
	xu::priority_queue<int> q;
	//插入
	q.push(1);
	q.push(3);
	q.push(2);
	q.push(4);
	q.push(4);
	q.push(5);
	q.push(6);

	//判断
	while (!q.empty())
	{
		//队头元素
		cout << q.top() <<" ";
		//出队
		q.pop();
	}
	cout << endl;
}

void test02()
{
	vector<int> v{ 1,2,5,3,8 };
	//迭代器区间构造
	xu::priority_queue<int, vector<int>, xu::greater<int>> q(v.begin(),v.end());

	while (!q.empty())
	{
		cout << q.top() << " ";
		q.pop();
	}
	cout << endl;
}

在这里插入图片描述

  • 6
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
在优先队列中,底层存储数据的容器默认是vector,因此优先队列的数组实现就是使用vector作为底层容器来存储数据。\[1\] 优先队列通过堆算法将vector中的元素构造成堆的结构,实现了优先级的排序。默认情况下,优先队列是大堆,即堆顶元素是最大的数据。\[1\] 优先队列的模板声明带有三个参数,分别是数据类型、保存数据的容器和元素比较方式。容器必须是用数组实现的容器,比如vector、deque,而STL默认使用的是vector作为容器。比较方式默认使用operator<来进行比较,所以如果不指定后面两个参数,优先队列就是大顶堆,队头元素最大。\[2\] #### 引用[.reference_title] - *1* *2* [C++优先级队列priority_queue详解及其模拟实现](https://blog.csdn.net/qq_61635026/article/details/125807805)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down1,239^v4^insert_chatgpt"}} ] [.reference_item] - *3* [priority_queue(优先级队列)的用法,模拟实现priority_queue(堆排序、仿函数)](https://blog.csdn.net/qq_46131499/article/details/120731928)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down1,239^v4^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值