forked from xuos/xiuos
2023_open_source_contest_warmup_1st_issue2 from 复旦大学_若客战队_李明辉
it is OK
This commit is contained in:
commit
a9140851c2
|
@ -240,5 +240,9 @@ menu "test app"
|
|||
bool "Config test soft timer"
|
||||
default n
|
||||
|
||||
menuconfig USER_TEST_RBTREE
|
||||
bool "Config test red black tree"
|
||||
default n
|
||||
|
||||
endif
|
||||
endmenu
|
||||
|
|
|
@ -101,5 +101,9 @@ ifeq ($(CONFIG_ADD_XIZI_FEATURES),y)
|
|||
SRC_FILES += test_timer.c
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_USER_TEST_RBTREE),y)
|
||||
SRC_FILES += test_rbtree/test_rbtree.c
|
||||
endif
|
||||
|
||||
include $(KERNEL_ROOT)/compiler.mk
|
||||
endif
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
# 基于cortex-m4-emulator实现红黑树并测试验证
|
||||
|
||||
## 1. 简介
|
||||
红黑树是一种自平衡的二叉查找树,具有良好的插入、删除和查找性能,本次提交结果为红黑树数据结构的简单实现。test_rbtree.h中定义了红黑树的数据结构和声明插入、删除、查找相关操作函数;test_rbtree.c中为操作函数的定义,并提供了测试函数TestRBTree用于验证红黑树的正确性。
|
||||
|
||||
|
||||
## 2. 数据结构设计说明
|
||||
|
||||
**RBNodeType 结构体**
|
||||
用来存储一个红黑树结点的相关信息
|
||||
- key:节点的键值
|
||||
- left_child:指向左子节点的指针
|
||||
- right_child:指向右子节点的指针
|
||||
- parent:指向父节点的指针
|
||||
- is_red:表示节点的颜色,true表示红色,false表示黑色
|
||||
|
||||
**RBTreeType 结构体**
|
||||
用来存储一个红黑树的相关信息
|
||||
- root:指向红黑树的根节点的指针
|
||||
- leaf:红黑树的叶节点,由于叶节点并不需要存储数据,故每棵树只分配一个叶节点
|
||||
|
||||
|
||||
**RBTreeTraversal 函数**
|
||||
该函数用于遍历红黑树并打印节点的键值。采用中序遍历的方式,递归地遍历左子树、当前节点和右子树。
|
||||
|
||||
**RBTreeLeftRotate 函数**
|
||||
该函数实现红黑树的左旋转操作。接受一个当前节点指针作为参数,并按照左旋转的规则调整节点和子树的位置。
|
||||
|
||||
**RBTreeRightRotate 函数**
|
||||
该函数实现红黑树的右旋转操作。接受一个当前节点指针作为参数,并按照右旋转的规则调整节点和子树的位置。
|
||||
|
||||
**InsertFixup 函数**
|
||||
该函数用于插入节点后修复红黑树的平衡性。接受一个当前节点指针作为参数,并根据红黑树的性质进行旋转和着色操作,以恢复平衡。
|
||||
|
||||
**RBTreeInsert 函数**
|
||||
该函数用于向红黑树中插入一个新节点。接受一个新节点指针作为参数,并根据新节点的键值插入到适当的位置,然后调用 InsertFixup 进行修复。
|
||||
|
||||
**DeleteFixup 函数**
|
||||
该函数用于删除节点后修复红黑树的平衡性。接受一个当前节点指针作为参数,并根据红黑树的性质进行旋转和着色操作,以恢复平衡。
|
||||
|
||||
**RBTreeDelete 函数**
|
||||
该函数用于从红黑树中删除指定节点。接受一个目标节点指针作为参数,并根据不同的情况进行节点的替换和删除操作,然后调用 DeleteFixup 进行修复。
|
||||
|
||||
**FindSuccessor 函数**
|
||||
该函数用于查找给定节点的后继节点。接受一个当前节点指针作为参数,并在红黑树中找到当前节点的后继节点。
|
||||
|
||||
**RBTreeSearch 函数**
|
||||
该函数用于在红黑树中查找指定键值的节点。接受一个键值作为参数,并在红黑树中进行查找,返回找到的节点指针。
|
||||
|
||||
## 3. 测试程序说明
|
||||
TestRBTree用于验证红黑树的功能和正确性,下面是该程序的使用步骤和说明:
|
||||
- 函数中定义一个默认关键字数组,其中包含了20个整数关键字,运行时自动遍历数组构建红黑树,构建完成后中序遍历输出结果,可以根据输出结果验证红黑树的节点顺序以及颜色是否符合预期。
|
||||
- 对关键字数组中的每个关键字,在红黑树中进行搜索,并输出找到节点的父节点、左子节点和右子节点的关键字,随后删除该节点。
|
||||
- 在每次删除操作后,程序会询问是否显示当前的红黑树。如果输入 "Y" 或 "y",将再次进行中序遍历,并输出当前红黑树中的结点,可以根据输出结果查看结点是否符合预期。当树空时结束程序。
|
||||
|
||||
|
||||
## 4. 运行结果(##需结合运行测试截图按步骤说明##)
|
||||
|
||||
根据默认关键字数组构建红黑树
|
||||
|
||||

