二叉搜索树的概念
二叉搜索树又称二叉排序树,他或者是一颗空树,或者是具有以下性质的二叉树
- 若他的左子树不为空,则左子树上所有节点的值都小于根节点的值
- 若他的右子树不为空,则右子树上所有节点的值都小于根节点的值
- 他的左右子树也分别为二叉搜索树
二叉搜索树的操作
查找
插入
在二叉搜索树中插入新元素时,必须先检测该元素是否在树中已经存在。如果已经存在,则不进行插入;否则将新元素加入到搜索停止的地方。
插入的具体过程:
1.树为空,则直接插入
2.树不空按二叉搜索树性质查找插入位置,插入新节点
删除
首先查找元素是否在二叉搜索树中,如果不存在,则返回,否则要删除的结点可能分下面四种情况:
- 要删除的结点无孩子结点
- 要删除的结点只有左孩子结点
- 要删除的结点只有右孩子结点
- 要删除的结点有左,右孩子结点
对应上述情况,相应的删除方法如下:
- 直接删除该结点
- 删除该节点且使被删除结点的双亲结点指向被删除结点的左孩子结点
- 删除该节点且被删除结点的双亲结点指向被删除结点的右孩子结点
- 在他的右子树中寻找中序下的第一个结点,用他的值填补到被删除节点中,再来处理该节点的删除问题
代码实现如下:
BinarySerchTree.h
#pragma once
#include <stdio.h>
#include <malloc.h>
#include <assert.h>
#include <string.h>
typedef int BSTDataType;
typedef struct BSTreeNode
{
struct BSTreeNode* _left;
struct BSTreeNode* _right;
BSTDataType _data;
}BSTreeNode;
//插入
int BSTreeInsert(BSTreeNode** tree, BSTDataType x);
//删除
int BSTreeRemove(BSTreeNode** tree, BSTDataType x);
//查找
BSTreeNode* BSTreeFind(BSTreeNode** tree, BSTDataType x);
//中序遍历
void BSTreeInOrder(BSTreeNode** tree);
//递归插入
int BSTreeInsertR(BSTreeNode** tree, BSTDataType x);
//递归查找
BSTreeNode* BSTreeFindR(BSTreeNode** tree, BSTDataType x);
//递归删除
int BSTreeRemoveR(BSTreeNode** tree, BSTDataType x);
void TestBSTree();
BinarySerchTree.c
#include "BinarySerchTree.h"
BSTreeNode* BuyBSTreeNode(BSTDataType x)
{
BSTreeNode* node = (BSTreeNode*)malloc(sizeof(BSTreeNode));
node->_data = x;
node->_left = NULL;
node->_right = NULL;
return node;
}
//插入
int BSTreeInsert(BSTreeNode** tree, BSTDataType x)
{
assert(tree);
BSTreeNode* cur, *parent = NULL;
if (*tree == NULL)
{
*tree = BuyBSTreeNode(x);
return 1;
}
cur = *tree;
while (cur)
{
if (cur->_data > x)
{
parent = cur;
cur = cur->_left;
}
else if (cur->_data < x)
{
parent = cur;
cur = cur->_right;
}
else
{
return 0;
}
}
if (parent->_data < x)
{
parent->_right = BuyBSTreeNode(x);
}
else
{
parent->_left = BuyBSTreeNode(x);
}
return 1;
}
//删除一个节点,成功返回1 失败返回0;
int BSTreeRemove(BSTreeNode** tree, BSTDataType x)
{
assert(tree);
BSTreeNode* cur = *tree, *parent = NULL;
while (cur)
{
//1.寻找要删除的结点
if (cur->_data < x)
{
parent = cur;
cur = cur->_right;
}
else if (cur->_data > x)
{
parent = cur;
cur = cur->_left;
}
//开始删除
//此时cur指向要删除结点,parent指向要删除结点的父亲
else ///左为空/右为空
{
//如果要删除的结点是根结点并且左孩子为空,替换根节点为右树根节点
if (cur->_left == NULL)
{
if (parent == NULL)
{
*tree = cur->_right;
free(cur);
}
else
{
if (cur == parent->_left)
{
parent->_left = cur->_right;
free(cur);
}
else
{
parent->_right = cur->_right;
free(cur);
}
}
}
else if (cur->_right == NULL)
{
//如果要删除的结点是根结点并且右孩子为空,替换根节点为左树根节点
if (parent == NULL)
{
*tree = cur->_left;
free(cur);
}
//不是根节点,则直接判断调整指向
else
{
if (cur == parent->_left)
{
parent->_left = cur->_left;
free(cur);
}
else
{
parent->_right = cur->_left;
free(cur);
}
}
}
//要删除结点的左右孩子都不为空(替换删除法)
else
{
BSTreeNode* repalce = cur->_right;
//找到要替换的结点(要删除结点右树最左边的那个结点就是替换结点)
while (repalce->_left)
{
repalce = repalce->_left;
}
//替换数据
cur->_data = repalce->_data;
//递归删除替换结点
BSTreeRemove(&cur->_right, repalce->_data);
}
return 1;
}
}
return 0;
}
//查找
BSTreeNode* BSTreeFind(BSTreeNode** tree, BSTDataType x)
{
assert(tree);
BSTreeNode* cur = *tree;
if (cur->_data < x)
{
cur = cur->_right;
}
else if (cur->_data>x)
{
cur = cur->_left;
}
else
{
return cur;
}
}
void BSTreeInOrder(BSTreeNode** tree)
{
if (*tree == NULL)
{
return;
}
if ((*tree)->_left != NULL)
{
BSTreeInOrder(&((*tree)->_left));
}
printf("%d ", (*tree)->_data);
if ((*tree)->_right != NULL)
{
BSTreeInOrder(&((*tree)->_right));
}
}
int BSTreeInsertR(BSTreeNode** tree, BSTDataType x)
{
assert(tree);
//树为空 直接插入
if (*tree == NULL)
{
*tree = BuyBSTreeNode(x);
return 1;
}
//树不为空
//要插入的数小于根节点的数,在插入位置的左子树
if ((*tree)->_data > x)
{
return BSTreeInsertR(&(*tree)->_left, x);
}
//要插入的数大于根节点的数,在插入位置的右子树
else if ((*tree)->_data < x)
{
return BSTreeInsertR(&(*tree)->_right, x);
}
//要插入的数等于根节点的数,不能插入,返回0;
else
{
return 0;
}
}
BSTreeNode* BSTreeFindR(BSTreeNode** tree, BSTDataType x)
{
assert(tree);
BSTreeNode* cur = *tree;
if (cur == NULL)
{
return NULL;
}
if (cur->_data > x)
{
return BSTreeFindR(&(cur->_left), x);
}
else if (cur->_data < x)
{
return BSTreeFindR(&(cur->_right), x);
}
else
{
return cur;
}
}
//递归删除一个节点,成功返回1 失败返回0;
int BSTreeRemoveR(BSTreeNode** tree, BSTDataType x)
{
assert(tree);
//树为空,删除失败
if (*tree == NULL)
{
return 0;
}
//要删除的数小于根结点的数,说明要删除的结点在左树
if ((*tree)->_data > x)
{
BSTreeRemoveR(&((*tree)->_left), x);
}
//要删除的数大于根结点的数,说明要删除的结点在右树
else if ((*tree)->_data < x)
{
BSTreeRemoveR(&((*tree)->_right), x);
}
else
{
BSTreeNode* del = *tree;
if ((*tree)->_left == NULL)
{
*tree = (*tree)->_right;
free(del);
}
else if ((*tree)->_right == NULL)
{
*tree = (*tree)->_left;
free(del);
}
else
{
BSTreeNode* replace = (*tree)->_right;
while (replace->_left)
{
replace = replace->_left;
}
(*tree)->_left->_data = replace->_data;
return BSTreeRemoveR(&(*tree)->_right, replace->_data);
}
}
return 1;
}
void TestBSTree()
{
//BSTreeNode* tree = NULL;
//BSTreeInsert(&tree, 4);
//BSTreeInsert(&tree, 2);
//BSTreeInsert(&tree, 1);
//BSTreeInsert(&tree, 3);
//BSTreeInsert(&tree, 2);
//const BSTreeNode* node = BSTreeFind(tree, 2);
//printf("Find 2? %d\n", node->_data);
int a[] = { 5, 3, 4, 1, 7, 8, 2, 6, 0, 9 };
BSTreeNode* tree = NULL;
for (int i = 0; i < sizeof(a) / sizeof(a[0]); ++i)
{
BSTreeInsert(&tree, a[i]);
}
BSTreeInOrder(&tree);
printf("\n");
BSTreeRemove(&tree, 4);
BSTreeRemove(&tree, 8);
BSTreeRemove(&tree, 3);
BSTreeRemove(&tree, 7);
BSTreeRemove(&tree, 5);
BSTreeInOrder(&tree);
printf("\n");
BSTreeRemove(&tree, 0);
BSTreeRemove(&tree, 1);
BSTreeRemove(&tree, 2);
BSTreeRemove(&tree, 3);
BSTreeRemove(&tree, 4);
BSTreeRemove(&tree, 5);
/*BSTreeRemove(&tree, 6);
BSTreeRemove(&tree, 7);*/
BSTreeRemove(&tree, 8);
BSTreeRemove(&tree, 9);
BSTreeInOrder(&tree);
printf("\n");
}
int main()
{
TestBSTree();
return 0;
}