蓝桥杯国赛备赛复习——数据结构

一、链表

1.1 单链表
package 链表;

public class 单链表 {
	static int e[] = new int[11010]; // index号节点的value值(value)
	static int ne[] = new int[11010];// index号节点的下一个节点的index(nextNode)
	static int head=-1,idx=0;      // 头节点的index,当前可用的最小index
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		// 遍历单链表
		for(int i=head;i!=-1;i = ne[i]) {
			System.out.print(e[i]);
		}
	}
	//	插入——链头
	static void add_to_head(int x) {
		e[idx] = x; ne[idx] = head; head = idx; idx++;
	}
    //	插入——第k个节点之后
	static void add_afterK(int k,int x) {
		e[idx] = x; ne[idx] = ne[k]; ne[k] = idx; idx++;
	}
	//  删除——第k个节点之后节点
	static void remove(int k,int x) {
		ne[k] = ne[ne[k]];
	}
}

例题: B3631 单向链表 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

import java.util.*;
public class Main {
	static int e[] = new int[11011];
	static int en[] = new int[11011];
	static int head = 0,idx = 1;
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Scanner in = new Scanner(System.in);
		e[0] = 1; en[0] = -1;
		int q = in.nextInt();
		while(q--!=0) {
			int o = in.nextInt();
			if(o==1) {
				int x = in.nextInt();
				int y = in.nextInt();
				add(x,y);
			}else if(o==2) {
				int x = in.nextInt();
				int index = find_index(x);
				if(en[index]==-1) {
					System.out.print("0\n");
				}else {
					System.out.print(e[en[index]]+"\n");
				}
			}else {
				int x = in.nextInt();
				remove(x);
			}
		}
	}
	static void add(int x,int y) {
		x = find_index(x);
		e[idx] = y;
		en[idx] = en[x];
		en[x] = idx;
		idx++;
	}
	static void remove(int x) {
		x = find_index(x);
		en[x] = en[en[x]];
	}
	static int find_index(int x) {
		for(int i=head;i!=-1;i = en[i])
			if(e[i]==x)
				return i;
		return -1;
	}
}

这个代码会有三个数据超时,应该改成快读就行了。

1.12双向链表
package 链表;

public class 双链表 {
	static int e[] = new int[11010]; // index号节点的value值(value)
	static int l[] = new int[11010];// index号节点的左边节点的index
	static int r[] = new int[11010];// index号节点的右边节点的index
	static int idx = 2;
	public static void main(String[] args) {
		// TODO Auto-generated method stub

	}
	// 初始化
	static void init() {
		r[0] = 1; l[1] = 0;
	}
	// K的右边插入x
	static void add_afterK(int k,int x) {
		e[idx] = x;
		l[idx] = k;
		r[idx] = r[k];
		l[r[k]] = idx;
		r[k] = idx;
	}
	// K的左边插入x
	static void add_beforeK(int k,int x) {
		add_afterK(l[k],x);
	}
	//  删除——第k个节点
	static void remove(int k) {
		r[l[k]] = r[k];
		l[r[k]] = l[k];
	}
}

二、栈和队列

2.1 单调栈

问题:找到左边的并且比我小的第一个数

思想:通过构造单调性---求极值

时间复杂度:O(n)                               # 每个元素最多进栈/出栈一次

package 栈和队列;
import java.util.*;
public class 单调栈 {
	
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Scanner in = new Scanner(System.in);
		int st[] = new int[11010],tt=0;
		int n = in.nextInt();
		for(int i=0;i<n;i++) {
			int x = in.nextInt();
			// 栈不空并且栈顶元素都大于等于我 => 出栈
			while(tt>0 && st[tt]>=x)
				tt--;
			if(tt>0) System.out.print(st[tt]+" ");
			else System.out.print("-1 ");
			st[++tt] = x;
		}
	}
}
2.2 单调队列

问题:求滑动窗口(队列维护)的最值

package 栈和队列;

import java.util.Scanner;

public class 单调队列 {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Scanner in = new Scanner(System.in);
		int qu[] = new int[1100];
		int a[] = new int [1100];
		int hh=0, tt=-1;
		int n = in.nextInt();
		int k = in.nextInt();
		for(int i=0;i< n;i++) {
			a[i] = in.nextInt();
		}
		for(int i=0;i< n;i++) {
			// 判断队头是否已经滑出窗口
			if(hh<=tt && i-k+1 > qu[hh]) hh++;
			// 出队
			while(hh<=tt && a[qu[tt]]>= a[i]) tt--;
			// 队列里存储的是下标
			qu[++tt] = i;
			if(i >= k-1) 
				System.out.print(a[qu[hh]]+" ");
		}
		hh=0;tt=-1;
		for(int i=0;i< n;i++) {
			// 判断队头是否已经滑出窗口
			if(hh<=tt && i-k+1 > qu[hh]) hh++;
			// 出队
			while(hh<=tt && a[qu[tt]]<= a[i]) tt--;
			// 队列里存储的是下标
			qu[++tt] = i;
			if(i >= k-1) 
				System.out.print(a[qu[hh]]+" ");
		}
	}
}

