java 优先队列(priority queue)中,提取第二优先级的值并删除,但是不删除第一优先值的数,怎么实现?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java 优先队列(priority queue)中,提取第二优先级的值并删除,但是不删除第一优先值的数,怎么实现?相关的知识,希望对你有一定的参考价值。

如题,我用top来提取第一优先的值,但是如果不满意想在保留第一优先值的情况下提取第二优先的值,应该怎么实现?
意思是说,在下次检索的时候还是可以从第一优先值开始,但是这个时候第二优先值已经被移除了

你要的是这样的效果么

public static void main(String[] args) 
  PriorityQueue<Integer> pq = new PriorityQueue<Integer>();
  pq.add(5);
  pq.add(2);
  pq.add(3);
  pq.add(4);
  System.out.println("取出了"+pq.poll()+",队列剩余"+Arrays.toString(pq.toArray()));
  
  /**
   * 假设3是我不满意的值,我要取到3后面的值
   */
  if(pq.peek()==3)
   System.out.println("3真不是我想要的,我可以接着往下处理么?ok,将3先保留吧");
   int a = pq.poll();//将当前的第一级优先的值暂存下来,等第二级优先的值取出后再将其加入
   pq.poll();
   pq.add(a);
   System.out.println("队列剩余"+Arrays.toString(pq.toArray()));
  
  
  System.out.println("取出了"+pq.poll()+",队列剩余"+Arrays.toString(pq.toArray())); 
  
 

打印效果:

取出了2,队列剩余[3, 4, 5]
3真不是我想要的,我可以接着往下处理么?ok,将3先保留吧
队列剩余[3, 5]
取出了3,队列剩余[5]

 

我觉得这个是优先队列,虽然poll时候会将优先级高的数据先取出,但是同样的,如果加进去是高优先级的数据 下次取的时候它依然还是高优先级的数据。

参考技术A 不明白你的意思,请问第一优先值跟第二优先值是什么关系,或者直接说他们是不是保存在同一个对象中的追问

我理解的优先队列是会按优先级的大小排列数值,所以如果输出最上面的则也是说输出优先级最大的即为第一优先级,而我想在保留最上面的值的情况下输出第二上面的并移除~

追答

秒杀腹黑菟已经回答得很好了,

 int a = pq.poll();//将当前的第一级优先的值暂存下来,等第二级优先的值取出后再将其加入
   pq.poll();
   pq.add(a);

这个他代码的精华

优先级队列priority_queue

优先级队列

之前我们在数据结构学过堆,在STL容器适配器里面学习了queue,本次深入探讨一下他们的亲戚——优先级队列。



前言

在这里插入图片描述

1.优先级队列是一种容器适配器,根据严格的弱排序标准(严格是说在判断的时候会用"<",而不是"<=",弱排序是因为,一旦"<“成立便认为存在”<“关系,返回ture,而忽略了”=“关系和”>"区别,把它们归结为false。),因此它的第一个元素总是他所包含的元素中最大的;

2.类似于堆,在堆中可以随时插入元素,并且只能检索最大堆元素(优先级队列中位于顶部的元素);

3.优先级队列被实现为容器适配器,容器适配器暨将特定容器类封装作为其底层容器类。queue提供了一组特定的成员函数来访问其元素,元素从特定容器的“尾部”弹出,其称为优先队列的顶部;

4.底层容器可以是任何标准容器类模板,也可以是其他特定设计的容器类,容器应该可以通过随机访问迭代器,并支持:empty()、size()、front()、push_back()、pop_back();

5.标准容器类vector和deque满足这些要求,默认情况下,如果没有为特定的priority_queue类实例化指定容器类,则使用vector;

6.需要支持随机访问迭代器,以便始终在内部保持堆结构,容器适配器通过在需要时自动调用算法函数make_heap、push_heap、pop_heap来自动完成此操作。


一、基本使用

优先级队列默认使用vector作为其底层存储数据的容器,在vector上又使用了堆算法将vector中的元素构造成堆的结构,因此priority_queue就是堆,所有需要用到堆的位置,都可以考虑使用priority_queue。注意:默认情况下priority_queue是大堆(升序排序)。

1.直接使用priority_queue

void main()
{
	vector<int> iv{ 5, 8, 3, 2, 1, 4, 9, 7 };
	priority_queue<int> pq;//直接使用priority_queue
	for (int i = 0; i < iv.size(); ++i)
	{
		pq.push(iv[i]);//入堆
	}
	cout << "pq size = " << pq.size() << endl;
	cout << "pq top = " << pq.top() << endl;//取堆顶
	pq.pop();
	cout << "pq top = " << pq.top() << endl;
	for (const auto&e : iv)
	{
		cout << e << " ";//vector里面的数据顺序没变
	}
	cout << endl;
}

在这里插入图片描述

2.利用全局函数构造堆

make_heap

void main()
{
	vector<int> iv{ 5, 8, 3, 2, 1, 4, 9, 7 };
	for (const auto&e : iv)
		cout << e << " ";
	cout << endl;
	make_heap(iv.begin(), iv.end());//构造大堆
	for (const auto&e : iv)
		cout << e << " ";
	cout << endl;
}

在这里插入图片描述
pop_heap
在此基础上:

	pop_heap(iv.begin(), iv.end());//删除堆顶元素
	for (const auto&e : iv)
		cout << e << " ";
	cout << endl;

在这里插入图片描述
我们可以借此操作进行堆排序:

	auto it = iv.end();//迭代器
	for (int i = 0; i < iv.size(); ++i)
	{
		pop_heap(iv.begin(), it);
		--it;
	}
	for (const auto&e : iv)
		cout << e << " ";
	cout << endl;

