trie树
适用题目:数据是小范围的,给一段句子,询问一个单词有没有在这个句子里。
难点:如何建立trie树,如何在树中查询单词
思路:由于数据范围一般是小写英文字母或大写英文字母,假设每个结点全满,则一个结点最多有26个儿子(代码同情境)使用一个足够大二维数组,用一个移动指针从头开始进行插入操作,儿子存在的赋值为层数,将最后的结尾用辅助数组存储作为标记。通过判断这个结点的值是不是0,来看这个结点存不存在。
代码:
#include<iostream>
using namespace std;
const int N = 100;
char son[N][26];
int cnt[N];
//插入操作
void insert(char str[]) {
int p = 0;
int index=0;
for (int i = 0; str[i]; i++)
{
int u = str[i] - 'a';
son[p][u] = ++index;
p = son[p][u];
}
cnt[p]++;
}
//查找操作
int query(char str[]) {
int p=0;
for (int i = 0; str[i]; i++) {
int u = str[i] - 'a';
if (!son[p][u]) return 0;
p = son[p][u];
}
return cnt[p];
}
并查集
适用题目:合并两个集合,询问二个元素是不是属于同个集合
思路:只有根结点是p[x]=x(父亲节点等于本身),其他的结点,只要一直寻找父亲结点,直到p[x]=x就可以了,这是一个递归的过程,代码中包含了压缩路径,也就是最后每个点都指向第一个结点。合并两个集合其实就是让一个集合成为另一个集合的父亲结点就可以了。
代码:
#include<iostream>
#include<string.h>
using namespace std;
//并查集作用:1.合并两个集合2.查找一个元素是否属于这个集合
char p[100];
char find(char x) {
if (p[x] != x) p[x] = find(p[x]);
return p[x];
}
int main() {
p[0] = 0;
char a, b;
p[find(a)] = find(b);
}
堆(以小根堆为例)
适用题目:查找最小/大值,删除最小/大值
思路:以小根堆为例,其实只由两个操作完成,一个是小数上浮,一个是大数下沉。由于末尾插入一个数不知道是应该上浮ren还是下沉,就都来一遍。下沉是和自己的两个儿子结点比,别忘记判断儿子是否存在,上浮是和父亲结点比。每次下浮/上沉一层是一个递归的过程,可以设置一个t开始设为起始点下标,记录最小的那个下标,如果这t改变就交换两个数。
删除最小值就是删除根结点,然后把最后一个结点移到根节点,重新排序一遍
代码:
#include<iostream>
#include<string.h>
#include<algorithm>
using namespace std;
const int N = 1005;
int Heap[N];
int siz;
int n;
//小数上浮
void up(int u) {
while (u / 2 && Heap[u / 2] > Heap[u]) {
swap(Heap[u / 2], Heap[u]);
u /= 2;
}
}
// 大数下沉
void down(int u) {
int t = u;
if (u * 2 <= siz && Heap[u * 2] < Heap[t]) t = u * 2;
if (u * 2 + 1 <= siz && Heap[u * 2 + 1] < Heap[t]) t = u * 2 + 1;
if (u != t) {
swap(Heap[u], Heap[t]);
down(t);
}
}
int main() {
cin >> n;
//建立一个堆
for (int i = 1; i <= n; i++) scanf("%d", &Heap[i]);
siz = n;
for (int i = 2 / n; i >=1; i--) {
down(Heap[i]);
}
}