【ACWING】模拟单链表、双链表、栈、队列、堆、哈希表
1 模拟链表
讲讲用数组模拟链表
开两个数组e[N],ne[N]
,前者存值,后者指向下一个节点,相同下标的对应同一个节点。
比如e[i],ne[i]
,分别表示节点i的值,以及节点i指向下一个节点,ne[i]
存的是下一个节点的index
初始化一个idx变量用于索引和存储,idx不断++,虽然元素是在数组中一个个存的,看起来是连续的,但是实际上链表会如下图所示
2 模拟栈
int stk[N]; int tt = -1; // top void push(int x){ stk[++tt] = x; } void pop(){ tt --; } int query() { // 求栈顶元素 return stk[tt]; } void empty() { if(tt==-1) { cout<<"YES"<<endl; }else{ cout<<"NO"<<endl; } }
3 模拟队列
int q[N]; int m,hh=0,tt=-1; void push(int x) { q[++tt] = x; } void pop() { hh ++; } bool empty() { if(tt<hh){ return true; } return false; } int query(){ return q[hh]; }
4 模拟堆
小根堆(小顶堆):每一个节点,小于等于左右儿子
堆的存储:用一维数组来存,一个节点为x,则左儿子为2x,右儿子为2x+1 ->完全二叉树序号定义 下标从1开始
// 核心操作 上筛和下筛 void down(int u) // 输入父节点下标,比较该父节点和左右儿子的大小,取最小的替换父节点 { int t = u; // 暂定最小的是输入的父节点 if(u * 2 <= hsize && h[u * 2] < h[t]) t = u * 2; // 如果有左儿子,且左儿子更小,则修改 if(u * 2 + 1<= hsize && h[u * 2 + 1] < h[t]) t = u * 2 + 1; // 如果有右儿子,且右儿子更小 // 如果发生了变化,则让儿子替换父节点,然后继续下筛 if(u != t){ mySwap(u,t); down(t); } } void up(int u) { // 如果存在父节点u/2 且 父节点大于儿子节点,交换。 while(u/2 && h[u/2] > h[u]){ mySwap(u/2,u); u /= 2; // 继续上筛 } }
5 模拟哈希表
-
哈希表的用途:将一个大的范围的数,映射到一个小范围
一般涉及 插入 和 查找 两个操作,查找接近O(1)
-
哈希函数:
(x % N + N) % N
(取模的时候N常用质数), 如果是负数的话也能映射到N这个区间内 -
冲突处理
- 拉链法
- 开放地址法(只需要一个数组,但是数组长度要开到题目范围的2/3倍)
5.1 拉链法
//哈希表h[N],每一项对应一个链表。这里的写法是多个链表共享一个一维数组e[N],ne[N] int h[N], e[N], ne[N], idx; // 插入x,找到位置k后,写入对应的链表中 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; }
5.2 开放地址法
// 用null表示一个还未存储的空位 const int N = 200003, null = 0x3f3f3f3f; int h[N]; // 如果找到x,返回下标,如果没有找到x,返回x应该存到的地方 int find(int x ) { int k = (x % N + N) % N ; while(h[k]!= null && h[k]!=x){ k++; if(k == N) k = 0; } return k; }
分类:
算法 / ACWING算法基础课
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步