三、KMP

四、Trie树

Trie树又称字典树、单词查找树。是一种能够高效存储和查找字符串集合的数据结构

son[x][26]---代表了x节点的26个孩子、

         -------son[1][0]=2表示1结点的一个值为a的子结点为结点2

         -------如果son[1][0] = 0,则意味着没有值为a子结点

cnt[x]--从根节点到x节点结尾的单词个数

参考博客:

AcWing 835. 如何理解单(双)链表,Trie树和堆中的idx? - AcWingicon-default.png?t=N7T8https://www.acwing.com/file_system/file/content/whole/index/content/139574/AcWing 835. Trie字符串统计 - AcWingicon-default.png?t=N7T8https://www.acwing.com/file_system/file/content/whole/index/content/585887/

package Trie树;
import java.util.*;
public class 模板 {
	static int son[][] = new int[11010][26]; // 每个节点的26个孩子结点(a~z)
	static int cnt[] = new int[11010];       // 以当前节点结尾的单词有多少个
	static int idx = 1;                        // 当前用到了哪个下标(0是根结点也是空节点)
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Scanner in = new Scanner(System.in);
		int n = in.nextInt();
		while(n--!=0) {
			String op = in.next();
			String str = in.next();
			if(op.equals("I")) insert(str);
			else System.out.print(query(str));
		}
	}
	static void insert(String str) {
		int p = 0;
		for(int i=0;i<str.length();i++) {
			int x = str.charAt(i) -'a';
			if(son[p][x]==0) son[p][x] = ++idx;
			p = son[p][x];
		}
		cnt[p]++;
	}
	static int query(String str) {
		int p = 0;
		for(int i=0;i<str.length();i++) {
			int x = str.charAt(i) -'a';
			if(son[p][x]==0) return 0;
			p = son[p][x];
		}
		return  cnt[p];
	}
}

五、并查集

---快速合并两个元素所在的集合

---两个元素是否在同一个集合中

package 并查集;
import java.util.*;
public class 模板 {
	static int p[] = new int[10010];
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Scanner in = new Scanner(System.in);
		// 初始化---每个结点的父结点是自己
		int n = in.nextInt();
		for(int i=1;i<=n;i++) p[i] = i;
		int m = in.nextInt();
		while(m--!=0) {
			String op = in.next();
			int x = in.nextInt();
			int y = in.nextInt();
			if(op=="M")
				p[find(x)] = find(y);
			else
				if(find(x)==find(y))
					System.out.print("yes");
				else
					System.out.print("yes");
		}
	}
	/**
	 * 返回x所在集合的编号(祖先结点),融合路径压缩进行优化
	 * @param x
	 */
	static int find(int x) {
		if(p[x]!=x) p[x] = find(p[x]);
		return p[x];
	}
}

六、堆

手写小根堆

---核心操作:如果元素变大---down(x);如果元素变小---up(x);

---核心方法:插入一个元素——hp[++size] = x;up(x);

                      输出集合中的最小值——hp[1];

                      删除最小值——hp[1] = hp[size];size--;down(1);

                      修改任意一个元素——hp[x] = k;down(x);up(x);

                      删除任意一个元素——hp[x] = hp[size];size--;down(x);up(x);

应用——堆排序

import java.util.Scanner;
public class 堆排序 {
	static int hp[] = new int[10010];
	static int size = 0;
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Scanner in = new Scanner(System.in);
		int n = in.nextInt();
		size = n;
		for(int i=1;i<=n;i++) hp[i] = in.nextInt();
		//建堆
		for(int i=n/2;i>=1;i--) down(i);
		//堆排序
		for(int i=1;i<=n;i++) {
			System.out.print(hp[1]+" ");
			//删除堆顶元素
			hp[1] = hp[size]; size--; down(1);
		}
	}
	// 向下调整
		static void down(int x) {
			int t = x;
			if(2*x<=size&&hp[2*x]<hp[t]) t = 2*x;
			if(2*x+1<=size&&hp[2*x+1]<hp[t]) t = 2*x+1;
			if(t!=x) {
				int s = hp[x];
				hp[x] = hp[t];
				hp[t] = s;
				down(t);
			}
		}
		// 向上调整
		static void up(int x) {
			while(x/2<=size&&hp[x/2]>hp[x]) {
				int s = hp[x];
				hp[x] = hp[x/2];
				hp[x/2] = s;
				x = x >> 1;
			}
		}
}

  • 8
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值