目录
priority_queue的介绍及模拟实现::
priority_queue的介绍
priority_queue的定义方式
priority_queue各个接口的使用
堆的向上调整算法
堆的向下调整算法
仿函数
priority_queue的模拟实现
反向迭代器的底层原理
反向迭代器的模拟实现
优先级队列默认使用vector作为其底层存储数据的容器,在vector上又使用了堆的向上调整和向下调整算法将vector中的元素构造成堆的结构,因此priority_queue就是堆,所有需要用到堆的位置,都可以考虑使用priority_queue。
#include
int main()
{
priority_queue pq;
pq.push(3);
pq.push(1);
pq.push(2);
pq.push(5);
while (!pq.empty())
{
cout << pq.top() << " ";
pq.pop();
}
cout << endl;
return 0;
}
#include
#include
int main()
{
priority_queue,greater> pq;
pq.push(3);
pq.push(1);
pq.push(2);
pq.push(5);
while (!pq.empty())
{
cout << pq.top() << " ";
pq.pop();
}
cout << endl;
return 0;
}
方式一:使用vector作为底层容器,内部构造大堆结构
priority_queue,less> pq1;
方式二:使用vector作为底层容器,内部构造小堆结构
priority_queue,greater> pq2;
方式三:不指定底层容器,默认为大堆结构
priority_queue pq3;
成员函数 | 功能 |
push | 插入元素到队尾并调整为堆结构 |
pop | 弹出堆顶元素 |
top | 访问堆顶元素 |
size | 获取队列中有效元素个数 |
empty | 判断队列是否为空 |
swap | 交换两个队列的内容 |
//方法一:建大堆 再popK次
class Solution
{
public:
int findKthLargest(vector& nums, int k)
{
priority_queue pq(nums.begin(), nums.end());
while (--k)
{
pq.pop();
}
return pq.top();
}
};
//方法二:建K个数的小堆 和堆顶数据比较
class Solution
{
public:
int findKthLargest(vector& nums, int k)
{
priority_queue, greater> pq(nums.begin(), nums.begin() + k);
for (size_t i = k; i < nums.size(); ++i)
{
if (nums[i] > pq.top())
{
pq.pop();
pq.push(nums[i]);
}
}
return pq.top();
}
};
思想:
1.将目标结点与父结点进行比较
2.若目标结点的值比父节点的值大,则交换目标结点与其父节点的位置,并将原目标节点的父节点当作新的目标节点继续进行向上调整,若目标节点的值比其父节点的值小,则停止向上调整。
void AdjustUp(vector& v, size_t child)
{
size_t parent = (child - 1) / 2;
while (child > 0)
{
if (v[child] > v[parent])
{
swap(v[child], v[parent]);
child = parent;
parent = (child - 1) / 2;
}
else
{
break;
}
}
}
思想:
1.将目标节点与其较大的子节点进行比较
2.若目标节点的值比其较大的子节点的值小,则交换目标节点与其较大的子节点的位置,并将原目标节点的较大子节点当作新的目标节点继续进行向下调整,若目标节点的值比其较大子节点的值大,则停止向下调整。
void AdjustDown(vector& v, int n , size_t parent)
{
size_t child = 2 * parent + 1;
while (child < v.size())
{
if (child + 1 < n && v[child] < v[child + 1])
{
++child;
}
if (v[parent] < v[child])
{
std::swap(v[child], v[parent]);
parent = child;
child = parent * 2 + 1;
}
else
{
break;
}
}
}
仿函数的介绍:
namespace wjq
{
template
struct less
{
bool operator()(const T& x, const T& y)
{
return x < y;
}
};
template
struct greater
{
bool operator()(const T& x, const T& y)
{
return x > y;
}
};
}
int main()
{
wjq::less lessFunc;
lessFunc(1, 2);
return 0;
}
仿函数的使用场景:
bool cmp(int x, int y)
{
return y > x;
}
void BubbleSort(int* a, int n, bool(*pcom)(int, int))
{
for (int i = 0; i < n; i++)
{
int exchange = 0;
for (int j = 1; j < n - i; j++)
{
if (pcom(a[j - 1] , a[j]))
{
std::swap(a[j - 1], a[j]);
exchange = 1;
}
}
if (exchange == 0)
{
break;
}
}
}
int main()
{
int a[] = { 2,3,4,5,6,1,4,9 };
BubbleSort(a, 8, cmp);
for (size_t i = 0; i < 8; i++)
{
cout << a[i] << " ";
}
cout << endl;
return 0;
}
namespace wjq
{
template
struct less
{
bool operator()(const T& x, const T& y)
{
return x < y;
}
};
template
struct greater
{
bool operator()(const T& x, const T& y)
{
return x > y;
}
};
}
template
void BubbleSort(T* a, int n, Compare com)
{
for (int i = 0; i < n; i++)
{
int exchange = 0;
for (int j = 1; j < n - i; j++)
{
if (com(a[j], a[j - 1]))
{
std::swap(a[j - 1], a[j]);
exchange = 1;
}
}
if (exchange == 0)
{
break;
}
}
}
int main()
{
wjq::less lessFunc;
int a[] = { 2,3,4,5,6,1,4,9 };
BubbleSort(a, 8, lessFunc);
for (size_t i = 0; i < 8; i++)
{
cout << a[i] << " ";
}
cout << endl;
return 0;
}
仿函数的特殊使用场景:
如果在priority_queue中放自定义类型的数据,用户需要自己提供>和<的重载
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& out, const Date& d)
{
out << d._year << "-" << d._month << "-" << d._day;
return out;
}
private:
int _year;
int _month;
int _day;
};
void TestPriorityQueue()
{
// 大堆,需要用户在自定义类型中提供<的重载
priority_queue q1;
q1.push(Date(2023, 12, 1));
q1.push(Date(2023, 12, 2));
q1.push(Date(2023, 11, 30));
cout << q1.top() << endl;
// 如果要创建小堆,需要用户提供>的重载
priority_queue, greater> q2;
q2.push(Date(2023, 12, 1));
q2.push(Date(2023, 12, 2));
q2.push(Date(2023, 11, 30));
cout << q2.top() << endl;
}
int main()
{
TestPriorityQueue();
return 0;
}
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& out, const Date& d)
{
out << d._year << "-" << d._month << "-" << d._day;
return out;
}
private:
int _year;
int _month;
int _day;
};
void TestPriorityQueue()
{
//大堆
priority_queue q1;
q1.push(new Date(2023, 12, 1));
q1.push(new Date(2023, 12, 2));
q1.push(new Date(2023, 11, 30));
cout << q1.top() << endl;
//小堆
priority_queue q2;
priority_queue, greater> q2;
q2.push(new Date(2023, 12, 1));
q2.push(new Date(2023, 12, 2));
q2.push(new Date(2023, 11, 30));
cout << q2.top() << endl;
}
int main()
{
TestPriorityQueue();
return 0;
}
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& out, const Date& d)
{
out << d._year << "-" << d._month << "-" << d._day;
return out;
}
private:
int _year;
int _month;
int _day;
};
struct PDateLess
{
bool operator()(const Date* d1, const Date* d2)
{
return *d1 < *d2;
}
};
struct PDateGreater
{
bool operator()(const Date* d1, const Date* d2)
{
return *d1 > *d2;
}
};
void TestPriorityQueue()
{
//大堆
priority_queue, PDateLess> q1;
q1.push(new Date(2023, 12, 1));
q1.push(new Date(2023, 12, 2));
q1.push(new Date(2023, 11, 30));
cout << *q1.top() << endl;
//小堆
priority_queue, PDateGreater> q2;
q2.push(new Date(2023, 12, 1));
q2.push(new Date(2023, 12, 2));
q2.push(new Date(2023, 11, 30));
cout << *q2.top() << endl;
}
int main()
{
TestPriorityQueue();
return 0;
}
namespace wjq
{
template
struct less
{
bool operator()(const T& x, const T& y)
{
return x < y;
}
};
template
struct greater
{
bool operator()(const T& x, const T& y)
{
return x > y;
}
};
template , class Compare = less>
class priority_queue
{
private:
void AdjustUp(size_t child)
{
Compare com;//构造一个仿函数对象
size_t parent = (child - 1) / 2;
while (child > 0)
{
if (com(_con[parent], _con[child]))
{
swap(_con[child], _con[parent]);
child = parent;
parent = (child - 1) / 2;
}
else
{
break;
}
}
}
void AdjustDown(size_t parent)
{
Compare com;//构造一个仿函数对象
size_t child = 2 * parent + 1;
while (child < _con.size())
{
if (child + 1 < _con.size() && com(_con[child], _con[child + 1]))
{
++child;
}
if (com(_con[parent], _con[child]))
{
std::swap(_con[child], _con[parent]);
parent = child;
child = parent * 2 + 1;
}
else
{
break;
}
}
}
public:
//无参构造函数
priority_queue()
{
//默认构造函数即可
}
//迭代器区间构造
template
priority_queue(InputIterator first, InputIterator last)
:_con(first, last)
{
for (int i = (_con.size() - 1 - 1) / 2; i >= 0; --i)
{
AdjustDown(i);
}
}
void push(const T& x)
{
_con.push_back(x);
AdjustUp(_con.size() - 1);//从size-1开始调整
}
void pop()
{
std::swap(_con[0], _con[_con.size() - 1]);//交换首尾数据
_con.pop_back();//尾删
AdjustDown(0);
}
const T& top() const
{
return _con[0];
}
bool empty() const
{
return _con.empty();
}
size_t size()const
{
return _con.size();
}
private:
Container _con;
};
}
反向迭代器的本质就是对正向迭代器的封装,它同样是一个适配器。
STL源码中的反向迭代器的实现:反向迭代器用正向迭代器进行构造。
typedef ReverseIterator reverse_iterator;
typedef ReverseIterator const_reverse_iterator;
reverse_iterator rbegin()
{
return reverse_iterator(end());
}
reverse_iterator rend()
{
return reverse_iterator(begin());
}
STL源码中,其实正向迭代器和反向迭代器的位置是对称的。通过图示,rbegin()迭代器是最后一个数据的下一个位置,但是通过rbegin()访问的数据应该是6,这是通过运算符重载operator*()来解决。
template
Ref operator*()
{
Iterator tmp = _it;
return *(--tmp);
}
namespace wjq
{
template
class ReverseIterator
{
public:
RevserseIterator(Iterator it)//使用正向迭代器构造反向迭代器
:_it(it)
{}
Ref operator*()
{
Iterator tmp = _it;
return *(--tmp);
}
Ptr operator->()
{
return &(operator*());
}
typedef ReverseIterator Self
Self& operator++()
{
--_it;
return *this;
}
Self& operator--()
{
++_it;
return *this;
}
bool operator!=(const Self& s) const
{
return _it != s._it;
}
private:
Iterator _it;//底层是传入类型的迭代器
};
}