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,本次深入探讨一下他们的亲戚——优先级队列。
priority_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;
};
}
总结
以上是关于java 优先队列(priority queue)中,提取第二优先级的值并删除,但是不删除第一优先值的数,怎么实现?的主要内容,如果未能解决你的问题,请参考以下文章