首先应该对二叉搜索树的性质有所了解。
二叉搜索树又称为二叉排序树。当左子树不为空时,则左子树的结点值小于根结点值;右子树不为空时反之。空树也是二叉排序树。
头文件及结构体定义代码:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef int DataType;
typedef struct BSTreeNode{
DataType data;
struct BSTreeNode *left;
struct BSTreeNode *right;
} BSTreeNode;
-
插入
插入首先应判断树是否为空,若为空则直接插入结点。
否则,根据树的性质,找到结点位置,创建新结点,插入到树中。
插入非递归代码:
// 插入 ---- 非递归
int BSTreeInsert2(BSTreeNode **root, DataType data)
{
BSTreeNode *cur = *root;
BSTreeNode *parent = NULL;
// 当前结点不为空
// 插入值大于当前值 向右子树遍历 遇空时结束循环
// 插入值小于当前值 向左子树遍历 遇空时结束循环
while (cur){
if (data == cur->data)
return 0;
parent = cur; // 记录上一个遍历的结点
if (data > cur->data){
cur = cur->right;
}
else
cur = cur->right;
}
// 创建新结点
BSTreeNode *node = (BSTreeNode *)malloc(sizeof(BSTreeNode));
node->data = data;
node->left = node->right = NULL;
if (parent == NULL){
(*root) = node;
}
if (data > parent->data){
parent->right = node;
}
else
parent->left = node;
return 1;
}
插入递归代码:
// 插入 ---- 递归
// 1表示成功 0表示失败
int BSTreeInsert(BSTreeNode **root, DataType data)
{
// 如果树为空
if ((*root) == NULL){
BSTreeNode *node = (BSTreeNode *)malloc(sizeof(BSTreeNode));
node->data = data;
node->left = node->right = NULL;
*root = node;
return 1;
}
// 若所要插入值已经存在则表示错误
// 若所要插入值 大于 当前结点值 则向结点左子树搜索 直到遇到空值 否则反之
BSTreeNode *cur = *root;
if (data == cur->data)
return 0;
if (data > cur->data){
return BSTreeInsert(&(cur->right), data);
}
else
return BSTreeInsert(&(cur->left), data);
}
-
查找
树不为空时, 判断所要查找的data与根节点data比值。
若 root-> data > data ,则在左子树查找;
若 root-> data < data , 则在右子树查找;
扫描二维码关注公众号,回复:
3477442 查看本文章
查找非递归代码:
// 查找 ---- 非递归
int BSTreeFind2(const BSTreeNode *root, DataType data)
{
const BSTreeNode *cur = root;
while (cur){
if (data == cur->data)
return 1;
else if (data > cur->data){
cur = cur->right;
}
else
cur = cur->left;
}
return 0;
}
查找递归代码:
// 插入 ---- 递归
// 1表示成功 0表示失败
int BSTreeInsert(BSTreeNode **root, DataType data)
{
// 如果树为空
if ((*root) == NULL){
BSTreeNode *node = (BSTreeNode *)malloc(sizeof(BSTreeNode));
node->data = data;
node->left = node->right = NULL;
*root = node;
return 1;
}
// 若所要插入值已经存在则表示错误
// 若所要插入值 大于 当前结点值 则向结点左子树搜索 直到遇到空值 否则反之
BSTreeNode *cur = *root;
if (data == cur->data)
return 0;
if (data > cur->data){
return BSTreeInsert(&(cur->right), data);
}
else
return BSTreeInsert(&(cur->left), data);
}
-
删除
删除大致分为:空树,没有孩子结点(子树),有一个孩子结点(子树),有左右孩子结点(子树);
没有孩子时: 将叶子结点删除后,让其父亲结点指向空。
有一个孩子时: 删除该结点使其父亲结点指向它的孩子结点。
有左右孩子时: 可用替换法:用左子树最大值或右子树最小值替换要删除结点。 PS:被替换可能存在一个孩子结点,处理方法与之前一样。
删除非递归代码:
// 删除
int BSTreeNodeRemove(BSTreeNode **root, DataType data)
{
BSTreeNode *cur = *root;
BSTreeNode *del = NULL;
BSTreeNode *node = NULL;
BSTreeNode *parent = NULL;
if (!cur)
return 0;
// 查找要删除结点
while (cur != NULL){
if (data == cur->data){
del = cur;
break;
}
parent = cur;
if (data > cur->data){
cur = cur->right;
}
else
cur = cur->left;
}
if (del == NULL){
printf(" 未找到该结点\n");
return;
}
// 是叶子结点 直接删除
// 只free删除结点 而其父亲结点依然指向他
if (del->left == NULL && del->right == NULL){
if (data < parent->data){
parent->left = NULL;
}
else
parent->right = NULL;
free(del);
return 1;
}
// 只有一个叶子结点(子树) 删除后其叶子结点(子树)继承该结点位置
// 只有左结点(子树)
else if (del->right == NULL){
// 判断删除结点 是左子树 还是 右子树
if (data < parent->data){
parent->left = del->left;
}
else
parent->right = del->left;
free(del);
return 1;
}
// 只有右结点(子树)
else if (del->left == NULL){
if (data < parent->data){
parent->left = del->right;
}
else
parent->right = del->right;
free(del);
return 1;
}
// 有左右两个叶子结点(子树) 删除后可用 其左子树最大值 或 右子树最小值替换
// 例如: 用左子树最大值替换
else{
parent = NULL;
node = del->left;
// node为替换点
while (node->right != NULL){
parent = node;
node = node->right;
}
del->data = node->data;
if (parent == NULL){
del->left = node->left;
}
else{
parent->right = node->left;
}
free(node);
return 1;
}
return 0;
}
对删除的几种可能可以各自封装,使得代码看起来较为清爽。
封装后的非递归代码:
// 没有左孩子
void RemoveNotLeft(BSTreeNode **root, DataType data, BSTreeNode *cur, BSTreeNode *parent)
{
// 为根结点
if (parent == NULL){
*root = cur->right;
}
else{
if (data > (parent)->data){
parent->right = cur->right;
}
else {
parent->left = cur->right;
}
}
free(cur);
}
// 没有右孩子
void RemoveNotRight(BSTreeNode **root, DataType data, BSTreeNode *cur, BSTreeNode *parent)
{
// 为根结点
if (parent == NULL){
*root = cur->left;
}
else{
if (data > (parent)->data){
parent->right = cur->left;
}
else {
parent->left = cur->left;
}
}
free(cur);
}
// 有左右孩子
void RemoveHaveLR(BSTreeNode *cur)
{
// 找左子树最大结点
BSTreeNode *del = cur->left;
BSTreeNode *parent = NULL;
while (del->right != NULL){
parent = del;
del = del->right;
}
// del 为子树中最大的
cur->data = del->data;
if (parent != NULL){
parent->right = del->left;
}
else{
cur->left = del->left;
}
free(del);
}
int BSTreeNodeRemove2(BSTreeNode **root, DataType data)
{
BSTreeNode *cur = *root;
BSTreeNode *parent = NULL;
if (cur == NULL){
return 0;
}
while (cur != NULL){
// 找到要删除的结点
if (data == cur->data){
// 没有左子树
if (cur->left == NULL){
RemoveNotLeft(root, data,cur, parent);
}
else if (cur->right == NULL){
RemoveNotRight(root, data, cur, parent);
}
else{
RemoveHaveLR(cur);
}
return 0;
}
parent = cur;
if (data > cur->data){
cur = cur->right;
}
else{
cur = cur->left;
}
}
return 0;
}
删除递归代码
// 递归的删除
int BSTreeNodeRemove3(BSTreeNode **root, DataType data)
{
// 空树直接返回
if (*root == NULL) {
return 0;
}
// 要删除的是不是根
if (data == (*root)->data) {
BSTreeNode *del = *root;
// 判断要删除的结点是根的左还是右
if ((*root)->left == NULL) {
*root = (*root)->right;
free(del);
}
else if ((*root)->right == NULL) {
*root = (*root)->left;
free(del);
}
else {
// 左右都不为空
RemoveHaveLR(*root);
}
return 1;
}
// 未找到向后递归运算
if (data < (*root)->data) {
return BSTreeNodeRemove3(&(*root)->left, data);
}
else {
return BSTreeNodeRemove3(&(*root)->right, data);
}
}