提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
第二周学习总结
单链表
构成:
数据域这用e[]表示,来存储当前节点的数据,指针域ne[]存放下一节点的首地址。最后一个节点的指针指向null。
相关操作:
链表初始化:
void init()
{
head = -1;
idx = 0;
}
添加头节点:
void add_head(int x)
{
e[idx] = x;
ne[idx] = head;
head = idx++;
}
在k后插入x:
void add(int k,int x)
{
e[idx] = x;
ne[idx] = ne[k];
ne[k] = idx++;
}
将k点后的节点删除:
void remove(int x)
{
ne[x] = ne[ne[x]];
}
删除头节点需要保证头节点存在
head = ne[head];
双链表:
相较于单链表多了一个指针域指向上一个节点。
这用l[ ]表示左节点,r[ ]表示右节点,idx表示当前用到哪个节点。
相关操作:
初始化:
r[0] = 1, l[1] = 0;
idx = 2;
在k后插入节点x:
void insert(int k,int x)
{
e[idx]=x;
l[idx] = k;
r[idx] = r[k];
l[r[k]] = idx;
r[k] = idx++;
}
删除k节点:
void remove(int k)
{
l[r[k]] = l[k];
r[l[k]] = r[k];
}
链表与数组的对比:
链表是一个圈,没有头和尾之分,可以更方便的插入和删除某个数。
栈:
栈的特点:
先进后出并且只能在栈顶进行插入和删除操作。
相关操作:
push x – 向栈顶插入一个数 xx;
pop – 从栈顶弹出一个数;
empty – 判断栈是否为空;
query – 查询栈顶元素。
#include<iostream>
using namespace std;
const int N = 1e6+10;
string t;
int m,a[N],tt;
int main()
{
cin>>m;
while(m--)
{int x;
cin>>t;
if(t=="push")
{
cin>>x;
a[++tt] = x;
}
else if(t=="pop")
{
tt--;
}
else if(t=="empty")
{
if(tt==0) cout<<"YES"<<endl;
else cout<<"NO"<<endl;
}
else {
cout<<a[tt]<<endl;
}
}
return 0;
}
单调栈:
特点:
单调栈:一种特殊的栈。在栈的「先进后出」规则基础上,要求「从 栈顶 到 栈底 的元素是单调递增(或者单调递减)」。
#include<iostream>
using namespace std;
const int N = 1e5+10;
int a[N],tt,n;
int main()
{
cin>>n;
for(int i=0;i<n;i++)
{
int x;
cin>>x;
while(tt!=0&&a[tt]>=x) tt--;
if(tt) cout<<a[tt]<<" ";
else cout<<-1<<" ";
a[++tt] = x;
}
return 0;
}
队列:
队列的特点:
先进先出
相关操作:
push x – 向队尾插入一个数 x;
pop – 从队头弹出一个数;
empty – 判断队列是否为空;
query – 查询队头元素。
#include<iostream>
using namespace std;
const int N = 1e6+10;
int m,a[N],hh,tt=-1;
string t;
int main()
{
cin>>m;
while(m--)
{
int x;
cin>>t;
if(t=="push")
{
cin>>x;
a[++tt] = x;
}
else if(t=="pop")
{
hh++;
}
else if(t=="empty")
{
if(hh<=tt) cout<<"NO"<<endl;
else cout<<"YES"<<endl;
}
else {
cout<<a[hh]<<endl;
}
}
return 0;
}
trie:
是一种树形结构,典型应用是用于统计,排序和保存大量的字符串(但不仅限于字符串,如01字典树)。主要思想是利用字符串的公共前缀来节约存储空间。很好地利用了串的公共前缀,节约了存储空间。
#include<iostream>
using namespace std;
const int N = 1e5+10;
int trie[N][26];
int cnt[N];
int id;
void insert(string s)
{
int p = 0;
for(int i = 0;i<s.size();i++)
{
int x =s[i];
if(trie[p][x]==0) trie[p][x]=++id;
p = trie[p][x];
}
cnt[p]++;
}
int find(string s)
{
int p = 0;
for(int i = 0;i<s.size();i++)
{
int x = s[i];
if(trie[p][x]==0) return 0;
p = trie[p][x];
}
return cnt[p];
}
int main()
{
int q;
cin>>q;
while(q--)
{
char t;
string s;
cin>>t;
if(t=='I')
{
cin>>s;
insert(s);
}
else if(t=='Q')
{
cin>>s;
cout<<find(s)<<endl;
}
}
return 0;
}
并查集:
作用:
将两个集合合并。
询问两个元素是否在一个集合当中
原理:
每一个集合用一棵树来表示,树根的编号就是整个集合的编号。每个节点存储它的父节点,p[x]表示x的父节点。
判断一个节点是不是树根?等价于if(p[x] == x)
x的集合编号?while(p[x] != x) x = p[x];
合并集合,p[x] = y;
#include<iostream>
using namespace std;
const int N=10e5+10;
int n,m;
int p[N];
int find(int x)
{
if(p[x]!=x) p[x]=find(p[x]);
return p[x];
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) p[i]=i;
while(m--)
{
char op;
int a,b;
cin>>op;
cin>>a>>b;
if(op=='M') p[find(a)]=find(b);
else if(find(a)==find(b)) puts("Yes");
else puts("No");
}
return 0;
}
堆:
如果有一个关键码的集合K = {k0,k1, k2,…,kn-1},把它的所有元素按完全二叉树的顺序存储方式存储在一个一维数组中,并满足:Ki <= K2i+1 且 Ki<=K2i+2 ,则称为小堆(或大堆)
将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小堆或小根堆
相关操作:
#include<iostream>
using namespace std;
const int N=10e5+10;
int n,m;
int p[N];
int find(int x)
{
if(p[x]!=x) p[x]=find(p[x]);
return p[x];
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) p[i]=i;
while(m--)
{
char op;
int a,b;
cin>>op;
cin>>a>>b;
if(op=='M') p[find(a)]=find(b);
else if(find(a)==find(b)) puts("Yes");
else puts("No");
}
return 0;
}
哈希表:
哈希表的最主要作用是将一个比较大的范围(如10^9)映射到一个比较小的空间(0 ~ N,其中N一般为10^5 - 10^6),通过一个哈希函数h(x)完成上述操作。
拉链法:
拉链法是把所有的同义词用单链表链接起来的方法。在这种方法中,哈希表的每个单元存储的不再是元素本身,而是相应同义词单链表的头指针
#include <cstring>
#include <iostream>
using namespace std;
const int N = 100003;
int h[N], e[N], ne[N], idx;
void insert(int x)
{
int k = (x % N + N) % N;
e[idx] = x;
ne[idx] = h[k];
h[k] = idx ++ ;
}
bool find(int x)
{
int k = (x % N + N) % N;
for (int i = h[k]; i != -1; i = ne[i])
if (e[i] == x)
return true;
return false;
}
int main()
{
int n;
scanf("%d", &n);
memset(h, -1, sizeof h);
while (n -- )
{
char op[2];
int x;
scanf("%s%d", op, &x);
if (*op == 'I') insert(x);
else
{
if (find(x)) puts("Yes");
else puts("No");
}
}
return 0;
}