1135 Is It A Red-Black Tree(30分)

题目翻译:

先给出了红黑树的定义,而后让你去判断一个给定的二叉搜索树的前序序列,这个二叉搜索树是否是红黑树。

题解思路:

首先明确什么是红黑树?

数据结构中有一类平衡的二叉搜索树,称为红黑树。
它具有以下 5 个属性:
1.节点是红色或黑色。
2.根节点是黑色。
3.所有叶子都是黑色。(叶子是 NULL节点)(注意这个不是我们寻常认为的叶子结点)
4.每个红色节点的两个子节点都是黑色。
5.从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点。

可以选择建树或者不建树。

建树的话:

将二叉搜索树的前序排序后就是中序,由中序和前序就可以建树了;或者直接由BST插入建树。

建树之后就用dfs的思想对树进行性质2、4、5的判定即可,对于性质5,只需要判断任意一条从根结点到每一个叶子结点的路径上黑色结点的数量相同就行了。

不建树的话:

只需要去记录几个变量再配合使用前序和中序序列便能遍历整棵树了。

代码:

建树:
#include<bits/stdc++.h>
using namespace std;
const int N = 31;
pair<int, bool> pre[N];
int K, t_max = 0, tag = 0;//t_max=0表示还未求得第一个从根结点到任意一个叶结点路上黑色结点的数量,tag=1表示已经判断为No

struct node {
	bool c;//0为红,1为黑
	int val = 0, l = -1, r = -1;
};
vector<node> v(N);
int ind = 0;//下标从0开始

void build(int& root, int h)//静态建树
{
	if (root == -1)
	{
		root = ind++;
		v[root].val = abs(h);
		v[root].c = (h >= 0) ? 1 : 0;
	}
	else if (abs(h) < v[root].val)
		build(v[root].l, h);
	else if (abs(h) > v[root].val)
		build(v[root].r, h);
}

void isRB(int cur, int num)
{
	if (tag == 1 || cur == -1) return;
	if (v[cur].c) num++;
	else
	{
		if ((!v[v[cur].l].c && v[cur].l != -1) || (!v[v[cur].r].c && v[cur].r != -1))//如果不满足红色结点的孩子结点为黑色
		{
			tag = 1;
			cout << "No" << endl;
			return;
		}
	}
	if ((v[cur].l == -1 || v[cur].r == -1) && !tag)//注意这里是或,而不是与
	{
		if (!t_max) {
			t_max = num;
		}
		else
		{
			if (num != t_max)//如果不满足从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点
			{
				tag = 1;
				cout << "No" << endl;
				return;
			}
		}
	}
	isRB(v[cur].l, num);
	isRB(v[cur].r, num);
}

int main()
{
	cin >> K;
	while (K--)
	{
		vector<node> v1(N);
		v = v1;
		t_max = 0, tag = 0;ind = 0;
		int t, root = -1;cin >> t;
		for (int i = 0;i < t;i++)
		{
			int p;cin >> p;
			build(root, p);
			if (p >= 0)
				pre[i] = make_pair(p, 1);
			else
				pre[i] = make_pair(-1 * p, 0);
		}
		if (v[root].c)
		{
			isRB(root, 0);
			if (!tag)
				cout << "Yes" << endl;
		}
		else
			cout << "No" << endl;
	}
}
不建树:
#include<bits/stdc++.h>
using namespace std;

int blackNum = -1, flag = -1;
unordered_map<int, int> indice;
struct node{
    int num;
    bool isRed;
    bool operator < (const node& p){
        return num < p.num;
    }
};

