第二章.数据结构(一)

知识点 : 链表与邻接表 . 栈与队列 . kmp

链表

1.单链表

*****

//head[]表示链表头,e[]表示节点,ne[]表示next指针,idx表示当前点 
int head,e[N],ne[N],idx;

void init(){
	head = -1;
	idx = 0;
}

//在头节点插入一个数 
void insert(int a){
	e[idx] = a;ne[idx] = head;head = idx++;
}

//删除头节点 
void remove(){
	head = ne[head];
}

//将x插到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]]; 
}

//遍历: 
for(int i = head;i != -1;i = ne[i])cout << e[i] << " ";


2.双链表

//该点的值,该点的左点,该点的右点,当前的下标 
int e[N],l[N],r[N],idx;

void init(){
	//0表示左端点,1表示右端点
	r[0] = 1,l[1] = 0;
	idx = 2; 
} 

//在下标是k的点的右边,插入x
//在k的左边插入等于在l[k]的右边插入
void add(int k,int x){
	e[idx] = x;
	r[idx] = r[k];
	l[idx] = k;
	l[r[k]] = idx;
	r[k] = idx;
} 

//删除第k个点 
void remove(int k){
	r[l[k]] = r[k];
	l[r[k]] = l[k];
}

栈与队列

1.栈

//模拟栈,tt表示栈顶 
int stk[N],tt;

//栈顶插入
stk[++tt] = x;

//栈顶弹出
tt--;

//判断栈是否为空
if(tt > 0){
	
} 

2.队列

//在队尾插入元素,在队头弹出元素
int q[N],hh,tt = -1;

//队尾插入
q[++tt] = x;

//队头弹出
hh++;

//是否为空 
if(hh <= tt){
	
}

//取出队头
q[hh] 

3.单调栈问题

找到一个序列中每个数左边离他最近的比他大/小的数 .
优化

//找到每个数左边离他最近的,比他小的数 
int n,stk[N],tt;

int main(){
	cin >> n;
	for(int i=0;i<n;i++){
		int x;cin >> x;
		while(tt && stk[tt] >= x)tt--;
		if(tt)cout << skt[tt];
		else cout << "-1";
		stk[++tt] = x;
	}
	return 0;
} 

4.单调队列

滑动窗口,输出一个窗口中最大值和最小值
优化 : 如果求最小值,枚举到i时,如果队列的尾部比a[i]大,去掉尾部,再把a[i]放进去,头部维护最小值的下标

//单调队列

int a[N],q[N],n,k; //q记录对应下标 

int main(){
	scanf("%d%d",&n,&k);
	for(int i=0;i<n;i++){
		scanf("%d",&a[i]);
	}
	int hh = 0,tt = -1;
	for(int i=0;i<n;i++){  //最小值 
	    //如果队列中有元素 而且 队头划出了窗口 
		if(hh <= tt && i - k + 1 > q[hh])hh++;
		//把队列中比a[i]大的元素全弹出 
		while(hh <= tt && a[q[tt]] >= a[i])tt--;
		q[++tt] = i;
		
		if(i >= k - 1)printf("%d ",a[q[hh]]);
	}
	puts("");
	hh = 0,tt = -1;
	for(int i=0;i<n;i++){  //最大值 
	    //如果队列中有元素 而且 队头划出了窗口 
		if(hh <= tt && i - k + 1 > q[hh])hh++;
		//把队列中比a[i]小的元素全弹出 
		while(hh <= tt && a[q[tt]] <= a[i])tt--;
		q[++tt] = i;
		if(i >= k - 1)printf("%d ",a[q[hh]]);
	}
	
	
	return 0;
} 

kmp算法

求模板串p在S中所有出现的下标
例如 aba 在 ababa中的下标为 0 2.

预处理 : 找到模板串p中,某一段前缀和后缀相同,找最长的.
next[i] = j 表示 p[1 ~ j] == p[ i - j + 1 ~ i] , 以i为终点前面这一段最少的移动距离,直接调用
例如 : p = “abababab”,ne[1] = 0,ne[2] =0 ,ne[3] = 1, ne[6] = 4,表示在ababab中.1 ~4 等于3 ~ 6.

const int N = 10010,M = 100010;

int n,m;
char p[N],s[M];
int ne[N];

int main(){
	cin >> n >> p+1 >> m >> s+1;	
	//求ne[]
	ne[1] = 0;
	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;
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值