算法基础课(四)——单链表、双链表、栈、队列、单调栈(队列)和KMP

2020-02-16   


单链表、双链表(循环)

// 单链表、邻接表(n 个链表)
# include <iostream>
using namespace std;
const int N = 100010;
// head 头结点,e[i] 节点 i的值,ne[i] 表示节点 i 的next位置
// idx 当前可用的空间数组下标
int head, e[N], ne[N], idx;
void init(){// 初始化一个空链表
    head = -1; // -1 表示空指针
    idx = 0;
}
void add_to_head(int x){
    e[idx] = x, ne[idx] = head; // head 的下一个为空
    head = idx, idx ++;
}
void add(int k, int x){
    // 将 x 插入到下标是 k 的点后面(idx 从 0 开始)
    e[idx] = x, ne[idx] = ne[k], ne[k] = idx, idx ++;
}
void remove(int k){
    // 将下标是 k 的点后面的点删除
    ne[k] = ne[ne[k]];
}

// 双链表
// 下标0:head;下标1:tail;
int e[N], l[N], r[N], idx;
void init(){
    r[0] = 1, l[1] = 0; // 分别是左右端点指针 // 0是左端点,1是右端点
    idx = 2;
}
void add(int k, int x){
    // 将 x 插入到下标是 k 的点右面(idx 从 0 开始)
    e[idx] = x;
    l[idx] = k, r[idx] = r[k];// 插入
    l[r[k]] = idx, r[k] = idx;// 修改指针
    idx ++;
}// add(l[k], x); 表示将 x 插入到下标是 k 的点左面
void remove(int k){
    // 将下标是 k 的点删除(idx 从 0 开始)
    r[l[k]] = r[k];
    l[r[k]] = l[k];
}

栈与队列

#include <iostream>
using namespace std;
const int N = 100010;
// 栈顶
int stk[N], tt = 0;// tt 是栈顶下标
// 插入
stk[++tt] = x;
// 弹出
tt --;
// 判定栈是否为空(栈是从 0 开始存)
if(tt > 0) not empty;
else empty;
// 栈顶元素
stk[tt];

//******队列*****//
// 队尾插入,队头弹出
int q[N], hh, tt = -1;//队头,队尾
// 插入
q[++tt] = x;
// 弹出
hh ++;
//判断是否为空
if(hh <= tt) not empty;
else empty;
// 取队头队尾
q[hh], q[tt];

//******单调栈*****//
// 求序列中数左边(右边)离他最近且比他小(大)的数
int stk[N], tt;
int main(){
    int n; 
    // cin.tie(0);
    // ios::sync_with_stdio(false);读入优化
    cin >> n;  
    while(n--){
        int x; cin >> x;
    	while(tt && stk[tt] >= x) tt --;//tt > 0, 栈非空并且栈顶比当前输入大,直接可忽略栈顶
    	if(tt > 0) cout << stk[tt] <<" ";
    	else cout << -1 << " ";
    	stk[++tt] = x;
    }
}
//******单调队列*****//
// 求滑动窗口中的最小最大值
int a[N], q[N]; // 队列中存的是数组元素的下标
int main(){
    int n, k; cin>>n>>k;
    int hh = 0, tt = -1;
    for(int i=0; i<n; i++){
        cin >> a[i];
        if (hh <= tt && i - k + 1 > q[hh]) hh++;  // 保证队列中有 k 个元素,每次队首出,hh加1
        while (hh <= tt && a[q[tt]] >= a[i]) tt--;    // 若队尾不单调,tt减1,即表示尾元素已经不可能成为最小值,
        q[++ tt] = i;                                  // 下标加到队尾
        if (i >= k-1) cout<< a[q[hh]];       // 输出结果
    }

}

kmp

原串 $s$, 模式串 $p$​

$next[i] = j$​ 的含义是对于模式串:$p[1,j]=p[i-j+1,i]$​

# include<iostream>
using namespace std;
const int N = 10010, M = 100010;
char p[N], s[M]; // 下标均从 1 开始
int ne[N];
int main(){
    cin >> n >> p+1 >> m >> s+1;
    // 求 next 数组,next[1] = 0;
    for(int i=2, j=0; i <= n; i++){
        while(j > 0 && p[i] != p[j+1]) j = ne[j]; // ne[j] 一定小于 j
        if(p[i] == p[j+1]) j++;
        ne[i] = j;
    }
    // KMP 匹配过程
    for(int i=1, j=0; i <= m; i++){
        while(j > 0 && s[i] != p[j+1]) j = ne[j];
        if(s[i] == p[j+1]) j ++;
        if(j == n){
			// 匹配成功
            cout << i - m + 1 << " ";//输出匹配下标(下标是从 1 开始的)
            j = ne[j];
        }
    }
}

Q.E.D.


我是星,利剑开刃寒光锋芒的银星,绝不消隐