一、priority_queue 优先队列底层(堆)
priority_queue底层默认使用vector作为底层容器,默认是大根堆。
template <class T, class Container = vector<T>,
class Compare = less<typename Container::value_type>>
class priority_queue;
-
less<T>:大根堆,优先级高的元素(大值)在堆顶 -
greater<T>:小根堆,优先级高的元素(小值)在堆顶
易错区分:
priority_queue<int,vector<int>,greater<int>> pq; //类,类模板参数,传类型
sort(v.begin(),v.end(),greater<int>()); //对象,函数模板参数,传对象
priority_queue第二个模板参数传类型 ;sort第三个参数传仿函数对象。
堆下标公式(数组存储完全二叉树)
左孩子 = 父亲*2 +1
右孩子 = 父亲*2 +2
父亲 = (孩子‑1)/2
- 插入:向上调整 adjust_up 新元素放在数组末尾,不断和父节点比较,如果优先级更高就交换,直到不满足条件或者到达根节点。
void adjust_up(int child)
{
int parent = (child - 1)/2;
while(child > 0)
{
if(_con[child] > _con[parent])
{
swap(_con[child],_con[parent]);
child = parent;
parent = (child -1)/2;
}
else
{
break;
}
}
}
插入新元素只影响这条向上的路径,因此使用向上调整。
- 删除堆顶:向下调整 adjust_down 把末尾元素放到堆顶,再向下和两个孩子比较,和优先级更高的孩子交换,直到满足堆性质。
二、仿函数(函数对象)
仿函数本质:重载 operator() 的类 / 结构体,类实例可以像函数一样调用。
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 Compare>
void BubbleSort(T* a,int n,Compare com)
{
int exchange = 0;
for(int i=0;i<n;i++)
{
for(int j=0;j<n‑i‑1;j++)
{
if(com(a[j+1],a[j]))
{
swap(a[j],a[j+1]);
exchange =1;
}
}
if(exchange == 0) break;
}
}
调用:
int a[]={1,2,3,2,5,7,1};
BubbleSort(a,7,Less<int>()); //升序
BubbleSort(a,7,Greater<int>()); //降序
对比 C 语言
qsort:qsort 接收函数指针;C++ STL 大量接收仿函数对象。
三、STL 算法等价底层逻辑(迭代器 + 仿函数)
1. find
按值查找元素,底层等价逻辑:
template<class InputIterator,class T>
InputIterator find(InputIterator first,InputIterator last,const T& val)
{
while(first != last)
{
if(*first == val)
return first;
++first;
}
return last;
}
2. find_if 按条件查找(一元谓词)
传入一元仿函数,满足谓词条件就返回迭代器。
template<class InputIterator,class UnaryPredicate>
InputIterator find_if(InputIterator first,InputIterator last,UnaryPredicate pred)
{
while(first != last)
{
if(pred(*first))
return first;
++first;
}
return last;
}
示例:查找第一个偶数
struct OP1
{
int operator()(int x)
{
return x%2 ==0;
}
};
auto it = find_if(a,a+7,OP1());
3. transform 变换(一元操作)
遍历区间,对每个元素执行仿函数,输出到目标迭代器。
template<class InputIterator,class OutputIterator,class UnaryOperator>
OutputIterator transform(InputIterator first,InputIterator last,
OutputIterator result,UnaryOperator op)
{
while(first != last)
{
*result = op(*first);
++result;
++first;
}
return result;
}
示例:所有元素乘 2
struct OP2
{
int operator()(int x)
{
if(x%2 ==0)
return x*2;
else
return x;
}
};
vector<int> v={1,2,3,4,5,6,7};
transform(v.begin(),v.end(),v.begin(),OP2());
四、核心总结
-
priority_queue是容器适配器,底层堆,less大根堆,greater小根堆;插入向上调整,删除堆顶向下调整。 -
仿函数 = 重载
operator()的类,可以把比较逻辑封装成对象,作为参数传给算法,比 C 语言函数指针类型更安全。 -
STL 算法全部基于迭代器,
find做等值匹配;find_if接收一元谓词做条件匹配;transform做元素批量变换。 -
模板传参区分:类模板传类型,函数模板传对象实例。