在这里插入图片描述
push_heap

void main()
{
	vector<int> iv{ 5, 8, 3, 2, 1, 4, 9, 7 };
	for (const auto&e : iv)
		cout << e << " ";
	cout << endl;
	make_heap(iv.begin(), iv.end());//构造大堆
	for (const auto&e : iv)
		cout << e << " ";
	cout << endl;
	iv.push_back(10);
	push_heap(iv.begin(), iv.end());//调整为大堆
	for (const auto&e : iv)
		cout << e << " ";
	cout << endl;
}

在这里插入图片描述
sort_heap:

	sort_heap(iv.begin(), iv.end());
	for (const auto&e : iv)
		cout << e << " ";
	cout << endl;

在这里插入图片描述

如果想要构建小堆(降序排序):
就需要使用仿函数greater(仿函数的本质就是个对象,重载了符号“()”)

#include <functional>
void main()
{
	vector<int> iv{ 5, 8, 3, 2, 1, 4, 9, 7 };
	for (const auto&e : iv)
		cout << e << " ";
	cout << endl;
	make_heap(iv.begin(), iv.end(),greater<int>());//构造小堆
	for (const auto&e : iv)
		cout << e << " ";
	cout << endl;
}

在这里插入图片描述
如果priority_queue的内容是自定义类型,则必须对比较符号“<,>”进行重载。

二、模拟实现

在这里插入图片描述

有3个模板参数,第一个是数据类型,第二个是要适配的容器,第三个相当于一个谓词(仿函数)。

第一种模拟方法(使用全局函数):

namespace LJL
{
	template<class T, class Cont = vector<T>, class Pred = less<T>>
	class priority_queue
	{
	public:
		//萃取
		typedef T value_type;
		typedef size_t size_type;
	public:
		explicit priority_queue(const Pred &pr = Pred()):sz(0)//构造
		{
		}
		priority_queue(const value_type *first, const value_type *last,
			const Pred &pr = Pred()) :c(first, last)
		{
			make_heap(c.begin(), c.end(),pr);//pr参数为仿函数,不传则默认为大堆
			sz = c.size();
		}
		void push(const value_type &x)
		{
			c.push_back(x);
			push_heap(c.begin(), c.end());//调整为大堆push_heap()需要引入queue头文件
			sz++;
		}
		void pop()
		{
			pop_heap(c.begin(), c.end());
			sz--;
		}
		/*void Show()const
		{
			for (size_t i = 0; i < c.size(); ++i)
			{
				cout << c[i] << " ";
			}
			cout << endl;
		}*/
	public:
		value_type &top()
		{return c.front();}
		size_type size()const
		{return sz;}
		bool empty()const
		{return sz == 0;}
	private:
		Cont c;
		Pred comp;
		size_t sz;
	};
}

第二种模拟方法:

namespace LJL
{
	template <class T, class Container = vector<T>,class Compare = less<T>>
	class priority_queue
	{
	public:
		priority_queue()
		{}
		priority_queue(const T *first, const T *last,
			const Compare &pr = Compare()) :c(first, last), comp(pr)
		{
			int curpos = c.size() / 2 - 1;//最后一个分支的位置
			//调整
			while (curpos >= 0)
			{
				_adjustdown(curpos);//向下调整
				curpos--;
			}
		}
		void Show()const
		{
			for (size_t i = 0; i < c.size(); ++i)
			{
				cout << c[i] << " ";
			}
			cout << endl;
		}
	public:
		bool empty()const
		{return c.size() == 0;}
		size_t size()const
		{return c.size();}
		T &top()
		{
			return c.front();
		}
		void push(const T &x)
		{
			c.push_back(x);
			_adjustup(c.size()-1);//从末尾的位置向根调整
		}
		void pop()
		{
			std::swap(*c.begin(),*(--c.end()));//首尾交换
			c.pop_back();//删除堆尾
			_adjustdown(0);
		}
	protected:
		void _adjustdown(int start)
		{
			int n = c.size();
			int i = start;
			int j = 2 * i + 1;//左子树
			while (j < n)
			{
				//less c[j]<c[j+1]
				if (j + 1 < n && comp(c[j] , c[j + 1]))//左右子树比较出的较大的那个
				{
					j++;
				}
				if (comp(c[i] , c[j]))//交换
				{
					T tmp = c[i];
					c[i] = c[j];
					c[j] = tmp;
					i = j;
					j = 2 * i + 1;
				}
				else
				{
					break;
				}
			}
		}
		void _adjustup(int start)
		{
			int j = start;
			int i = (j - 1)/2;
			while (i >= 0)
			{
				if (comp(c[i] , c[j]))
				{
					T tmp = c[i];
					c[i] = c[j];
					c[j] = tmp;

					j = i;
					i = (j - 1) / 2;
				}
				else
					break;
			}
		}
	private:
		Container c;
		Compare comp;
	};
}

总结

提示:这里对文章进行总结:例如:以上就是今天要讲的内容,本文仅仅简单介绍了pandas的使用,而pandas提供了大量能使我们快速便捷地处理数据的函数和方法。

以上是关于java 优先队列(priority queue)中,提取第二优先级的值并删除,但是不删除第一优先值的数,怎么实现?的主要内容,如果未能解决你的问题,请参考以下文章

STL之优先级队列priority_queue

优先队列 priority_queue

priority_queue 优先队列

STL学习笔记优先队列priority_queue

优先队列priority_queue的简单应用

优先队列(priority_queue)