二叉搜索树概念 : 二叉搜索树又称二叉排序树,它或者是一棵空树,或者是具有以下性质的 二叉树
- 若它的左子树不为空,子树上所有节点的值都小于根节点的值
- 若它的右子树不为空,则右子树上所有节点的值都大于根节点的值
- 它的左右子树也分别为二叉搜索树
如下图所示 :
int [ a ] = { 5 , 3 , 4 , 1 , 7 , 8 , 2 , 6 , 0 , 9 } ;
按照中序遍历的结果就为 [ a ] = { 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 }
二叉搜索树基本操作 :
查找 : 当根节点不为空时 ,
- 若根节点data==要查找的数据 , 则返回根节点
- 若根节点data > 要查找的数据 , 继续在其左子树查找
- 若根节点data < 要查找的数据 , 继续在其右子树查找
- 若没有找到返回NULL
代码如下 :
//查找
BSTreeNode* BSTreeFind(BSTreeNode** tree, BSTDataType x)
{
BSTreeNode * node = *tree;
while (node)
{
if (node->_data > x)
node = node->_right;
else if (node->_data > x)
node = node->_left;
else
return node;
}
return NULL;
}
//递归查找
BSTreeNode* BSTreeFind_R(BSTreeNode** tree, BSTDataType x)
{
if (*tree == NULL)
return NULL;
if ((*tree)->_data > x)
return BSTreeFind_R(&(*tree)->_left, x);
else if ((*tree)->_data < x)
return BSTreeFind_R(&(*tree)->_right, x);
else
return *tree;
}
插入 : 在新数据插入之前 , 先检查该元素是否已经存在树中 , 如果存在则不能插入 , 否则将数据插入到搜索停止的地方 .
- 当树为空时 , 直接插入 , 并返回 1 ;
- 当树不为空时 , 按照搜索二叉树的性质 , 寻找要插入的位置 , 若在查找过程中发现该元素已经存在则直接返回 0 , 否则将数据插入到停止的位置 ;
代码如下 :
//插入
int BSTreeInsert(BSTreeNode** tree, BSTDataType x)
{
//cur指针代表要插入位置的父亲节点
BSTreeNode * cur;
BSTreeNode * root= *tree;
//如果为空树直接插入,并返回
if (root == NULL)
{
*tree = BuyBSTreeNode(x);
return 1;
}
root = *tree;
cur = root;
while (root)
{
if (root->_data > x)
{
cur = root;
root = root->_left;
}
else if (root->_data < x)
{
cur = root;
root = root->_right;
}
//要插入的数据已经存在,直接返回
else
return 0;
}
if (cur->_data > x)
cur->_left = BuyBSTreeNode(x);
else
cur->_right = BuyBSTreeNode(x);
return 1;
}
//递归插入
//采用二级指针,将要查入位置用指针表示,然后直接将要插入的元素直接插入即可
int BSTreeInsert_R(BSTreeNode** tree, BSTDataType x)
{
assert(tree);
if (*tree == NULL)
{
//二级指针解引用表示要查入位置的地址
*tree = BuyBSTreeNode(x);
return 1;
}
if ((*tree)->_data > x)
return BSTreeInsert_R(&(*tree)->_left, x);
else if ((*tree)->_data < x)
return BSTreeInsert_R(&(*tree)->_right, x);
else
return 0;
}
删除 ( 重点 ) : 当要查找的元素不在树中时 , 直接返回 , 否则就要分情况讨论 ,
- 当要删除的节点无孩子节点时
- 当删除的节点只有左孩子节点时
- 当删除的节点只有右孩子节点时
- 当删除的节点有左 , 右孩子节点时
我们可以将上述情况中的前三点分为一点 , 当我们要删除的点为前三个条件时 , 我们只需要将父亲点指向孩子节点的非空节点或者直接指向空即可 .
- 直接删除该节点
- 删除该节点 , 并且使被删除节点的父亲节点指向被删除节点的左孩子节点
- 删除该节点 , 并且使被删除节点的父亲节点指向被删除节点的右孩子节点
- 在它右子树中中序遍历寻找最小的数据节点 , 然后将该数据节点的值填补到要被删除的节点 , 再将该数据节点删除即可
例如 : 当我们要删除根节点⑤时 , 我们只需要将节点值为⑥的值填充的根节点 , 然后删除查找到⑥所在的节点 , 删除完成后 该树依旧满足二叉搜索树的性质
代码如下 :
//删除
int BSTreeRemove(BSTreeNode** tree, BSTDataType x)
{
BSTreeNode * parent;
BSTreeNode * cur;
cur = *tree;
parent = NULL;
while (cur)
{
if (cur->_data > x)
{
parent = cur;
cur = cur->_left;
}
else if (cur->_data < x)
{
parent = cur;
cur = cur->_right;
}
else
{
//左为空或者右为空
if (!cur->_left||!cur->_right)
{
//当根节点的左为空,或者右为空时,需要特殊处理
if (parent == NULL)
{
//当根节点的左孩子为空时,只需要将根节点的指针
//指向它的右孩子即可,
if (cur->_left == NULL)
*tree = cur->_right;
//右孩子为空,指向左孩子即可
else
*tree = cur->_left;
break;
}
//如果查找到的孩子节点为父亲节点的左孩子时,如果孩子节点的
//左节点为空时,将父亲节点的左节点指向孩子节点的右节点
if (parent->_left == cur)
{
if (cur->_left == NULL)
parent->_left = cur->_right;
else
parent->_left = cur->_left;
break;
}
//如果查找到的孩子节点为父亲节点的右孩子时,如果孩子节点的
//左节点为空时,将父亲节点的左节点指向孩子节点的右节点
else
{
if (cur->_left == NULL)
parent->_right = cur->_right;
else
parent->_right = cur->_left;
break;
}
}
//左右都不为空
else
{
//不能使用parent去充当临时指针
//创建一个临时指针去查找它的替换节点,并且将查找到的节点的数据
//存放到要删除的节点,再将查找到的节点按照上面的操作删除即可
BSTreeNode * ret;
ret = cur->_right;
while (ret->_left)
ret = ret->_left;
cur->_data = ret->_data;
//注意 : 这里要将cur的右孩子作为查找删除元素的起点
BSTreeRemove(&cur->_right, ret->_data);
}
}
}
//没有找到要删除的节点,直接返回
if(cur==NULL)
return 0;
//将查找到的节点释放掉,并置空
free(cur);
cur = NULL;
return 1;
}
//递归删除(思想基本一致)
int BSTreeRemove_R(BSTreeNode** tree, BSTDataType x)
{
BSTreeNode * parent;
BSTreeNode * cur;
assert(tree);
cur = *tree;
parent = NULL;
if (cur == NULL)
return 0;
if (cur->_data == x)
{
//若查找到元素,且它的左,右孩子中有一个节点为空,
//直接将该元素的指针指向它的非空子节点
if (cur->_left == NULL)
*tree = cur->_right;
else if (cur->_right == NULL)
*tree = cur->_left;
//若左,右孩子都不为空,则寻找替换节点
else
{
parent = cur->_right;
while (parent->_left)
parent = parent->_left;
cur->_data = parent->_data;
return BSTreeRemove_R(&cur->_right,cur->_data);
}
//释放掉要删除元素,并置空,返回
free(cur);
cur = NULL;
return 1;
}
else if (cur->_data > x)
return BSTreeRemove_R(&cur->_left, x);
else
return BSTreeRemove_R(&cur->_right, x);
return 0;
}
完整代码 :
BinarySearchTree.h
#pragma once
#include <stdio.h>
#include <malloc.h>
#include <assert.h>
#include <stdlib.h>
typedef int BSTDataType;
//数据结构
typedef struct BSTreeNode
{
struct BSTreeNode* _left;
struct BSTreeNode* _right;
BSTDataType _data;
}BSTreeNode;
//插入
int BSTreeInsert(BSTreeNode** tree, BSTDataType x);
//递归插入
int BSTreeInsert_R(BSTreeNode** tree, BSTDataType x);
//删除
int BSTreeRemove(BSTreeNode** tree, BSTDataType x);
//递归删除
int BSTreeRemove_R(BSTreeNode** tree, BSTDataType x);
//查找
BSTreeNode* BSTreeFind(BSTreeNode** tree, BSTDataType x);
//递归查找
BSTreeNode* BSTreeFind_R(BSTreeNode** tree, BSTDataType x);
//中序遍历
void BSTreeInOrder(BSTreeNode** tree);
//测试
void TestBSTree();
BinarySearchTree.c
#include "BinarySearchTree.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)
{
BSTreeNode * cur;
BSTreeNode * root= *tree;
if (root == NULL)
{
*tree = BuyBSTreeNode(x);
return 1;
}
root = *tree;
cur = root;
while (root)
{
if (root->_data > x)
{
cur = root;
root = root->_left;
}
else if (root->_data < x)
{
cur = root;
root = root->_right;
}
else
return 0;
}
if (cur->_data > x)
cur->_left = BuyBSTreeNode(x);
else
cur->_right = BuyBSTreeNode(x);
return 1;
}
//递归插入
int BSTreeInsert_R(BSTreeNode** tree, BSTDataType x)
{
assert(tree);
if (*tree == NULL)
{
*tree = BuyBSTreeNode(x);
return 1;
}
if ((*tree)->_data > x)
return BSTreeInsert_R(&(*tree)->_left, x);
else if ((*tree)->_data < x)
return BSTreeInsert_R(&(*tree)->_right, x);
else
return 0;
}
//删除
int BSTreeRemove(BSTreeNode** tree, BSTDataType x)
{
BSTreeNode * parent;
BSTreeNode * cur;
cur = *tree;
parent = NULL;
while (cur)
{
if (cur->_data > x)
{
parent = cur;
cur = cur->_left;
}
else if (cur->_data < x)
{
parent = cur;
cur = cur->_right;
}
else
{
//左为空或者右为空
if (!cur->_left||!cur->_right)
{
if (parent == NULL)
{
if (cur->_left == NULL)
*tree = cur->_right;
else
*tree = cur->_left;
break;
}
if (parent->_left == cur)
{
if (cur->_left == NULL)
parent->_left = cur->_right;
else
parent->_left = cur->_left;
break;
}
else
{
if (cur->_left == NULL)
parent->_right = cur->_right;
else
parent->_right = cur->_left;
break;
}
}
//左右都不为空
else
{
//不能使用parent去充当临时指针
BSTreeNode * ret;
ret = cur->_right;
while (ret->_left)
ret = ret->_left;
cur->_data = ret->_data;
BSTreeRemove(&cur->_right, ret->_data);
}
}
}
if (cur == NULL)
return 0;
free(cur);
cur = NULL;
return 1;
}
//递归删除
int BSTreeRemove_R(BSTreeNode** tree, BSTDataType x)
{
BSTreeNode * parent;
BSTreeNode * cur;
assert(tree);
cur = *tree;
parent = NULL;
if (cur == NULL)
return 0;
if (cur->_data == x)
{
if (cur->_left == NULL)
*tree = cur->_right;
else if (cur->_right == NULL)
*tree = cur->_left;
else
{
parent = cur->_right;
while (parent->_left)
parent = parent->_left;
cur->_data = parent->_data;
return BSTreeRemove_R(&cur->_right,cur->_data);
}
free(cur);
cur = NULL;
return 1;
}
else if (cur->_data > x)
return BSTreeRemove_R(&cur->_left, x);
else
return BSTreeRemove_R(&cur->_right, x);
return 0;
}
//查找
BSTreeNode* BSTreeFind(BSTreeNode** tree, BSTDataType x)
{
BSTreeNode * node = *tree;
while (node)
{
if (node->_data > x)
node = node->_right;
else if (node->_data > x)
node = node->_left;
else
return node;
}
return NULL;
}
//递归查找
BSTreeNode* BSTreeFind_R(BSTreeNode** tree, BSTDataType x)
{
if (*tree == NULL)
return NULL;
if ((*tree)->_data > x)
return BSTreeFind_R(&(*tree)->_left, x);
else if ((*tree)->_data < x)
return BSTreeFind_R(&(*tree)->_right, x);
else
return *tree;
}
//中序遍历
void BSTreeInOrder(BSTreeNode** tree)
{
if ((*tree) == NULL)
return;
BSTreeInOrder(&(*tree)->_left);
printf("%d ", (*tree)->_data);
BSTreeInOrder(&(*tree)->_right);
}
//测试
void TestBSTree()
{
//BSTreeNode root;
//BSTreeNode* tree = &root;
BSTreeNode * tree;
tree = NULL;
int a[] = { 5, 3, 4, 1, 7, 8, 2, 6, 0, 9 };
int i = 0;
for (; i < sizeof(a) / sizeof(a[0]); i++)
BSTreeInsert_R(&tree, a[i]);
BSTreeRemove(&tree, 2);
BSTreeRemove(&tree, 9);
BSTreeRemove(&tree, 5);
BSTreeRemove(&tree, 5);
BSTreeRemove(&tree, 5);
BSTreeRemove_R(&tree, 0);
BSTreeRemove_R(&tree, 1);
BSTreeRemove_R(&tree, 5);
BSTreeRemove_R(&tree, 5);
BSTreeRemove_R(&tree, 6);
printf("%d \n",BSTreeFind_R(&tree, 3)->_data);
BSTreeInOrder(&tree);
printf("\n");
}
Test.c
#include "BinarySearchTree.h"
int main()
{
TestBSTree();
system("pause");
return 0;
}