数据结构(一)
单链表:邻接表
作用是存储图和树
我们用数组模拟链表即静态链表,因为速度快;而C++中的动态链表慢。且只有一个指向后的指针。
我们需要学会初始化,头插法,在某个下标后的数插入一个数,删除某个下标后的数…
例题 单链表
#include <iostream>
using namespace std;
const int N = 100010;
//e[i]节点i的数值 ne[i]指向下一个数的下标 heaad头结点下标 idx处理的数的位置
int e[N],ne[N],idx,head;
//初始化
void init()
{
head = -1;
idx = 0;
}
//头插法
void add_to_head(int x)
{
e[idx] = x;
ne[idx] = head;
head = idx;
idx ++;
}
//在下标为k的数后添加一个数
void add(int k,int x)
{
e[idx] = x;
ne[idx] = ne[k];
ne[k] = idx;
idx ++;
}
//删除下标为k的数的后一个数
void remove_(int k)
{
ne[k] = ne[ne[k]];
}
int main()
{
int m;
cin >> m;
init(); //先初始化
while(m--)
{
char op;
int k,x;
cin >> op;
if(op == 'H')
{
cin >> x;
add_to_head(x);
}
else if(op == 'D')
{
cin >> k;
if(!k)
{
head = ne[head];
}
else
{
remove_(k-1); //是k-1不是k啦}
}
}
else
{
cin >> k >> x;
add(k-1,x); //下标从0开始>>k-1
}
}
for(int i = head; i != -1; i=ne[i]) cout << e[i] << ' ';
cout << endl;
return 0;
}
双链表
优化某些问题
和单链表不同的是他有两个指针,一个指向前,一个指向后
题 双链表
对第k个节点的操作变成了k+1了
因为一开始有了一个头节点0和尾节点1,所以第k个插入的数就是下标就是k+1;
单链表中 (k - 1)是因为idx从0开始,双链表这里(k + 1)是因为idx从2开始的
#include <iostream>
using namespace std;
const int N = 100010;
int l[N],r[N],e[N],idx;
//初始化,让0为左端点,1为右端点
void init()
{
l[1] = 0;
r[0] = 1;
idx = 2;
}
//在下标为k的数的右边插入一个数 若是想在左边插入可以和自己将k变成l[k]
void add_r(int a,int x)
{
e[idx] = x;
r[idx] = r[a];
l[idx] = a;
l[r[a]] = idx;
r[a] = idx;
idx ++;
}
void remove_(int a)
{
l[r[a]] = l[a];
r[l[a]] = r[a];
}
int main()
{
int m;
cin >> m;
init();
while(m--)
{
string op;
int k,x;
cin >> op;
if(op == "IR")
{
cin >> k >> x;
add_r(k+1,x);
}
else if(op == "IL")
{
cin >> k >> x;
add_r(l[k+1],x);
}
else if(op == "D")
{
cin >> k;
remove_(k+1);
}
else if(op == "L")
{
cin >> x;
add_r(0,x);
}
else
{
cin >> x;
add_r(l[1],x);
}
}
for(int i = r[0];i!=1;i=r[i]) cout << e[i] << ' ';
cout << endl;
return 0;
}
单调栈
和单调队列一样应用不多,背过即可
题目 单调栈
栈里面只会保留比当前入栈元素小的数字
//yxc
#include <iostream>
using namespace std;
const int N = 100010;
int stk[N], tt;
int main()
{
int n;
cin >> n;
while (n -- )
{
int x;
scanf("%d", &x);
while (tt && stk[tt] >= x) tt -- ;//如果栈顶元素大于当前待入栈元素,则出栈
if (!tt) printf("-1 ");//如果栈空,则没有比该元素小的值。
else printf("%d ", stk[tt]);//栈顶元素就是左侧第一个比它小的元素。
stk[ ++ tt] = x;
}
return 0;
}
单调队列
# include <iostream>
using namespace std;
const int N = 1000010;
int a[N], q[N], hh, tt = -1;
int main()
{
int n, k;
cin >> n >> k;
for (int i = 0; i < n; ++ i)
{
scanf("%d", &a[i]);
if (i - k + 1 > q[hh]) ++ hh; // 若队首出窗口,hh加1
while (hh <= tt && a[i] <= a[q[tt]]) -- tt; // 若队尾不单调,tt减1
q[++ tt] = i; // 下标加到队尾
if (i + 1 >= k) printf("%d ", a[q[hh]]); // 输出结果
}
cout << endl;
hh = 0; tt = -1; // 重置!
for (int i = 0; i < n; ++ i)
{
if (i - k + 1 > q[hh]) ++ hh;
while (hh <= tt && a[i] >= a[q[tt]]) -- tt;
q[++ tt] = i;
if (i + 1 >= k) printf("%d ", a[q[hh]]);
}
return 0;
}
KMP QAQ
需要好好理解
KMP字符串
#include <iostream>
using namespace std;
const int N = 100010, M = 1000010;
int n, m;
int ne[N];
char s[M], p[N];
int main()
{
cin >> n >> p + 1 >> m >> s + 1;
for (int i = 2, j = 0; i <= n; i ++ )
{
while (j && p[i] != p[j + 1]) j = ne[j];
if (p[i] == p[j + 1]) j ++ ;
ne[i] = j;
}
for (int i = 1, j = 0; i <= m; i ++ )
{
while (j && s[i] != p[j + 1]) j = ne[j];
if (s[i] == p[j + 1]) j ++ ;
if (j == n)
{
printf("%d ", i - n);
j = ne[j];
}
}
return 0;
}