|
||||
|
||||
根据键值查找结点,输出相关信息并删除,可以输入'Y'或'y'展示删除后的红黑树
|
||||
|
||||

|
||||
|
||||
到达空树,退出程序
|
||||
|
||||

|
Binary file not shown.
After Width: | Height: | Size: 65 KiB |
Binary file not shown.
After Width: | Height: | Size: 36 KiB |
Binary file not shown.
After Width: | Height: | Size: 125 KiB |
|
@ -0,0 +1,341 @@
|
|||
/*
|
||||
* Copyright (c) 2023 AIIT XUOS Lab
|
||||
* XiUOS is licensed under Mulan PSL v2.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||
* You may obtain a copy of Mulan PSL v2 at:
|
||||
* http://license.coscl.org.cn/MulanPSL2
|
||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
* See the Mulan PSL v2 for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file: test_rbtree.c
|
||||
* @brief: a application of red-black tree function
|
||||
* @version: 1.0
|
||||
* @author: AIIT XUOS Lab
|
||||
* @date: 2023/6/23
|
||||
*/
|
||||
#include<string.h>
|
||||
#include <transform.h>
|
||||
#include"test_rbtree.h"
|
||||
#ifdef ADD_XIZI_FETURES
|
||||
|
||||
void RBTreeTraversal(RBTreeType *tree, RBNodeType *node)
|
||||
{
|
||||
if (node != tree->leaf) {
|
||||
RBTreeTraversal(tree, node->left_child);
|
||||
printf("key:%d, color:%s\n", node->key, (node->is_red ? "Red" : "Black"));
|
||||
RBTreeTraversal(tree, node->right_child);
|
||||
}
|
||||
}
|
||||
|
||||
RBNodeType* RBTreeSearch(RBTreeType *tree, int key)
|
||||
{
|
||||
RBNodeType* current_node = tree->root;
|
||||
while (current_node != tree->leaf){
|
||||
if (key < current_node->key)
|
||||
current_node = current_node->left_child;
|
||||
else if (key > current_node->key)
|
||||
current_node = current_node->right_child;
|
||||
else
|
||||
return current_node;
|
||||
}
|
||||
|
||||
return tree->leaf;
|
||||
}
|
||||
|
||||
void RBTreeLeftRotate(RBTreeType *tree, RBNodeType *current_node)
|
||||
{
|
||||
RBNodeType* child_node = current_node->right_child;
|
||||
|
||||
current_node->right_child = child_node->left_child;
|
||||
if (child_node->left_child != tree->leaf)
|
||||
child_node->left_child->parent = current_node;
|
||||
|
||||
child_node->parent = current_node->parent;
|
||||
if (current_node->parent == tree->leaf)
|
||||
tree->root = child_node;
|
||||
else if (current_node == current_node->parent->left_child)
|
||||
current_node->parent->left_child = child_node;
|
||||
else
|
||||
current_node->parent->right_child = child_node;
|
||||
|
||||
child_node->left_child = current_node;
|
||||
current_node->parent = child_node;
|
||||
}
|
||||
|
||||
void RBTreeRightRotate(RBTreeType *tree, RBNodeType* current_node)
|
||||
{
|
||||
RBNodeType* child_node = current_node->left_child;
|
||||
|
||||
current_node->left_child = child_node->right_child;
|
||||
if (child_node->right_child != tree->leaf)
|
||||
child_node->right_child->parent = current_node;
|
||||
|
||||
child_node->parent = current_node->parent;
|
||||
if (current_node->parent == tree->leaf)
|
||||
tree->root = child_node;
|
||||
else if (current_node == current_node->parent->right_child)
|
||||
current_node->parent->right_child = child_node;
|
||||
else
|
||||
current_node->parent->left_child = child_node;
|
||||
|
||||
child_node->right_child = current_node;
|
||||
current_node->parent = child_node;
|
||||
}
|
||||
|
||||
void InsertFixup(RBTreeType *tree, RBNodeType* current_node)
|
||||
{
|
||||
while (current_node->parent->is_red){
|
||||
/* The parent of current_node is the left subtree of the grandfather */
|
||||
if (current_node->parent == current_node->parent->parent->left_child){
|
||||
RBNodeType * uncle_node = current_node->parent->parent->right_child;
|
||||
if (uncle_node->is_red){ /* case1:red uncle and red parent, change color */
|
||||
uncle_node->is_red = false;
|
||||
current_node->parent->is_red = false;
|
||||
current_node->parent->parent->is_red = true;
|
||||
|
||||
current_node = current_node->parent->parent;
|
||||
}else{ /* case2:black uncle and red parent, need rotation */
|
||||
if (current_node->parent->right_child == current_node){
|
||||
current_node = current_node->parent;
|
||||
RBTreeLeftRotate(tree, current_node);
|
||||
}
|
||||
|
||||
current_node->parent->is_red = false;
|
||||
current_node->parent->parent->is_red = true;
|
||||
RBTreeRightRotate(tree, current_node->parent->parent);
|
||||
}
|
||||
/* The parent of current_node is the right subtree of the grandfather, same with left subtree */
|
||||
}else{
|
||||
RBNodeType * uncle_node = current_node->parent->parent->left_child;
|
||||
if (uncle_node->is_red){
|
||||
uncle_node->is_red = false;
|
||||
current_node->parent->is_red = false;
|
||||
current_node->parent->parent->is_red = true;
|
||||
|
||||
current_node = current_node->parent->parent;
|
||||
}else{
|
||||
if (current_node->parent->left_child == current_node){
|
||||
current_node = current_node->parent;
|
||||
RBTreeRightRotate(tree, current_node);
|
||||
}
|
||||
|
||||
current_node->parent->is_red = false;
|
||||
current_node->parent->parent->is_red = true;
|
||||
RBTreeLeftRotate(tree, current_node->parent->parent);
|
||||
}
|
||||
}
|
||||
}
|
||||
tree->root->is_red = false;
|
||||
}
|
||||
|
||||
void RBTreeInsert(RBTreeType *tree, RBNodeType* new_node)
|
||||
{
|
||||
RBNodeType* previous_node = tree->root;
|
||||
RBNodeType* current_node = tree->root;
|
||||
|
||||
while (current_node != tree->leaf){
|
||||
previous_node = current_node;
|
||||
if (new_node->key > current_node->key)
|
||||
current_node = current_node->right_child;
|
||||
else if (new_node->key < current_node->key)
|
||||
current_node = current_node->left_child;
|
||||
else
|
||||
return;
|
||||
}
|
||||
|
||||
if (previous_node == tree->leaf){
|
||||
tree->root = new_node;
|
||||
tree->root->parent = tree->leaf;
|
||||
}else{
|
||||
new_node->parent = previous_node;
|
||||
|
||||
if (previous_node->key > new_node->key)
|
||||
previous_node->left_child = new_node;
|
||||
else
|
||||
previous_node->right_child = new_node;
|
||||
}
|
||||
|
||||
InsertFixup(tree, new_node);
|
||||
}
|
||||
|
||||
RBNodeType* FindSuccessor(RBTreeType *tree, RBNodeType* current_node)
|
||||
{
|
||||
RBNodeType* parent_node = current_node->parent;
|
||||
if (current_node->right_child != tree->leaf){
|
||||
current_node = current_node->right_child;
|
||||
while (current_node->left_child != tree->leaf)
|
||||
current_node = current_node->left_child;
|
||||
return current_node;
|
||||
}
|
||||
|
||||
while ((parent_node != tree->leaf) && (current_node == parent_node->right_child)){
|
||||
current_node = parent_node;
|
||||
parent_node = parent_node->parent;
|
||||
}
|
||||
return parent_node;
|
||||
}
|
||||
|
||||
void DeleteFixup(RBTreeType *tree, RBNodeType* current_node)
|
||||
{
|
||||
while ((current_node != tree->root) && (current_node->is_red == false)){
|
||||
if (current_node == current_node->parent->left_child){
|
||||
|
||||
RBNodeType* brother_node = current_node->parent->right_child;
|
||||
if (brother_node->is_red){
|
||||
brother_node->is_red = false;
|
||||
current_node->parent->is_red = true;
|
||||
RBTreeLeftRotate(tree, current_node->parent);
|
||||
brother_node = current_node->parent->right_child;
|
||||
}
|
||||
|
||||
if ((brother_node->left_child->is_red == false) && (brother_node->right_child->is_red == false)){
|
||||
brother_node->is_red = true;
|
||||
current_node = current_node->parent;
|
||||
}else{
|
||||
if (brother_node->right_child->is_red == false){
|
||||
brother_node->left_child->is_red = false;
|
||||
brother_node->is_red = true;
|
||||
RBTreeRightRotate(tree, brother_node);
|
||||
brother_node = current_node->parent->right_child;
|
||||
}
|
||||
|
||||
brother_node->is_red = current_node->parent->is_red;
|
||||
current_node->parent->is_red = false;
|
||||
brother_node->right_child->is_red = false;
|
||||
RBTreeLeftRotate(tree, current_node->parent);
|
||||
current_node = tree->root;
|
||||
}
|
||||
}else{
|
||||
RBNodeType* brother_node = current_node->parent->left_child;
|
||||
if (brother_node->is_red){
|
||||
brother_node->is_red = false;
|
||||
current_node->parent->is_red = true;
|
||||
RBTreeRightRotate(tree, current_node->parent);
|
||||
brother_node = current_node->parent->left_child;
|
||||
}
|
||||
|
||||
if ((brother_node->left_child->is_red == false) && (brother_node->right_child->is_red == false)){
|
||||
brother_node->is_red = true;
|
||||
current_node = current_node->parent;
|
||||
}else{
|
||||
if (brother_node->left_child->is_red == false){
|
||||
brother_node->right_child->is_red = false;
|
||||
brother_node->is_red = true;
|
||||
RBTreeLeftRotate(tree, brother_node);
|
||||
brother_node = current_node->parent->left_child;
|
||||
}
|
||||
|
||||
brother_node->is_red = current_node->parent->is_red;
|
||||
current_node->parent->is_red = false;
|
||||
brother_node->left_child->is_red = false;
|
||||
RBTreeRightRotate(tree, current_node->parent);
|
||||
current_node = tree->root;
|
||||
}
|
||||
}
|
||||
}
|
||||
current_node->is_red = false;
|
||||
}
|
||||
|
||||
void RBTreeDelete(RBTreeType *tree, RBNodeType* target_node)
|
||||
{
|
||||
RBNodeType* delete_node = tree->leaf;
|
||||
RBNodeType* replace_node = tree->leaf;
|
||||
|
||||
if ((target_node->left_child == tree->leaf) || (target_node->right_child == tree->leaf))
|
||||
delete_node = target_node;
|
||||
else
|
||||
delete_node = FindSuccessor(tree, target_node);
|
||||
|
||||
if (delete_node->left_child != tree->leaf) /* successor still has subtree */
|
||||
replace_node = delete_node->left_child;
|
||||
else if (delete_node->right_child != tree->leaf)
|
||||
replace_node = delete_node->right_child;
|
||||
|
||||
replace_node->parent = delete_node->parent;
|
||||
|
||||
if (delete_node->parent == tree->leaf) /* delete a root node */
|
||||
tree->root = replace_node;
|
||||
else if (delete_node == delete_node->parent->left_child)
|
||||
delete_node->parent->left_child = replace_node;
|
||||
else
|
||||
delete_node->parent->right_child = replace_node;
|
||||
|
||||
if (delete_node != target_node)
|
||||
target_node->key = delete_node->key;
|
||||
|
||||
if (delete_node->is_red == false)
|
||||
DeleteFixup(tree, replace_node);
|
||||
|
||||
free(delete_node);
|
||||
}
|
||||
|
||||
|
||||
void TestRBTree(void)
|
||||
{
|
||||
int default_key[] = { 16, 25, 23, 5, 2, 6, 17, 37, 38, 98, 20, 19, 47, 49, 12, 21, 9, 18, 14, 15 };
|
||||
int array_size = sizeof(default_key) / sizeof(default_key[0]);
|
||||
|
||||
printf("Test Red Black Tree\n");
|
||||
printf("default_key array: ");
|
||||
for (int i = 0; i < array_size; i++)
|
||||
printf("%d ", default_key[i]);
|
||||
printf("\n%d elements\n", array_size);
|
||||
|
||||
RBTreeType *tree = (RBTreeType *)malloc(sizeof(RBTreeType));
|
||||
if (tree == NULL) {
|
||||
printf("malloc failed\n");
|
||||
return;
|
||||
}
|
||||
|
||||
tree->leaf = (RBNodeType*)malloc(sizeof(RBNodeType));
|
||||
tree->leaf->left_child = NULL;
|
||||
tree->leaf->right_child = NULL;
|
||||
tree->leaf->parent = NULL;
|
||||
tree->leaf->is_red = false;
|
||||
tree->leaf->key = -1;
|
||||
tree->root = tree->leaf;
|
||||
|
||||
RBNodeType *node = tree->leaf;
|
||||
|
||||
for (int i = 0; i < array_size; i++) {
|
||||
node = (RBNodeType*)malloc(sizeof(RBNodeType));
|
||||
node->left_child = tree->leaf;
|
||||
node->right_child = tree->leaf;
|
||||
node->parent = NULL;
|
||||
node->is_red = true;
|
||||
node->key = default_key[i];
|
||||
printf("insert key[%d]=%d\n",i,default_key[i]);
|
||||
RBTreeInsert(tree, node);
|
||||
}
|
||||
|
||||
printf("------------------Inorder Traversal------------------\n");
|
||||
RBTreeTraversal(tree, tree->root);
|
||||
|
||||
for (int i = 0; i < array_size; i++) {
|
||||
printf("search key = %d\n", default_key[i]);
|
||||
node = RBTreeSearch(tree, default_key[i]);
|
||||
printf("search succeeded, parent node: %d, left-child: %d, right-child: %d\n", node->parent->key, node->left_child->key, node->right_child->key);
|
||||
|
||||
printf("delete key = %d\n", node->key);
|
||||
RBTreeDelete(tree, node);
|
||||
|
||||
printf("Show current tree?Y/N \n");
|
||||
char ch;
|
||||
scanf("%c", &ch);
|
||||
if (ch == 'Y' || ch == 'y') {
|
||||
printf("------------------Inorder Traversal Tree After Deletion------------------\n");
|
||||
if (tree->root != tree->leaf)
|
||||
RBTreeTraversal(tree, tree->root);
|
||||
else
|
||||
printf("the tree is empty.\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PRIV_SHELL_CMD_FUNCTION(TestRBTree, a red-black tree test sample, PRIV_SHELL_CMD_MAIN_ATTR);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* Copyright (c) 2023 AIIT XUOS Lab
|
||||
* XiUOS is licensed under Mulan PSL v2.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||
* You may obtain a copy of Mulan PSL v2 at:
|
||||
* http://license.coscl.org.cn/MulanPSL2
|
||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
* See the Mulan PSL v2 for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file: test_rbtree.h
|
||||
* @brief: a head file of red-black tree structure
|
||||
* @version: 1.0
|
||||
* @author: AIIT XUOS Lab
|
||||
* @date: 2023/6/23
|
||||
*/
|
||||
#ifndef REDBLACKTREE_H_
|
||||
#define REDBLACKTREE_H_
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
|
||||
typedef struct RedBlackNode
|
||||
{
|
||||
int key;
|
||||
struct RedBlackNode *left_child;
|
||||
struct RedBlackNode *right_child;
|
||||
struct RedBlackNode *parent;
|
||||
bool is_red;
|
||||
} RBNodeType;
|
||||
|
||||
typedef struct RedBlackTree
|
||||
{
|
||||
RBNodeType *root;
|
||||
RBNodeType *leaf;
|
||||
} RBTreeType;
|
||||
|
||||
void TestRBTree(void);
|
||||
|
||||
void RBTreeTraversal(RBTreeType *tree, RBNodeType *node);
|
||||
|
||||
void RBTreeLeftRotate(RBTreeType *tree, RBNodeType *current_node);
|
||||
|
||||
void RBTreeRightRotate(RBTreeType *tree, RBNodeType* current_node);
|
||||
|
||||
void InsertFixup(RBTreeType *tree, RBNodeType* current_node);
|
||||
|
||||
void RBTreeInsert(RBTreeType *tree, RBNodeType* new_node);
|
||||
|
||||
void DeleteFixup(RBTreeType *tree, RBNodeType* current_node);
|
||||
|
||||
void RBTreeDelete(RBTreeType *tree, RBNodeType* target_node);
|
||||
|
||||
RBNodeType* FindSuccessor(RBTreeType *tree, RBNodeType* current_node);
|
||||
|
||||
RBNodeType* RBTreeSearch(RBTreeType *tree, int key);
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue