【PAT甲级题解记录】1110 Complete Binary Tree(25 分)
前言
Problem:1110 Complete Binary Tree (25 分)
Tags:完全二叉树 二叉树的层序遍历 BFS DFS
Difficulty:剧情模式
想流点汗想流点血死而无憾Address:1110 Complete Binary Tree (25 分)
问题描述
给定一棵树,其中有结点 0 to N-1 ,判定是否为完全二叉树。
- 若是完全二叉树,则需要输出最后一个结点。
- 若不是,则需要输出这棵树的根结点。
PS:这里给出完全二叉树的定义
一棵深度为k的有n个结点的二叉树,对树中的结点按从上至下、从左到右的顺序进行编号,如果编号为i(1≤i≤n)的结点与满二叉树中编号为i的结点在二叉树中的位置相同,则这棵二叉树称为完全二叉树。
解题思路
-
检查二叉树是否为完全二叉树,其实就是考察二叉树的遍历。结合四种基本遍历方式(pre、in、post、level)各自的特点来选取适合的方法,但说到底就是搜索。
-
方法一:在层序遍历过程中,有两种情况可供判断是不是完全二叉树:
- 遇到“无左孩子,有右孩子”的情况,有这种情况可以直接认定为非完全二叉树。
- 遇到”无孩子“的情况,则接下来的节点都不能有孩子,否则是非完全二叉树。
-
方法二:可以看出方法一的判断有一点麻烦。由于完全二叉树他的编号与满二叉树一一对应,所以可以直接DFS搜索,然后看每一个结点位置是否都小于N就好了,因为一旦有结点位置不小于N,就与满二叉树无法对应了。(但是这种方法就得在搜索时动态维护当前的结点位置)
-
-
这道题在初始化树时,我们并不能直接知道根结点是哪个,需要作额外判断,即没有父结点的就是root。
参考代码
-
层序遍历动态判断
#include<bits/stdc++.h> using namespace std; int N; vector<pair<int, int>> tree; vector<int> have_parent; int root; void init() { cin >> N; tree.resize(N); have_parent.resize(N, 0); for (int i = 0; i < N; ++i) { string l, r; cin >> l >> r; if (l == "-") { tree[i].first = -1; } else { tree[i].first = stoi(l); have_parent[stoi(l)] = 1; } if (r == "-") { tree[i].second = -1; } else { tree[i].second = stoi(r); have_parent[stoi(r)] = 1; } } for (int i = 0; i < N; ++i) { if (have_parent[i] == 0) { root = i; return; } } } int main() { init(); queue<int> q; q.push(root); int last_node = -1; bool flag = false; while (!q.empty()) { int ft = q.front(); last_node = ft; // update last_node q.pop(); // check if (tree[ft].first == -1 && tree[ft].second != -1) { cout << "NO " << root << endl; return 0; } if (flag && (tree[ft].first != -1 || tree[ft].second != -1)) { cout << "NO " << root << endl; return 0; } // update flag if (tree[ft].first == -1 && tree[ft].second == -1) { flag = true; } // push queue if (tree[ft].first != -1) { q.push(tree[ft].first); } if (tree[ft].second != -1) { q.push(tree[ft].second); } } cout << "YES " << last_node << endl; return 0; }
-
DFS直接找最大位置
#include<bits/stdc++.h> using namespace std; int N; vector<pair<int, int>> tree; vector<int> have_parent; int root_node, last_node, max_pos; void init() { cin >> N; tree.resize(N); have_parent.resize(N, 0); for (int i = 0; i < N; ++i) { string l, r; cin >> l >> r; if (l == "-") { tree[i].first = -1; } else { tree[i].first = stoi(l); have_parent[stoi(l)] = 1; } if (r == "-") { tree[i].second = -1; } else { tree[i].second = stoi(r); have_parent[stoi(r)] = 1; } } for (int i = 0; i < N; ++i) { if (have_parent[i] == 0) { root_node = i; return; } } } /** * * @param root 当前结点编号 * @param pos 当前搜索位置 * @return DFS的最大搜索位置 */ void dfs(int root, int pos) { if (pos > max_pos) { max_pos = pos; last_node = root; } if (tree[root].first != -1) { dfs(tree[root].first, pos * 2 + 1); } if (tree[root].second != -1) { dfs(tree[root].second, pos * 2 + 2); } } int main() { init(); dfs(root_node, 0); if (max_pos < N) { cout << "YES " << last_node << endl; } else { cout << "NO " << root_node << endl; } return 0; }