C++初阶学习————STL(priority_queue使用及模拟实现)

优先级队列

  • priority_queue常用接口介绍
    • priority_queue模拟实现
    • 1.普通的构造函数
    • 2.push
    • 3.pop
    • 4.top
    • 5.empty
    • 6.size
    • 迭代器构造函数
    • 控制大/小的优先级(仿函数)

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

priority_queue常用接口介绍

函数声明 接口说明
priority_queue()/priority_queue(first,last) 构造一个空优先级队列/迭代器构造优先级队列
empty( ) 检测优先级队列是否为空,是返回true,否则返回false
top( ) 返回优先级队列中最大(最小元素),即堆顶元素
push(x) 在优先级队列中插入元素x
pop() 删除优先级队列中最大(最小)元素,即堆顶元素
#include 
using namespace std;

void test()
{
	priority_queue<int> pq;
	pq.push(4);
	pq.push(1);
	pq.push(7);
	pq.push(9);
	cout << pq.top() << endl;
}

C++初阶学习————STL(priority_queue使用及模拟实现)_第1张图片
优先级队列的底层逻辑就是堆排序,在类模板中会有一个默认的模板参数也叫仿函数——less,默认是大的优先级高,想要控制小的优先级需要给一个——“greater” ,代表小的优先级高
C++初阶学习————STL(priority_queue使用及模拟实现)_第2张图片

priority_queue模拟实现

1.普通的构造函数

template<class T,class Container = vector<T>>
class priority_queue
{
public:
	priority_queue()
	{}
private:
	Container  _con;
};

因为这里的成员函数类型是自定义类型,而自定义类型会去调用他自己的拷贝构造、析构、赋值重载等等,所以这里就不用写了

2.push

void adjust_up(size_t child)
{
	size_t parent = (child-1)/2;
	while(child)
	{
		if(_con[child] > _con[parent])
		{
			swap(_con[child],_con[parent]);
			child = parent;
			parent = (child-1)/2;
		}
		else
			break;
	}
}

void push(const T& val)
{
	_con.push_back(val);
	adjust_up(_con.size() - 1);
}

前面介绍过,优先级队列在默认情况下是个 “大堆”,而堆的push是向上调整,所以这里用的也是向上调整

3.pop

void adjust_down(size_t parent)
{
	size_t child = parent*2 + 1;
	while(child < _con.size())
	{
		if(child+1 < _con.size() && _con[child+1] > con[child])
			child++;
		if(_con[child] > _con[parent])
		{
			swap(_con[child],_con[parent])
			parent = child;
			child = parent*2 + 1;
		}
		else
			break;
	}
}

void pop()
{
	assert(!_con.empty());
	swap(_con[0],_con[_con.size() - 1]);
	_con.pop_back();
	adjust_down(0);
}

堆的删除,删除最值的元素,也就是堆顶的元素(下标0的位置),先交换头部与尾部的数据,在删除尾部,最后向下调整

4.top

const T& top()
{
	return _con.[0];
}

取最值,也就是堆顶的值

5.empty

bool empty()
{
	return _con.empty();
}

6.size

size_t size()
{
	return _con.size();
}

迭代器构造函数

template<class InputIterator>
priority_queue(InputIterator first,InputIterator last)
	:_con(first,last)  //vector是支持迭代器初始化的
{
	//还需要把数组建成堆
	for(int i = (_con.size() -1 -1)/2 ; i >= 0;i--)
	{
		adjust_down(i);
	}
}
或者不使用初始化列表,直接用自己的push
	while(first != last)
	{
		push(*first);
		++first;
	}

使用迭代器构造函数,需要把数组变为堆的结构,可以使用向下或者向下调整,向上调整就需要从第一个开始,每个数据都需要调整;向下调整则需要从最后一个叶子的父类节点开始直到0下标位置的元素,并每次都向下调整,因为向下调整的前提是左右两子树必须是堆(也可以复用上面的push函数,从0开始)

控制大/小的优先级(仿函数)

仿函数的定义和使用方法


struct Less
{
	bool operator()(int x,int y)
	{
		return x < y;
	}
};

struct Greater
{
	bool operator()(int x, int y)
	{
		return x > y;
	}
};

int main()
{
	Less min;
	Greater max;
	cout << min(3,6) << endl;
	cout << max(3,6) << endl;
	return 0;
}

C++初阶学习————STL(priority_queue使用及模拟实现)_第3张图片
Less、Greater称作仿函数类型,max、min就是函数对象
C++初阶学习————STL(priority_queue使用及模拟实现)_第4张图片
可以看出,仿函数重载的是括号表达式,可以让对象像函数名一样调用使用(也可以用函数指针,但是太麻烦,所以C++设计了这种)

那么在priority_queue中的该如何定义? 请看如下代码:

template<class T>
struct Less
{
	bool operator()(const T& x, const T& y)const
	{
		return x < y;
	}
};
template<class T>
struct Greater
{
	bool operator()(const T& x, const T& y)const
	{
		return x > y;
	}
};
Greater和Less都是类型,那么类型就可以放到模板中去使用,所以:
template<class T,class Container = vector<T>, class Compare = Less<T>>
class priority_queue
{
	......
	......
	void adjust_up(size_t child)
	{
		size_t parent = (child-1)/2;
		while(child)
		{
			Compare com;
			//if(_con[child] > _con[parent])
			if( com(_con[parent] , _con[child]) )
			{
				swap(_con[child],_con[parent]);
				child = parent;
				parent = (child-1)/2;
			}
			else
				break;
		}
	}
	......
	......
	......
	......
	void adjust_down(size_t parent)
	{
		size_t child = parent*2 + 1;
		while(child < _con.size())
		{
			Compare com;
			//if(child+1 < _con.size() && _con[child+1] > con[child])
			if(child+1 < _con.size() && com(_con[child] , con[child+1]) )
				child++;
			//if(_con[child] > _con[parent])
			if( com(_con[parent] , _con[child]) )
			{
				swap(_con[child],_con[parent])
				parent = child;
				child = parent*2 + 1;
			}
			else
				break;
		}
	}
	......
	......
};

priority_queue默认是Less(大的优先),想设置小的优先,参数传Greater就可以

整体代码:

template<class T>
struct Less
{
	bool operator()(const T& x, const T& y)const
	{
		return x < y;
	}
};
template<class T>
struct Greater
{
	bool operator()(const T& x, const T& y)const
	{
		return x > y;
	}
};

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)
		:_con(first,last)  
	{
		for(int i = (_con.size() -1 -1)/2 ; i >= 0;i--)
		{
			adjust_down(i);
		}
	}
	
	void push(const T& val)
	{
		_con.push_back(val);
		adjust_up(_con.size() - 1);
	}
	
	
	void pop()
	{
		assert(!_con.empty());
		swap(_con[0],_con[_con.size() - 1]);
		_con.pop_back();
		adjust_down(0);
	}

	const T& top()
	{
		return _con[0];
	}
	
	bool empty()
	{
		return _con.empty();
	}
	
	size_t size()
	{
		return _con.size();
	}
private:
	void adjust_down(size_t parent)
	{
		size_t child = parent*2 + 1;
		while(child < _con.size())
		{
			Compare com;
			//if(child+1 < _con.size() && _con[child+1] > con[child])
			if(child+1 < _con.size() && com(_con[child] , con[child+1]) )
				child++;
			//if(_con[child] > _con[parent])
			if( com(_con[parent] , _con[child]) )
			{
				swap(_con[child],_con[parent])
				parent = child;
				child = parent*2 + 1;
			}
			else
				break;
		}
	}

	void adjust_up(size_t child)
	{
		size_t parent = (child-1)/2;
		while(child)
		{
			Compare com;
			//if(_con[child] > _con[parent])
			if( com(_con[parent] , _con[child]) )
			{
				swap(_con[child],_con[parent]);
				child = parent;
				parent = (child-1)/2;
			}
			else
				break;
		}
	}	
private:
	Container  _con;
};

你可能感兴趣的:(c++,学习,开发语言)