优先级队列的常用函数的使用
#include<iostream>
#include<queue>
using namespace std;
int main()
{
priority_queue<int>st;
st.push(1);
st.push(7);
st.push(5);
st.push(2);
st.push(3);
st.push(9);
while (!st.empty())
{
cout << st.top() << " ";
st.pop();
}
}
优先级队列的实现
优先级队列本质上是一个堆,所以实现和堆差不多,不同的是作为优先级队列我们可以使用别的容器来当适配器,比如说我们用vector作为优先级队列的容器,也可以用dequeue(双端队列)来做优先级队列的容器,
本篇我们使用vector来作为优先级队列的容器
所以我们优先级队列的函数可以用vector的函数来封装
#pragma once
#include<iostream>
#include<vector>
#include<functional>
using namespace std;
namespace bit
{
template <class T>
class less
{
public:
bool operator()(const T& x, const T& y)
{
return x < y;
}
};
template <class T>
class greater
{
public:
bool operator()(const T& x, const T& y)
{
return x > y;
}
};
template <class T, class Container = vector<T>, class Compare = less<T> >
class priority_queue
{
public:
priority_queue()=default;
template <class InputIterator>
priority_queue(InputIterator first, InputIterator last)
{
while (first != last)
{
push(*first);
first++;
}
}
void adjust_up(int child)
{
int parent = (child - 1) / 2;
while (child > 0)
{
if (comp(c[child],c[parent]))
{
swap(c[child],c[parent]);
child = parent;
parent = (child - 1) / 2;
}
else
{
break;
}
}
}
void adjust_down(int parent)
{
int child = parent * 2 + 1;
while (child<c.size())
{
if (child + 1 < c.size() && comp(c[child + 1], c[child]))
{
child = child + 1;
}
if (comp(c[child],c[parent]))
{
swap(c[parent],c[child]);
parent = child;
child = parent * 2 + 1;
}
else
{
break;
}
}
}
bool empty() const
{
return c.empty();
}
size_t size() const
{
return c.size();
}
const T& top() const
{
return c[0];
}
void push(const T& x)
{
c.push_back(x);
adjust_up(c.size() - 1);
}
void pop()
{
swap(c[0], c[c.size() - 1]);
c.pop_back();
adjust_down(0);
}
private:
Container c;
Compare comp;
};
};
void test()
{
bit::priority_queue<int, vector<int>, less<int>>st;
st.push(4);
st.push(7);
st.push(3);
st.push(1);
st.push(5);
st.push(2);
while (!st.empty())
{
cout << st.top() << " ";
st.pop();
}
}
优先级队列对自定义类型的排序
class Date
{
public:
Date(int year = 1900, int month = 1, int day = 1)
: _year(year)
, _month(month)
, _day(day)
{}
bool operator<(const Date& d)const
{
return (_year < d._year) ||
(_year == d._year && _month < d._month) ||
(_year == d._year && _month == d._month && _day < d._day);
}
bool operator>(const Date& d)const
{
return (_year > d._year) ||
(_year == d._year && _month > d._month) ||
(_year == d._year && _month == d._month && _day > d._day);
}
friend ostream& operator<<(ostream& _cout, const Date& d)
{
_cout << d._year << "-" << d._month << "-" << d._day;
return _cout;
}
private:
int _year;
int _month;
int _day;
};
void test()
{
priority_queue<Date, vector<Date>, less<Date>>st;
Date d1(2024, 4, 9);
st.push(d1);
st.push({2024,4,11});
st.push(Date(2024, 4, 10));
while (!st.empty())
{
cout << st.top() << " ";
st.pop();
}
}
如果我们把地址放进优先级队列里面呢??
void test()
{
priority_queue<Date*, vector<Date*>, less<Date*>> st;
st.push(new Date(2018, 10, 29));
st.push(new Date(2018, 10, 30));
st.push(new Date(2018, 10, 28));
while (!st.empty())
{
cout << *(st.top()) << endl;
st.pop();
}
}
这里为什么排序是无序的呢??
因为它是按照地址的大小来排序的,但是每次new对象,他的地址大小是不确定的,所以排出来属无序的,我们可以实现一个仿函数来实现
class Dateless
{
public:
bool operator()(const Date* x, const Date* y)
{
return *x < *y;
}
};
class Dategreater
{
public:
bool operator()(const Date* x, const Date* y)
{
return *x > *y;
}
};
反向迭代器
首先迭代器是怎么将模版适配成所有类型的变量都可以使用??
反向迭代器的实现
#pragma once
using namespace std;
namespace zjw
{ template<class Iterator,class Ref,class Ptr>
struct Reverselterator
{
typedef Reverselterator<Iterator, Ref, Ptr>Self;
Iterator _it;
Reverselterator(Iterator it)
:_it(it)
{}
Ref operator*()
{
Iterator tmp = _it;
return *(--tmp);
}
Ptr operator->()
{
return & (operator*());
}
Self& operator++()
{
--_it;
return *this;
}
Self& operator--()
{
++_it;
return *this;
}
bool operator!=(const Self& s)
{
return _it != s._it;
}
};
}
根据反向迭代器的特性,我们知道正向迭代器的++就是反向迭代器的–,正向迭代器的–就是反向迭代器的++,实现下面两个函数
Self& operator++()
{
--_it;
return *this;
}
Self& operator--()
{
++_it;
return *this;
}
Ref operator*()
{
Iterator tmp = _it;
return *(--tmp);
}
这个为什么要先–呢?
同时,需要在vector类或者list类中添加反向迭代器记录起始位置和结束位置的函数
reverse_iterator rbegin()
{
//return reverse_iterator(end());
return iterator(end());
}
reverse_iterator rend()
{
// return reverse_iterator(begin());
return iterator(begin());
}
这样写比较好理解,用正向迭代器的begin()做反向迭代器的rend(),用正向迭代器的end()做反向迭代器的rbegin(),
vector迭代器的重命名
typedef T* iterator;
typedef const T* const_iterator;
typedef Reverselterator<iterator,T&,T*> reverse_iterator;
typedef Reverselterator<const_iterator,const T&,const T*> const_reverse_iterator;
list迭代器的重命名
typedef ListIterator<T, T&, T*> iterator;
typedef ListIterator<T, const T&,const T*> const_iterator;
typedef Reverselterator<iterator,T&,T*> reverse_iterator;
typedef Reverselterator<const_iterator,const T&,const T*> const_reverse_iterator;
不同的是vector迭代器使用的是原生指针,这样写反向迭代器的好处是既可以给list使用,也可以给vector使用
注意反向迭代器的类命名空间必须和vector或list的命名空间一样.
测试vector的反向迭代器
测试list的反向迭代器