queue和priority_queue的实现
1、源代码
queue.h
#pragma once
#include<deque>
#include<vector>
#include<algorithm>
#include<assert.h>
namespace sdf
{
	template <class T, class container = std::deque<T>>
	class queue
	{
	public:
		void pop()
		{
			assert(!empty());
			_con.pop_back();
		}
		void push(const T& val)
		{
			_con.push_back(val);
		}
		T& front()
		{
			assert(!empty());
			return _con.front();
		}
		const T& front()const
		{
			assert(!empty());
			return _con.front();
		}
		T& back()
		{
			assert(!empty());
			return _con.back();
		}
		const T& back()const
		{
			assert(!empty());
			return _con.front();
		}
		bool empty()const//
		{
			return _con.empty();
		}
		size_t size()const//
		{
			return _con.size();
		}
	private:
		container _con;
	};
	template <class T>
	struct Greater
	{
		bool operator() (const T& val1, const T& val2){
			return val1 > val2;
		}
	};
	template <class T>
	struct Less
	{
		bool operator() (const T& val1, const T& val2) {
			return val1 < val2;
		}
	};
	template<class T, class Container = std::vector<T>, class Compare = Less<T>>//有了仿函数能够自己控制是大堆还是小堆,
	class priority_queue                                                        //函数指针同样能达到效果,但C++中的仿函数写起来更加简单
	{ 
	public:
		void UpJust(size_t child)
		{
			Compare compar;
			int parent = (child - 1) / 2;
			while (child > 0)
			{
				/*Less<int> funcLess;
				funcLess(1, 2);//funcLess.operator() (1,2)  仿函数:对象能够像函数一样进行调用,其实就是类中重载了()函数
				v0[1];//v0.operator[](1)
				Less<int>() (1, 2);//Less<int>().operator() (1,2)*/
				if (compar(_con[parent], _con[child])) {
					std::swap(_con[parent], _con[child]);//vector中有swap()
				}else{
					break;
				}
				child = parent;
				parent = (child - 1) / 2;
			}
		}
		void push(const T& val)
		{
			_con.push_back(val);
			UpJust(size()-1);
		}
		size_t size()
		{
			return _con.size();
		}
		void DownJust()
		{
			Compare compar;
			int parent = 0;
			int child = parent*2 + 1;
			if ((parent * 2 + 2) <= (size() - 1) && compar(_con[child], _con[child+1])) { //(parent*2+2)就是child+1
				child = parent * 2 + 2;                                                   //为了保险加一个_con[child] > _con[chold+1]的比较
			}
			while (child <= (size()-1))
			{
				if ( compar(_con[parent], _con[child]) ){
					std::swap(_con[parent], _con[child]);
				}else{
					break;
				}
				parent = child;
				child = parent * 2 + 1;
				if ((parent * 2 + 2) <= (size() - 1) && compar(_con[child], _con[child + 1])) {
					child = parent * 2 + 2;
				}
			}
		}
		void pop()
		{
			std::swap(_con[0], _con[size()-1]);
			_con.pop_back();
			if (size() > 0)
				DownJust();
		}
		bool empty()const
		{
			return _con.empty();
		}
		const T& top()const
		{
			return _con[0];
		}
		T& top()
		{
			return _con[0];
		}
	private:
		Container _con;
	};
};
Date.h
#pragma once
#include<iostream>
using namespace std;
class Date
{
	friend ostream& operator<<(ostream& out, const Date& d);
	friend istream& operator>>(istream& in, Date& d);
public:
	bool CheckDate(int year, int month, int day);
	Date(int year = 2024, int month = 9, int day = 8);
	Date(const Date& d);
	Date& operator=(const Date& d);
	bool operator>(const Date& d)const;
	bool operator==(const Date& d)const;
	bool operator>=(const Date& d)const;
	bool operator<(const Date& d)const;
	bool operator<=(const Date& d)const;
	bool operator!=(const Date& d)const;
	int GetMonthDay(int year, int month)
	{
		static int YearMonthDay[13] = { -1,31,28,31,30,31,30,31,31,30,31,30,31 };
		if (month == 2 && ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0))
			return 29;
		return YearMonthDay[month];
	}
	Date& operator+=(int day);
	Date operator+(int day)const;
	Date& operator-=(int day);
	Date operator-(int day)const;
	Date& operator++();
	Date operator++(int);
	Date& operator--();
	Date operator--(int);
	int operator-(const Date& d)const;
private:
	int _year;
	int _month;
	int _day;
};
ostream& operator<<(ostream& out, const Date& d);
istream& operator>>(istream& in, Date& d);
Date.cpp
#include"Date.h"
bool Date::CheckDate(int year, int month, int day)
{
	if (month <= 0 || month >= 13 || day <= 0 || day > GetMonthDay(year, month)) {
		cout << "请输入合法日期" << endl;
		return false;
	}
	return true;
}
ostream& operator<<(ostream& out, const Date& d)
{
	out << d._year << " " << d._month << " " << d._day;
	return out;
}
istream& operator>>(istream& in, Date& d)
{
	int year, month, day;
	do {
		in >> year >> month >> day;
	} while (!d.CheckDate(year, month, day));
	d._year = year;
	d._month = month;
	d._day = day;
	return in;
}
Date::Date(int year, int month, int day)
{
	_year = year;
	_month = month;
	_day = day;
}
Date::Date(const Date& d)
{
	_year = d._year;
	_month = d._month;
	_day = d._day;
}
Date& Date::operator=(const Date& d)
{
	if (this!=&d)
	{
		_year = d._year;
		_month = d._month;
		_day = d._day;
	}
	return *this;
}
bool Date::operator>(const Date& d)const
{
	if (_year > d._year)
	{
		return true;
	}
	else if (_year == d._year)
	{
		if (_month > d._month)
		{
			return true;
		}
		else if (_month == d._month && _day > d._day)
		{
			return true;
		}
	}
	return false;
}
bool Date::operator==(const Date& d)const
{
	if (_year == d._year && _month == d._month && _day == d._day)
	{
		return true;
	}
	return false;
}
bool Date::operator>=(const Date& d)const
{
	return *this > d || *this == d;
}
bool Date::operator<(const Date& d)const
{
	return !(*this >= d);
}
bool Date::operator<=(const Date& d)const
{
	return *this < d || *this == d;
}
bool Date::operator!=(const Date& d)const
{
	return !(*this == d);
}
Date& Date::operator+=(int day)
{
	_day += day;
	while (_day > GetMonthDay(_year, _month))
	{
		_day -= GetMonthDay(_year, _month);
		_month += 1;
		if (_month == 13)
			_year += 1;
	}
	return *this;
}
Date Date::operator+(int day)const
{
	Date tmp = *this;
	return tmp += day;
}
Date& Date::operator-=(int day)
{
	_day -= day;
	while (_day <= 0)
	{
		--_month;
		if (_month == 0)
		{
			_year -= 1;
			_month = 12;
		}
		_day += GetMonthDay(_year, _month);
	}
	return *this;
}
Date Date::operator-(int day)const
{
	Date tmp = *this;
	return tmp -= day;
}
Date& Date::operator++()
{
	return *this += 1;
}
Date Date::operator++(int)
{
	Date d = *this;
	*this += 1;
	return d;
}
Date& Date::operator--()
{
	return *this -= 1;
}
Date Date::operator--(int)
{
	Date d = *this;
	*this -= 1;
	return d;
}
int Date::operator-(const Date& d)const
{
	Date MaxDay = *this;
	Date MinDay = d;
	int flage = 1;
	if (*this < d)
	{
		MinDay = *this;
		MaxDay = d;
		flage = -1;
	}
	int difference = 0;
	while (MinDay != MaxDay)
	{
		++MinDay;
		++difference;
	}
	return flage * difference;
}
test.cpp
#include"queue.h"
#include"Date.h"
#include<iostream>
int main()
{
	sdf::queue<int> qe;
	qe.push(13);
	qe.push(12);
	std::cout << qe.front() << std::endl;
	std::cout << qe.back() << std::endl;
	qe.pop();
	std::cout << qe.size() << std::endl;
	sdf::priority_queue<int> qe2;
	qe2.push(3);
	qe2.push(8);
	qe2.push(2);
	while (!qe2.empty())
	{
		std::cout << qe2.top() << " ";
		qe2.pop();
	}
	std::cout << std::endl;
	sdf::priority_queue<Date> qe3;
	Date d0(2024, 4, 6);
	qe3.push(d0);
	qe3.push(Date(2024, 4, 7));
	qe3.push({ 2024,4,8 });
	while (!qe3.empty())
	{
		std::cout << qe3.top() << " ";
		qe3.pop();
	}
	std::cout << std::endl;
	return 0;
}
运行结果:

