文章目录
PAT1110完全二叉树
找到根节点,按照完全二叉树填到数组里面,判断最大的数组下标如果超过了 n n n表示有空隙,代表不是一棵完全二叉树
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 30;
int n;
int l[N], r[N];
bool has_father[N];
int lastid, maxk; // lastid 填到最后一个叶子里面的id
// maxk表示的是填这么多数最大空间
void dfs(int u, int k)
{
if(u == -1) return ;
if(k > maxk)
{
maxk = k;
lastid = u;
}
dfs(l[u], k * 2);
dfs(r[u], k * 2 + 1);
}
int main()
{
// memset(l, -1, sizeof l);
// memset(r, -1, sizeof r);
cin >> n;
for (int i = 0; i < n; i ++ )
{
string lc, rc;
cin >> lc >> rc;
if(lc != "-")
{
l[i] = stoi(lc);
has_father[l[i]] = true;
}
else l[i] = -1;
if(rc != "-")
{
r[i] = stoi(rc);
has_father[r[i]] = true;
}
else r[i] = -1;
}
int root = 0;
while (has_father[root]) root ++;
dfs(root, 1);
if(maxk == n) printf("YES %d\n", lastid);
else printf("NO %d\n", root);
return 0;
}
PAT1115二叉搜索树最后两层结点的数量
c n t cnt cnt数组记录一下每层结点的个数, i n s e r t insert insert函数 B S T BST BST树的插入
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 1010;
int n;
int l[N], r[N], w[N], idx;
int cnt[N], max_depth;
void insert(int &u, int x) // u随着遍历过程根节点的改变而改变
{
if(!u)
{
u = ++ idx;
w[u] = x;
}
else if(x <= w[u]) insert(l[u], x);
else insert(r[u], x);
}
void dfs(int u, int depth)
{
if(!u) return ;
max_depth = max(max_depth, depth);
cnt[depth] ++;
if(l[u]) dfs(l[u], depth + 1);
if(r[u]) dfs(r[u], depth + 1);
}
int main()
{
cin >> n;
int root = 0;
for (int i = 0; i < n; i ++ )
{
int x;
cin >> x;
insert(root, x);
}
dfs(root, 0);
int n1 = cnt[max_depth], n2 = cnt[max_depth - 1];
printf("%d + %d = %d\n", n1, n2, n1 + n2);
return 0;
}
PAT1127Z字形遍历
d e p t h depth depth记录一下每一层是奇数层还是偶数层, b f s bfs bfs遍历一遍就好
#include <iostream>
#include <cstring>
#include <algorithm>
#include <unordered_map>
using namespace std;
const int N = 40;
unordered_map<int, int> l, r, pos;
int inorder[N], postorder[N];
int n, q[N];
int build(int il, int ir, int pl, int pr)
{
int root = postorder[pr];
int k = pos[root];
if(il < k) l[root] = build(il, k - 1, pl, pl + k - 1 - il);
if(ir > k) r[root] = build(k + 1, ir, pl + k - 1 - il + 1, pr - 1);
return root;
}
void bfs(int root)
{
int hh = 0, tt = 0;
q[0] = root;
int depth = 0;
while (hh <= tt)
{
int head = hh, tail = tt;
while (hh <= tail)
{
int t = q[hh ++ ];
if(l[t]) q[ ++ tt] = l[t];
if(r[t]) q[ ++ tt] = r[t];
}
if(++ depth & 1) reverse(q + head, q + tail + 1);
}
}
int main()
{
cin >> n;
for (int i = 0; i < n; i ++ )
{
scanf("%d", &inorder[i]);
pos[inorder[i]] = i;
}
for (int i = 0; i < n; i ++ ) scanf("%d", &postorder[i]);
int root = build(0, n - 1, 0 , n - 1);
bfs(root);
cout << q[0];
for (int i = 1; i < n; i ++ ) printf(" %d", q[i]);
cout << endl;
return 0;
}
PAT1066AVL的根
平衡树的左旋和右旋两种方式
u
p
d
a
t
e
update
update记录跟的深度
void update(int u)
{
h[u] = max(h[l[u]], h[r[u]]) + 1;
}
右旋
void R(int& u)
{
int p = l[u];
l[u] = r[p], r[p] = u;
update(u), update(p);
u = p;
}
左旋
void L(int& u)
{
int p = r[u];
r[u] = l[p], l[p] = u;
update(u), update(p);
u = p;
}
求左右子树的高度差(多次计算的过程都可以写成函数)
int get_balance(int u)
{
return h[l[u]] - h[r[u]];
}
插入的过程,u要引用因为更改了左右孩子
void insert(int& u, int w)
{
if (!u) u = ++ idx, v[u] = w;
else if (w < v[u])
{
insert(l[u], w);
if (get_balance(u) == 2)
{
if (get_balance(l[u]) == 1) R(u);
else L(l[u]), R(u);
}
}
else
{
insert(r[u], w);
if (get_balance(u) == -2)
{
if (get_balance(r[u]) == -1) L(u);
else R(r[u]), L(u);
}
}
update(u);
}
PAT1123判断完全AVL树
两道题的综合:PAT1552 + PAT1064
AVL树的插入,判断完全二叉树,输出完全AVL树的层序遍历
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 30;
int l[N], r[N], h[N], v[N], idx; // 左儿子,右儿子,高度,权值,使用的结点编号
int q[N], n, pos[N]; // 队列,总个数,在完全AVL树中结点的下标
void update(int u)
{
h[u] = max(h[l[u]], h[r[u]]) + 1;
}
void R(int &u)
{
int p = l[u];
l[u] = r[p], r[p] = u;
update(u), update(p);
u = p;
}
void L(int &u)
{
int p = r[u];
r[u] = l[p], l[p] = u;
update(u), update(p);
u = p;
}
int get_balance(int u)
{
return h[l[u]] - h[r[u]];
}
void insert(int &u, int w) // 插入的过程中把根节点更新
{
if(!u) u = ++ idx, v[u] = w;
else if(w < v[u])
{
insert(l[u], w); // 每一次插入的那个结点高度都会更新
if(get_balance(u) == 2)
{
if(get_balance(l[u]) == 1) R(u);
else L(l[u]), R(u);
}
}
else
{
insert(r[u], w);
if(get_balance(u) == -2)
{
if(get_balance(r[u]) == -1) L(u);
else R(r[u]), L(u);
}
}
update(u);
}
bool bfs(int root)
{
int hh = 0, tt = 0;
q[0] = root;
pos[root] = 1;
bool flag = true;
while (hh <= tt)
{
int u = q[hh ++ ];
// printf("%d %d\n", u, pos[u]);
if(pos[u] > n)
{
flag = false;
}
if(l[u]) q[ ++ tt] = l[u], pos[l[u]] = pos[u] * 2;
if(r[u]) q[ ++ tt] = r[u], pos[r[u]] = pos[u] * 2 + 1;
}
return flag;
}
int main()
{
int root = 0;
cin >> n;
for (int i = 0; i < n; i ++)
{
int w;
cin >> w;
insert(root, w);
}
bool flag = bfs(root);
cout << v[q[0]];
for (int i = 1; i < n; i ++ ) printf(" %d", v[q[i]]);
cout << endl;
if(flag) puts("YES");
else puts("NO");
return 0;
}
PAT后序遍历
在这里插入代码片
PAT1066AVL树的根
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 30;
int l[N], r[N], h[N], v[N], idx; // 左儿子,右儿子,高度,权值,使用的结点编号
int q[N], n, pos[N]; // 队列,总个数,在完全AVL树中结点的下标
void update(int u)
{
h[u] = max(h[l[u]], h[r[u]]) + 1;
}
void R(int &u)
{
int p = l[u];
l[u] = r[p], r[p] = u;
update(u), update(p);
u = p;
}
void L(int &u)
{
int p = r[u];
r[u] = l[p], l[p] = u;
update(u), update(p);
u = p;
}
int get_balance(int u)
{
return h[l[u]] - h[r[u]];
}
void insert(int &u, int w) // 插入的过程中把根节点更新
{
if(!u) u = ++ idx, v[u] = w;
else if(w < v[u])
{
insert(l[u], w); // 每一次插入的那个结点高度都会更新
if(get_balance(u) == 2)
{
if(get_balance(l[u]) == 1) R(u);
else L(l[u]), R(u);
}
}
else
{
insert(r[u], w);
if(get_balance(u) == -2)
{
if(get_balance(r[u]) == -1) L(u);
else R(r[u]), L(u);
}
}
update(u);
}
int main()
{
int root = 0;
cin >> n;
for (int i = 0; i < n; i ++)
{
int w;
cin >> w;
insert(root, w);
}
cout << v[root] << endl;
return 0;
}
PAT1135判断红黑树
其实跟平衡树没什么关系
先用前序遍历和中序遍历建树,存的时候中序遍历是正的,前序遍历是负的,方便排序
开一个 a n s ans ans和 c n t cnt cnt记录答案是否正确和当前黑结点的个数
红黑树判断:
- 如果说前序遍历不存在 如果不是一棵树,一定不是红黑树
- 左右子树黑色结点数量不等,也不是红黑树
- 如果父节点是红色的,那么孩子必须是黑色的
#include <iostream>
#include <cstring>
#include <algorithm>
#include <unordered_map>
using namespace std;
const int N = 40;
bool ans;
int n, inorder[N], preorder[N];
unordered_map<int, int> pos;
int build(int il, int ir, int pl, int pr, int &cnt)
{
// 中序遍历是正的,为了方便排序,并且题目保证了各结点的绝对值不相等
int root = (preorder[pl]);
int k = pos[abs(root)];
if(k < il || k > ir)
{
ans = false;
return 0;
}
int left = 0, right = 0, lcnt = 0, rcnt = 0;
if(il < k) left = build(il, k - 1, pl + 1, pl + 1 + k - 1 - il, lcnt);
if(ir > k) right = build(k + 1, ir, pl + 1 + k - 1 - il + 1, pr, rcnt);
if(lcnt != rcnt) ans = false;
cnt = lcnt;
if(root < 0)
{
if(left < 0 || right < 0)
ans = false;
}
else cnt ++;
return root;
}
int main()
{
int T;
scanf("%d", &T);
while (T -- )
{
cin >> n;
pos.clear();
for (int i = 0; i < n; i ++ )
{
scanf("%d", &preorder[i]);
inorder[i] = abs(preorder[i]);
}
sort(inorder, inorder + n);
for (int i = 0; i < n; i ++ ) pos[inorder[i]] = i;
ans = true;
int cnt = 0;
int root = build(0, n - 1, 0, n - 1, cnt);
if(root < 0) ans = false;
if(ans) puts("Yes");
else puts("No");
}
return 0;
}
PAT1053等重路径
在这里插入代码片
PAT1094最大的一代
方法一:邻接矩阵+vector遍历
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
const int N = 110;
int n, m;
vector<int> ans[N];
bool g[N][N];
int main()
{
cin >> n >> m;
while (m -- )
{
int x, k;
cin >> x >> k;
while (k -- )
{
int son;
cin >> son;
g[x][son] = true;
}
}
int l = 1;
ans[l].push_back(1);
while (ans[l].size())
{
for (auto t : ans[l])
{
for (int i = 1; i <= n; i ++ )
if(g[t][i])
ans[l + 1].push_back(i);
}
l ++;
}
int k = 1, cnt = 0;
for (int i = 1; i < l; i ++ )
if(cnt < ans[i].size())
{
cnt = ans[i].size();
k = i;
}
printf("%d %d\n", cnt, k);
return 0;
}
邻接表的方式
在这里插入代码片