给出二叉搜索树的定义:
typedef char SearchTreeType;
typedef struct SearchTreeNode
{
SearchTreeType key; // 关键码
struct SearchTreeNode* lchild;
struct SearchTreeNode* rchild;
}SearchTreeNode;
将函数的声明放在head.h的头文件里面:
#pragma once
#include <stdio.h>
#include <windows.h>
typedef char SearchTreeType;
typedef struct SearchTreeNode
{
SearchTreeType key; // 关键码
struct SearchTreeNode* lchild;
struct SearchTreeNode* rchild;
}SearchTreeNode;
// 初始化
void SearchTreeInit(SearchTreeNode** root);
// 创建新节点
SearchTreeNode* CreateSearchTreeNode(SearchTreeType key);
//非递归
// 插入
void SearchTreeInsert_P(SearchTreeNode** root, SearchTreeType key);
// 查找
SearchTreeNode* SearchTreeFind_P(SearchTreeNode* root, SearchTreeType to_find);
// 删除
void SearchTreeRemove_P(SearchTreeNode** root, SearchTreeType key);
void PreOrder(SearchTreeNode* root);
void InOrder(SearchTreeNode* root);
void DestroySearchTreeNode(SearchTreeNode* node);
//递归
// 插入
void SearchTreeInsert(SearchTreeNode** root, SearchTreeType key);
// 查找
SearchTreeNode* SearchTreeFind(SearchTreeNode* root, SearchTreeType to_find);
// 删除
void SearchTreeRemove(SearchTreeNode** root, SearchTreeType key);
函数的定义(具体实现):
#include "SearchTree.h"
void SearchTreeInit(SearchTreeNode** root)
{
if (root == NULL)
{
return;
}
*root = NULL;
}
void DestroySearchTreeNode(SearchTreeNode* node)
{
free(node);
}
SearchTreeNode* CreateSearchTreeNode(SearchTreeType key)
{
SearchTreeNode* new_node = (SearchTreeNode*)malloc(sizeof(SearchTreeNode));
new_node->key = key;
new_node->lchild = NULL;
new_node->rchild = NULL;
return new_node;
}
void SearchTreeInsert_P(SearchTreeNode** root, SearchTreeType key)
{
if (root == NULL)
{
return;
}
// 1. 如果这个树是空树
if (*root == NULL)
{
*root = CreateSearchTreeNode(key);
return;
}
// 2. 如果这个树是非空树:
// a) 先查找到一个合适的插入位置
SearchTreeNode* cur = *root;
SearchTreeNode* parent = NULL;
while (1)
{
if (cur == NULL)
{
// 合适的位置已经找到了
break;
}
if (key < cur->key)
{
parent = cur;
cur = cur->lchild;
}
else if (key > cur->key)
{
parent = cur;
cur = cur->rchild;
}
else
{
// 发现当前元素和要插入的值相同,此处我们约定,让其插入失败
return;
}
}
// b) 再在对应的位置上创建结点
SearchTreeNode* new_node = CreateSearchTreeNode(key);
if (key < parent->key)
{
parent->lchild = new_node;
}
else
{
parent->rchild = new_node;
}
}
SearchTreeNode* SearchTreeFind_P(SearchTreeNode* root, SearchTreeType to_find)
{
if (root == NULL)
{
return;
}
SearchTreeNode* cur = root;
while (cur)
{
if (to_find < cur->key)
{
cur = cur->lchild;
}
else if (to_find < cur->key)
{
cur = cur->rchild;
}
else
{
break;
}
}
return cur;
}
void SearchTreeRemove_P(SearchTreeNode** root, SearchTreeType key)
{
if (root == NULL)
{
return;
}
// 1. 处理空树的情况,直接返回
if (*root == NULL)
{
return NULL;
}
// 2. 找到要删除的结点的位置,以及要删除结点的父节点
SearchTreeNode* to_remove = *root;
SearchTreeNode* parent = NULL;
while (to_remove)
{
if (key < to_remove->key)
{
parent = to_remove;
to_remove = to_remove->lchild;
}
else if (key > to_remove->key)
{
parent = to_remove;
to_remove = to_remove->rchild;
}
else
{
// 找到了
break;
}
}
// 3. 如果要查找元素在树中没有找到,也直接返回
if (to_remove == NULL)
{
return;
}
// 4. 如果要删除的结点存在,要分情况讨论:
// a) 要删除的结点,没有子树,直接删除该结点,并且将父节点置空
if (to_remove->lchild == NULL && to_remove->rchild == NULL)
{
if (to_remove == *root)
{
// 如果要删除的元素是根节点,那么就直接处理
*root = NULL;
}
else
{
// 如果要删除的元素不是根节点,按以下逻辑判定
if (parent->lchild == to_remove)
{
parent->lchild = NULL;
}
else
{
parent->lchild = NULL;
}
}
DestroySearchTreeNode(to_remove);
return;
}
// b) 要删除的结点,只有左子树,删除该结点同时,将该结点的左子树挂到父节点上
else if (to_remove->lchild != NULL && to_remove->rchild == NULL)
{
if (to_remove == *root)
{
// 如果要删除的元素是根节点
*root = to_remove->lchild;
}
else
{
// 如果要删除的元素不是根节点,按以下逻辑判定
if (to_remove == parent->lchild)
{
parent->lchild = to_remove->lchild;
}
else
{
parent->rchild = to_remove->lchild;
}
}
DestroySearchTreeNode(to_remove);
return;
}
// c) 要删除的结点,只有右子树,删除该结点同时,将该结点的右子树挂到父节点上
else if (to_remove->lchild == NULL && to_remove->rchild != NULL)
{
if (to_remove == *root)
{
// 如果要删除的元素是根节点
*root = to_remove->rchild;
}
else
{
// 如果要删除的元素不是根节点,按以下逻辑判定
if (to_remove == parent->lchild)
{
parent->lchild = to_remove->rchild;
}
else
{
parent->rchild = to_remove->rchild;
}
}
DestroySearchTreeNode(to_remove);
return;
}
// d) 要删除的结点,同时有左右子树,找到右子树中的最小值,然后将该最小值赋值给要删除的位置,
// 然后再删除该右子树中的最小值结点,这样一个结点最多只有一个右子树,就转换成了情况 c)
else
{
SearchTreeNode* min = to_remove->rchild;
SearchTreeNode* min_parent = to_remove;
while (min->lchild != NULL)
{
min_parent = min;
min = min->lchild;
}
// 代码执行到这里的时候,min就已经指向 to_remove 右子树的最小值
to_remove->key = min->key;
if (min_parent->lchild == min)
{
min_parent->lchild = min->rchild;
}
else
{
min_parent->rchild = min->rchild;
}
DestroySearchTreeNode(min);
return;
}
}
void PreOrder(SearchTreeNode* root)
{
if (root)
{
printf("%c ", root->key);
PreOrder(root->lchild);
PreOrder(root->rchild);
}
}
void InOrder(SearchTreeNode* root)
{
if (root)
{
InOrder(root->lchild);
printf("%c ", root->key);
InOrder(root->rchild);
}
}
void SearchTreeInsert(SearchTreeNode** root, SearchTreeType key)
{
if (root == NULL)
{
// 非法输入
return;
}
if (*root == NULL) // 关键代码 // 2. 创建新的结点,挂在对应的位置上
{
*root = CreateSearchTreeNode(key);
return;
}
// 1. 先找到要往哪个位置插入
if (key < (*root)->key)
{
SearchTreeInsert(&(*root)->lchild, key);
}
else if (key > (*root)->key)
{
SearchTreeInsert(&(*root)->rchild, key);
}
else
{
// 发现当前元素和要插入的值相同,此处我们约定,让其插入失败
return;
}
}
SearchTreeNode* SearchTreeFind(SearchTreeNode* root, SearchTreeType to_find)
{
if (root == NULL)
{
// 空树
return;
}
if (to_find < root->key)
{
return SearchTreeFind(root->lchild, to_find);
}
else if (to_find > root->key)
{
return SearchTreeFind(root->rchild, to_find);
}
else
{
// 找到
return root;
}
}
void SearchTreeRemove(SearchTreeNode** root, SearchTreeType key)
{
if (root == NULL)
{
// 非法输入
return;
}
// 1. 找到要删除的元素在树中的位置
// 2. 如果没找到的话,不需要进行任何删除操作
if (*root == NULL)
{
// 空树
return;
}
if (key < (*root)->key)
{
SearchTreeRemove(&(*root)->lchild, key);
}
else if (key > (*root)->key)
{
SearchTreeRemove(&(*root)->rchild, key);
}
// 3. 如果找到了的话,分情况来讨论
else
{
SearchTreeNode* to_remove = *root;
// a) 要删除元素没有子树,直接删除该结点就行了
if (to_remove->lchild == NULL && to_remove->rchild == NULL)
{
*root = NULL;
DestroySearchTreeNode(to_remove);
}
// b) 要删除元素只有左子树,先把左子树挂在父节点上,再删除当前结点
else if (to_remove->lchild != NULL && to_remove->rchild == NULL)
{
*root = to_remove->lchild;
DestroySearchTreeNode(to_remove);
}
// c) 要删除元素只有右子树,先把右子树挂在父节点上,再删除当前结点
else if (to_remove->lchild == NULL && to_remove->rchild != NULL)
{
*root = to_remove->rchild;
DestroySearchTreeNode(to_remove);
}
// d) 要删除元素同时有左右子树,先找到当前元素右子树中最小的那个元素,
// 把这个最小元素赋值到要删除的元素上,然后再删除刚才的最小元素,然后把问题转换成 b) 或者 c)
else
{
SearchTreeNode* min = to_remove->rchild;
while (min->lchild != NULL)
{
min = min->lchild;
}
// 代码执行到这里,意味着 min 已经指向了 to_remove 的右子树中的最小元素
to_remove->key = min->key;
SearchTreeRemove(&to_remove->rchild, min->key);
} // to_remove 左右子树都存在
} // key == to_remove->key
}
测试代码:
#include "SearchTree.h"
void TestSearchTree()
{
SearchTreeNode* root;
SearchTreeInit(&root);
printf("root expect NULL, actual %p\n", root);
SearchTreeInsert_P(&root, 'B');
SearchTreeInsert_P(&root, 'A');
SearchTreeInsert_P(&root, 'G');
SearchTreeInsert_P(&root, 'D');
SearchTreeInsert_P(&root, 'E');
SearchTreeInsert_P(&root, 'F');
printf("先序遍历:");
PreOrder(root);
printf("\n");
printf("中序遍历:");
InOrder(root);
printf("\n");
SearchTreeNode* result = SearchTreeFind(root, 'E');
printf("result expect %p, actual %p \n", root->rchild->lchild->rchild, result);
}
int main()
{
TestSearchTree();
system("pause");
return 0;
}
结果如下: