STL源码剖析 [容器](八)[priority_queue]

       priority_queue,首先它是一个queue,即只允许在低端加入元素,并从顶端取出元素,除此之外别无其他存取元素的途径(故priority_queue不提供遍历功能,也不提供迭代器);再次它具有priority,即queue中的元素具有一定的priority:其内的元素自动依照元素的权值排列,权值最高者(也就是数值最高),排在最前面。注:在queue并非是依照严格的权值递减的顺序排列,而是每次保持顶端(对头)元素为queue中权值最高的元素(其内部采用heap来实现(默认是max heap))。

下面是stl_queue.h中的priority_queue源码:

class priority_queue{
public:
 typedef typename Sequence::value_type value_type;
 typedef typename Sequence::size_type size_type;
 typedef typename Sequence::reference reference;
 typedef typename Sequence::const_reference const_reference;
protected:
 Sequencec;  // 底层容器
 Compare comp;    // 元素大小比较标准
public:
 priority_queue(): c() {}
 explicit priority_queue(constCompare& x) :  c(), comp(x) {}
 
// 以下用到的make_heap(), push_heap(),pop_heap()都是泛型算法
// 注意,任何一个构造函数都立刻于底层容器内产生一个implicitrepresentation heap。
#ifdef __STL_MEMBER_TEMPLATES
 template <class InputIterator>
 priority_queue(InputIteratorfirst, InputIterator last, const Compare& x)
   : c(first, last), comp(x) { make_heap(c.begin(),c.end(), comp); }
 template <class InputIterator>
 priority_queue(InputIteratorfirst, InputIterator last)
   : c(first, last) { make_heap(c.begin(),c.end(), comp); }
#else /* __STL_MEMBER_TEMPLATES */
 priority_queue(constvalue_type* first, const value_type* last,
                 const Compare& x) :c(first, last), comp(x) {
   make_heap(c.begin(), c.end(), comp);
 }
 priority_queue(constvalue_type* first, const value_type* last)
   : c(first, last) { make_heap(c.begin(),c.end(), comp); }
#endif /* __STL_MEMBER_TEMPLATES */
 
 bool empty()const { return c.empty(); }
 size_type size()const { return c.size(); }
 const_reference top()const { return c.front(); }
 void push(constvalue_type& x) {
   __STL_TRY {
     // push_heap 是泛型算法,先利用底层容器的push_back()将新元素
      // 推入末端,再重排heap
     c.push_back(x);
     push_heap(c.begin(), c.end(), comp);// push_heap 是泛型演算法
   }
   __STL_UNWIND(c.clear());
 }
 void pop(){
   __STL_TRY {
     // pop_heap 是泛型演算法,從 heap 內取出一個元素。它並不是真正將元素
      // 彈出,而是重排heap,然後再以底層容器的pop_back() 取得被彈出
      // 的元素。見C++ Primerp.1195。
     pop_heap(c.begin(), c.end(), comp);  
     c.pop_back();
   }
   __STL_UNWIND(c.clear());
 }
};
 
 

priority_queue的使用示例1:

#include <iostream>
#include <queue>
using namespace std;

class myComparison
{
    bool reverse;
public:
    myComparison(const bool& revParam = false)
    {
        reverse = revParam;
    }
    bool operator()(const int& lhs, const int& rhs) const
    {
        if(reverse)
            return (lhs > rhs);
        else
            return (lhs < rhs);
    }
};

int main()
{
    int myInts[] = {10, 60, 50 ,20};

    priority_queue<int> first;

    priority_queue<int> second(myInts, myInts+4);
    cout << "second size: " << second.size() << endl;
    cout << "second top: " << second.top() << endl;
    second.push(100);
    cout << "second top: " << second.top() << endl;

    priority_queue<int, vector<int>, greater<int> > third(myInts, myInts+4);
    cout << "third size: " << third.size() << endl;
    cout << "third top: " << third.top() << endl;
    third.push(100);
    cout << "third top: " << third.top() << endl;

    //using myComparison
    priority_queue<int, vector<int>, myComparison > fourth;

    typedef priority_queue<int, vector<int>, myComparison> myPq_type;
    myPq_type fifth(myComparison() );

    myPq_type sixth(myInts, myInts+4, myComparison(true) );
    cout << "sixth top: " << sixth.top() << endl;
    sixth.pop();
    cout << "sixth top: " << sixth.top() << endl;

    return 0;
}

priority_queue的使用范例2:

//优先级队列 priority_queue by MoreWindows( http://blog.csdn.net/MoreWindows )
// 支持 empty() size() top() push() pop() 与stack的操作函数全部一样
//by MoreWindows
#include <queue>
#include <list>
#include <cstdio>
using namespace std;
int main()
{
	//优先级队列默认是使用vector作容器。
	priority_queue<int> a;
	priority_queue<int, list<int>> b; //可以这样声明,但无法使用
	int i;
	//压入数据
	for (i = 0; i < 10; i++)
	{
		a.push(i * 2 - 5);
		//b.push(i); //编译错误
	}
	//优先级队列的大小
	printf("%d\n", a.size());
	//取优先级队列数据并将数据移出队列
	while (!a.empty())
	{
		printf("%d ", a.top());
		a.pop();
	}
	putchar('\n');
	return 0;
}


 

下面程序是针对结构体的,对数据的比较是通过对结构体重载operator()。

程序功能是模拟排队过程,每人有姓名和优先级,优先级相同则比较姓名,开始有5个人进入队列,然后队头2个人出队,再有3个人进入队列,最后所有人都依次出队,程序会输出离开队伍的顺序。

//by MoreWindows( http://blog.csdn.net/MoreWindows )
#include <queue>
#include <cstring>
#include <cstdio>
using namespace std;
//结构体
struct Node
{
	char szName[20];
	int  priority;
	Node(int nri, char *pszName)
	{
		strcpy(szName, pszName);
		priority = nri;
	}
};
//结构体的比较方法 改写operator()
struct NodeCmp
{
	bool operator()(const Node &na, const Node &nb)
	{
		if (na.priority != nb.priority)
			return na.priority <= nb.priority;
		else
			return strcmp(na.szName, nb.szName) > 0;
	}
};
void PrintfNode(Node &na)
{
	printf("%s %d\n", na.szName, na.priority);
}
int main()
{
	//优先级队列默认是使用vector作容器,底层数据结构为堆。
	priority_queue<Node, vector<Node>, NodeCmp> a;

	//有5个人进入队列
	a.push(Node(5, "小谭"));
	a.push(Node(3, "小刘"));
	a.push(Node(1, "小涛"));
	a.push(Node(5, "小王"));

	//队头的2个人出队
	PrintfNode(a.top());
	a.pop();
	PrintfNode(a.top());
	a.pop();
	printf("--------------------\n");

	//再进入3个人
	a.push(Node(2, "小白"));
	a.push(Node(2, "小强"));
	a.push(Node(3, "小新"));

	//所有人都依次出队
	while (!a.empty())
	{
		PrintfNode(a.top());
		a.pop();
	}

	return 0;
}


将上面结构体Node改成类:

类code:

class Node
{
public:
	Node(int nri, char *pszName)
	{
		strcpy(szName, pszName);
		priority = nri;
	}
	char* GetName();
	int   GetPriority();
	char* GetName() const;
	int   GetPriority() const;

private:
	char szName[20];
	int  priority;
};
char* Node::GetName()
{
	return szName;
}
int   Node::GetPriority()
{
	return priority;
}
char* Node::GetName() const
{
	return (char*)szName;
}
int   Node::GetPriority() const
{
	return priority;
}
inline bool operator < (const Node &na, const Node &nb)
{
	if (na.GetPriority() != nb.GetPriority())
		return na.GetPriority() <= nb.GetPriority();
	else
		return strcmp(na.GetName(), nb.GetName()) > 0;
}


程序code:

#include <queue>
#include <cstring>
#include <cstdio>
using namespace std; 
void PrintfNode(Node &na)
{
	printf("%s %d\n", na.GetName(), na.GetPriority());
}
int main()
{
	//优先级队列默认是使用vector作容器,底层数据结构为堆。
	priority_queue<Node> a;

	//有5个人进入队列
	a.push(Node(5, "小谭"));
	a.push(Node(3, "小刘"));
	a.push(Node(1, "小涛"));
	a.push(Node(5, "小王"));

	//队头的2个人出队
	PrintfNode(a.top());
	a.pop();
	PrintfNode(a.top());
	a.pop();
	printf("--------------------\n");

	//再进入3个人
	a.push(Node(2, "小白"));
	a.push(Node(2, "小强"));
	a.push(Node(3, "小新"));

	//所有人都依次出队
	while (!a.empty())
	{
		PrintfNode(a.top());
		a.pop();
	}

	return 0;
}


 

 



你可能感兴趣的:(STL源码剖析 [容器](八)[priority_queue])