数据结构--二叉搜索树( 概念 & 基本操作 ) ( C语言版 )

二叉搜索树概念 : 二叉搜索树又称二叉排序树,它或者是一棵空树,或者是具有以下性质的 二叉树

  • 若它的左子树不为空,子树上所有节点的值都小于根节点的值
  • 若它的右子树不为空,则右子树上所有节点的值都大于根节点的值
  • 它的左右子树也分别为二叉搜索树

如下图所示 : 

    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. 当树为空时 , 直接插入 , 并返回 1 ;
  2. 当树不为空时 , 按照搜索二叉树的性质 , 寻找要插入的位置 , 若在查找过程中发现该元素已经存在则直接返回 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;
}

猜你喜欢

转载自blog.csdn.net/ds19980228/article/details/82120429