void getAns(vector<node>& pre, vector<node>& in, int pivot, int inl, int inr, bool isFatherRed, int black){
    if(inl > inr){//如果当前已到达叶子节点
        if(black + 1 != blackNum && blackNum != -1)//条件5:每条路径上的黑节点数相等
            flag = 1;
        else
            blackNum = black + 1;
        return;
    } 
    if(pre[pivot].isRed && isFatherRed){//条件4:红父节点的孩子必为黑,通过设置入口参数使得条件2的判断也在此进行
        flag = 1;
        return;
    }
    int pos = indice[pre[pivot].num];//下面就是相当于一个前序遍历,或者说是DFS
    getAns(pre, in, pivot + 1, inl, pos - 1, pre[pivot].isRed, pre[pivot].isRed ? black : black + 1);
    getAns(pre, in, pivot + pos - inl + 1, pos + 1, inr, pre[pivot].isRed, pre[pivot].isRed ? black : black + 1);
}

int main(){
    int k, n, u;
    cin >> k;
    while(k--){
        cin >> n;
        vector<node> pre(n);
        for (int i = 0; i < n;i++){
            cin >> u;
            pre[i].num = abs(u);
            pre[i].isRed = u < 0 ? true : false;
        }
        vector<node> in(pre);
        sort(in.begin(), in.end());
        for (int i = 0; i < n;i++)
            indice[in[i].num] = i;
        blackNum = flag = -1;//切记初始化啊,不然就错了。。。。。哭聊
        getAns(pre, in, 0, 0, n - 1, true, 0);
        if(flag == 1) cout << "No" << endl;
        else cout << "Yes" << endl;
    }
    return 0;
}

坑点:

对于测试点2和3的错误,请再仔细阅读红黑树的判断性质3和5。

(5) For each node, all simple paths from the node to descendant leaves contain the same number of black nodes.
这个性质一定要搜索到NULL 节点再来判断。否则就有可能出现你认为是红黑树,但它不是红黑树

如:

还有就是红黑树不允许插入相同的值,本题的样例也没考虑这一个,所以如果你测试点错了,不用考虑这个问题。 

  • 24
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 红黑树有下面几种操作:1. 插入:在红黑树中插入一个新的节点;2. 删除:从红黑树中删除一个节点;3. 查找:在红黑树中查找一个特定的节点;4. 遍历:遍历红黑树中的所有节点。使用C语言实现红黑树的操作代码可以参考下面的示例:1. 插入:/* Insert a node into the Red-Black Tree */ void rb_insert(struct rb_node *node, struct rb_root *root) { struct rb_node *parent = NULL; struct rb_node **link = &root->rb_node; /* Find the place to insert the new node */ while (*link) { parent = *link; if (node->key < parent->key) link = &(*link)->rb_left; else link = &(*link)->rb_right; } /* Insert the new node into the tree */ node->rb_parent = parent; node->rb_left = node->rb_right = NULL; *link = node; /* Fix any violations of the Red-Black Tree properties */ rb_insert_fixup(node, root); }2. 删除:/* Delete a node from the Red-Black Tree */ void rb_delete(struct rb_node *node, struct rb_root *root) { struct rb_node *child, *parent; /* If the node to be deleted has two children, replace it with its successor */ if (node->rb_left && node->rb_right) { struct rb_node *successor = rb_successor(node); node->key = successor->key; node = successor; } /* Get a pointer to the node's parent and child */ parent = node->rb_parent; child = node->rb_left ? node->rb_left : node->rb_right; /* Remove the node from the tree */ if (child) child->rb_parent = parent; if (parent) { if (node == parent->rb_left) parent->rb_left = child; else parent->rb_right = child; } else root->rb_node = child; /* Fix any violations of the Red-Black Tree properties */ rb_delete_fixup(node, root); }3. 查找:/* Find a node in the Red-Black Tree */ struct rb_node *rb_search(int key, struct rb_root *root) { struct rb_node *node = root->rb_node; while (node) { if (key < node->key) node = node->rb_left; else if (key > node->key) node = node->rb_right; else return node; } return NULL; }4. 遍历:/* Traverse the Red-Black Tree in-order */ void rb_inorder_traverse(struct rb_node *node, void (*func)(struct rb_node *)) { if (!node) return; rb_inorder_traverse(node->rb_left, func); func(node); rb_inorder_traverse(node->rb_right, func); } ### 回答2: 红黑树是一种自平衡的二叉搜索树,它具有以下特点:节点要么是红色,要么是黑色;根节点是黑色;每个叶子节点(NIL节点,空节点)是黑色;如果一个节点是红色,则它的两个子节点都是黑色;对于每个节点,从该节点到其所有后代叶子节点的简单路径上,均包含相同数量的黑色节点。 以下是使用C语言实现红黑树的所有操作的代码: ```c #include <stdio.h> #include <stdlib.h> enum Color {RED, BLACK}; typedef struct Node { int data; enum Color color; struct Node *left, *right, *parent; } Node; Node* createNode(int data) { Node* newNode = (Node*)malloc(sizeof(Node)); newNode->data = data; newNode->color = RED; newNode->left = newNode->right = newNode->parent = NULL; return newNode; } Node* bstInsert(Node* root, Node* newNode) { if (root == NULL) return newNode; if (newNode->data < root->data) { root->left = bstInsert(root->left, newNode); root->left->parent = root; } else if (newNode->data > root->data) { root->right = bstInsert(root->right, newNode); root->right->parent = root; } return root; } void swapColors(Node* a, Node* b) { enum Color temp; temp = a->color; a->color = b->color; b->color = temp; } void rotateLeft(Node** root, Node* x) { Node* y = x->right; x->right = y->left; if (y->left != NULL) y->left->parent = x; y->parent = x->parent; if (x->parent == NULL) *root = y; else if (x == x->parent->left) x->parent->left = y; else x->parent->right = y; y->left = x; x->parent = y; } void rotateRight(Node** root, Node* x) { Node* y = x->left; x->left = y->right; if (y->right != NULL) y->right->parent = x; y->parent = x->parent; if (x->parent == NULL) *root = y; else if (x == x->parent->right) x->parent->right = y; else x->parent->left = y; y->right = x; x->parent = y; } void fixViolation(Node** root, Node* newNode) { Node* parent = NULL; Node* grandParent = NULL; while ((newNode != *root) && (newNode->color != BLACK) && (newNode->parent->color == RED)) { parent = newNode->parent; grandParent = newNode->parent->parent; if (parent == grandParent->left) { Node* uncle = grandParent->right; if (uncle != NULL && uncle->color == RED) { grandParent->color = RED; parent->color = BLACK; uncle->color = BLACK; newNode = grandParent; } else { if (newNode == parent->right) { rotateLeft(root, parent); newNode = parent; parent = newNode->parent; } rotateRight(root, grandParent); swapColors(parent, grandParent); newNode = parent; } } else { Node* uncle = grandParent->left; if ((uncle != NULL) && (uncle->color == RED)) { grandParent->color = RED; parent->color = BLACK; uncle->color = BLACK; newNode = grandParent; } else { if (newNode == parent->left) { rotateRight(root, parent); newNode = parent; parent = newNode->parent; } rotateLeft(root, grandParent); swapColors(parent, grandParent); newNode = parent; } } } (*root)->color = BLACK; } Node* insertNode(Node* root, int data) { Node* newNode = createNode(data); root = bstInsert(root, newNode); fixViolation(&root, newNode); return root; } void inOrderTraversal(Node* root) { if (root == NULL) return; inOrderTraversal(root->left); printf("%d ", root->data); inOrderTraversal(root->right); } int main() { Node* root = NULL; root = insertNode(root, 10); root = insertNode(root, 20); root = insertNode(root, 30); root = insertNode(root, 40); root = insertNode(root, 50); root = insertNode(root, 60); printf("In-order traversal of the constructed Red-Black tree is: "); inOrderTraversal(root); return 0; } ``` 上述代码实现了红黑树的插入操作,并进行了适当的旋转和颜色交换以保证红黑树的特性。在主函数中,将节点插入到红黑树中,并进行中序遍历输出。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值