There is a kind of balanced binary search tree named red-black tree in the data structure. It has the following 5 properties:
- (1) Every node is either red or black.
- (2) The root is black.
- (3) Every leaf (NULL) is black.
- (4) If a node is red, then both its children are black.
- (5) For each node, all simple paths from the node to descendant leaves contain the same number of black nodes.
For example, the tree in Figure 1 is a red-black tree, while the ones in Figure 2 and 3 are not.
|
|
|
---|---|---|
Figure 1 | Figure 2 | Figure 3 |
For each given binary search tree, you are supposed to tell if it is a legal red-black tree.
Input Specification:
Each input file contains several test cases. The first line gives a positive integer K (≤30) which is the total number of cases. For each case, the first line gives a positive integer N (≤30), the total number of nodes in the binary tree. The second line gives the preorder traversal sequence of the tree. While all the keys in a tree are positive integers, we use negative signs to represent red nodes. All the numbers in a line are separated by a space. The sample input cases correspond to the trees shown in Figure 1, 2 and 3.
Output Specification:
For each test case, print in a line “Yes” if the given tree is a red-black tree, or “No” if not.
Sample Input:
3
9
7 -2 1 5 -4 -11 8 14 -15
9
11 -2 1 -7 5 -4 8 14 -15
8
10 -7 5 -6 8 15 -11 17
Sample Output:
Yes
No
No
Ω
给出二叉搜索树的先序遍历,判断它是否为红黑树。红黑树是一种高效的二叉搜索树,查找效率可以达到 ,主要具有以下特征:
根节点和所有叶子节点(这里将NULL看作叶节点,因此这个特征不具有什么约束)都是黑色
如果一个节点是红色,那么它的两个子节点必须均为黑色
每个节点到它所有子代叶子节点的路径上有相同个数的黑色节点
由于是二叉搜素树,因此通过和根节点之间的比较,可以将先序遍历划分为【根节点|左子树节点|右子树节点】,然后递归划分找出所有父子关系。然后通过DFS递归验证2、3特征,2比较简单只要检查红节点的子节点 即可;验证3的话就让dfs函数返回从当前节点到叶子节点路径中的黑节点个数,如果发现左右子节点返回个数不同或者其一返回-1,则说明不符合特征3直接返回-1。
🐎
#include <iostream>
#include <vector>
#include <map>
#include <algorithm>
using namespace std;
map<int, pair<int, int>> sons;
vector<int> pre;
void build(int s, int e)
{
int idx = upper_bound(pre.begin() + s, pre.begin() + e, abs(pre[s]),
[](const int &a, const int &b) { return abs(a) < abs(b); }) - pre.begin();
if (idx > s + 1)
{
sons[pre[s]].first = pre[s + 1];
build(s + 1, idx);
}
if (idx < e)
{
sons[pre[s]].second = pre[idx];
build(idx, e);
}
}
int check(int n)
{
if (n == 0) return 0;
// feature 2
if (n < 0 && (sons[n].first < 0 || sons[n].second < 0))
return -1;
int l, r;
// feature 3
if ((l = check(sons[n].first)) < 0) return -1;
else if ((r = check(sons[n].second)) < 0) return -1;
else if (l != r) return -1;
else return l + (n > 0);
}
int main()
{
int n, m;
cin >> n;
for (int i = 0; i < n; ++i)
{
cin >> m;
pre.resize(m);
for (int j = 0; j < m; ++j)
cin >> pre[j];
if (pre[0] < 0)
{
printf("No\n");
continue;
}
build(0, m);
printf(check(pre[0]) > 0 ? "Yes\n" : "No\n");
sons.clear(), pre.clear();
}
}
这里用了upper_bound
函数找到右子树的根节点位置,该函数返回第一个>给定值的元素迭代器,它的兄弟函数lower_bound
则返回第一个≥给定值的元素迭代器。