基本数据结构
最基本的数据结构有栈、队列、链表、堆等等,除了链表之外,C++的STL都有相应的实现。
- 栈:stack<type>,
push(),pop(),top()等; - 队列:queue<type>,
push(),pop(),front()等; - 堆:priority_queue<type>(priority_queue<type,vector<type>,func>),
push(),pop(),top()等; - 集合:set<type>,
insert(),count(),size()等;
除此之外,STL中还有很多有用的数据结构,比如说:
- deque:双端队列,注意STL中的栈和队列其实都是基于deque实现的;
- vector:向量,类似数组,而且是可变长数组;
- map:内部实现的是红黑树,可以实现任意两种类型的一一映射;
- unordered_map:内部实现的是哈希表,其实和map功能差不多,但是这个查找更快,不过内部元素无序;
- bitset:一种支持各种位运算并且特别高效的结构;
- multiset:支持重复元素的集合;
- pair:二元对,比较方便;
并查集
一种树形结构,支持集合的合并和查询:
- 合并(unite):合并两个子集;
- 查询(find):查询某个元素属于哪个集合;
并查集的名字也由此而来(应该是 union-find set,不过C++的union是一个关键字,所以这里用了unite)。
并查集的代码如下:
const int maxn=1e5+5;
int n,far[maxn];
int find(int x) {
return x==far[x]?x:far[x]=find(far[x]);}
bool isSame(int x,int y) {
return find(x)==find(y);}
void unite(int x,int y) {
far[find(x)]=find(y);}
// 注意要初始化
// REP(i,1,n) far[i]=i;
上面的代码已经实现了路径压缩,大多数情况已经足够快了(平均单次复杂度是阿克曼函数级别的),如果要求比较严格,可以加上启发式合并,也就是合并的时候让集合小的合并到集合大的上面去。
带权并查集
普通的并查集维护的只是结点之间的连接关系,如果两个结点之间还有其他关系,就要用带权并查集。对于每个结点不仅仅要保存其父亲结点 far[i] ,还要保存其与父亲节点的关系 value[i] 。
然后同样讨论“并”和“查”两个操作:
- 查询(find):在路径压缩的时候,因为直接把当前结点连到了祖先,所以要先处理父亲节点,然后就已经知道了父亲结点和祖先的关系value,所以只用把自己的 value[i] 加上父结点和祖先的 value 就行了;
- 合并(unite):假设合并 x 和 y,x 和 y 的关系为 w,他们的祖先分别是 fx 和 fy,我们要令 far[fx] = fy,这里改变value的只有fx,如果画一个图出来就知道,应该令 value[fx]=value[y]+w-value[x] 。
这里面两个结点之间的关系都是单向的,属于偏序关系。
代码如下:
int find(int x)
{
if(x==far[x]) return x;
int t=far[x]; far[x]=find(far[x]); value[x]+=value[t];
return far[x];
}
void unite(int x,int y,int w)
{
int fx=find(x),fy=find(y);
if(fx!=fy)
{
far[fx]=fy;
value[fx]=value[y]+w-value[x];
}
}
// 注意要初始化
// REP(i,1,n) far[i]=i;
st表
st表用于处理RMQ问题,可以在O(nlogn)的时间内建表,在O(1)时间内查询。
其实就是一个倍增+dp的思想, s t [ i ] [ j ] st[i][j] st[i][j] 表示 a [ i ] a[i] a[i] 至 a [ i + 2 j − 1 ] a[i+2^j-1] a[i+2j−1] 这个区间的最值。
代码如下:
const int maxn=1e5+5;
int st[maxn][22],lg2[maxn],a[maxn];
void get_st(int n)
{
REP(i,2,maxn-1) lg2[i]=lg2[i-1]+(1<<(lg2[i-1]+1)==i);
REP(i,1,n) st[i][0]=a[i];
REP(j,1,lg2[n]) REP(i,1,n+1-(1<<j))
st[i][j]=max(st[i][j-1],st[i+(1<<(j-1))][j-1]);
}
int RMQ(int l,int r)
{
int k=lg2[r-l+1];
return max(st[l][k],st[r-(1<<k)+1][k]);
}
扩展到二维,其实也是一样的,用 s t [ r ] [ c ] [ i ] [ j ] st[r][c][i][j] st[r][c][i][j] 表示 a [ r ] [ c ] a[r][c] a[r][c] 至 a [ r + 2 i − 1 ] [ c + 2 j − 1 ] a[r+2^i-1][c+2^j-1] a[r+2i−

本文深入讲解了多种数据结构,包括栈、队列、链表、堆、并查集、st表、线段树、树状数组和单调队列。探讨了它们的基本原理、应用场景及优化技巧,如并查集的路径压缩、线段树的懒惰标记和永久标记等。
最低0.47元/天 解锁文章
8405

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