2、分析
2.1适配器模式
适配器模式是一种设计模式,该种模式是将一个类的接口转换成客户希望的另外一个接口。在STL中stack和queue并没有将其划分在容器的行列,而是将其称为容器适配器,这是因为栈和队列只是对其他容器的接口进行了包装。



2.2双端队列(deque)
双端队列支持迭代器、任意位置随机访问、任意位置的插入和删除


底层原理图(deque并不是真正连续的空间,而是由一段段连续的小空间拼接而成的,实际deque类似于一个动态的二维数组)

1、vector容器的优点和缺陷
- 支持任意位置的随机访问
 - 头部和中间位置的插入、删除效率低
 - 扩容有消耗
 
2、list容器的优点和缺陷
- 头部和中间位置的插入、删除效率高
 - 不支持任意位置的随机访问
 
3、deque容器的优点和缺陷
- 与vector比较,deque的优势是:头部插入和删除时,不需要搬移元素,效率特别高,而且在扩容时,也不 需要搬移大量的元素,因此其效率是必比vector高的。
 - 与list比较,其底层是连续空间,空间利用率比较高,不需要存储额外字段。
 - 不适合遍历(因为在遍历时,deque的迭代器要频繁的去检测其是否移动到 某段小空间的边界,导致效率低下,而序列式场景中,可能需要经常遍历,因此在实际中,需要线性结构时,大多数情况下优先考虑vector和list,deque的应用并不多,而目前能看到的一个应用就是,STL用其作 为stack和queue的底层数据结构)
 - 下标[]访问不够极致
 
4、为什么选择deque作为stack和queue的底层默认容器
- stack和queue不需要遍历,只需要在固定的一端或者两端进行操作。
 - 在stack中元素增长时,deque比vector的效率高(扩容时不需要搬移大量数据);queue中的元素增长
时,deque不仅效率高,而且内存使用率高。 - 结合了deque的优点,而且完美的避开了其缺陷。
 
2.3priority_queue(底层数据结构是堆)
插入(尾插,然后与父节点比较向上调整)
		void UpJust(size_t child)
		{
			Compare compar;
			int parent = (child - 1) / 2;
			while (child > 0)
			{
				if (compar(_con[parent], _con[child])) {
					std::swap(_con[parent], _con[child]);//vector中有swap()
				}else{
					break;
				}
				child = parent;
				parent = (child - 1) / 2;
			}
		}
		void push(const T& val)
		{
			_con.push_back(val);
			UpJust(size()-1);
		}
删除(如果头删之后,整体向前移动,时间复杂度为O(N)。如果头部的数据与尾部的数据交换,尾删,然后头部数据在向下调整,这样时间复杂度为O(logN))
void DownJust()
{
	Compare compar;
	int parent = 0;
	int child = parent*2 + 1;
	if ((parent * 2 + 2) <= (size() - 1) && compar(_con[child], _con[child+1])) { 
		child = parent * 2 + 2;                                                   
	}
	while (child <= (size()-1))
	{
		if ( compar(_con[parent], _con[child]) ){
			std::swap(_con[parent], _con[child]);
		}else{
			break;
		}
		parent = child;
		child = parent * 2 + 1;
		if ((parent * 2 + 2) <= (size() - 1) && compar(_con[child], _con[child + 1])) {
			child = parent * 2 + 2;
		}
	}
}
void pop()
{
	std::swap(_con[0], _con[size()-1]);
	_con.pop_back();
	if (size() > 0)
		DownJust();
}
2.4仿函数


std::sort(vr0.begin(), vr0.end(), PriceGreater())按照价格从高到低来排

std::sort(vr0.begin(), vr0.end(), PriceGreater())按照评价从低到高来排

                  
                  
                  
                  
                    
      
          
                
                
                
                
              
                
                
                
                
                
              
                
                
              
            
                  
					2647
					
被折叠的  条评论
		 为什么被折叠?
		 
		 
		
    
  
    
  
            


            