数据结构----二叉搜索树(C语言)

关于数据结构二叉树的概念及操作可参看博客:
https://blog.csdn.net/eric_qiushui/article/details/80261271


一、二叉搜索树


二叉搜索树又称为二叉排序树,它或者是一颗空树,或者时具有以下性质的二叉树

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

二、二叉搜索树的操作

最难的部分还是要数二叉搜索树的删除操作

  1. BinarySearchTree.h
 // BinarySearchTree.h

#pragma once

#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <assert.h>

typedef int DataType;

typedef struct BSTreeNode
{
	struct BSTreeNode *_pLeft;
	struct BSTreeNode *_pRight;
	DataType _data;
}BSTNode, *PBSTN;

// 初始化二叉搜索树 
void InitBSTree(PBSTN* pRoot);

// 插入值为data的元素 
void InsertBSTree(PBSTN* pRoot, DataType data);

// 删除值为data的结点 
void DeleteBSTree(PBSTN* pRoot, DataType data);

// 在二叉搜索树中查找值为data的结点 
PBSTN FindBSTree(PBSTN pRoot, DataType data);

// 中序遍历二叉搜索树 
void InOrder(PBSTN pRoot);

// 销毁二叉搜索树 
void DestroyBSTree(PBSTN* pRoot);


  1. BinarySearchTree.c
 // BinarySearchTree.c

#include "BinarySearchTree.h"

// 初始化二叉搜索树 
void InitBSTree(BSTNode** pRoot)
{
	assert(pRoot);

	(*pRoot) = NULL;
}

PBSTN BuyNewNode(DataType data)
{
	PBSTN _new = (PBSTN)malloc(sizeof(BSTNode));
	if (_new == NULL)
	{
		assert(0);
		return NULL;
	}
	else
	{
		_new->_data = data;
		_new->_pLeft = NULL;
		_new->_pRight = NULL;
	}
	return _new;
}

// 插入值为data的元素 
 // 在二叉树中插入新元素时,必须先检测该元素是否在树中已经存在
 // 如果已经存在,则不进行插入
 // 否则将新元素加入到搜索停止的地方
// 具体插入过程:
 // 1.如果树为空树,则直接插入
 // 2.树不空,按二叉搜索树性质查找插入位置,插入新节点
void InsertBSTree(PBSTN* pRoot, DataType data)
{
	PBSTN pCur = NULL;
	PBSTN pParent = NULL;
	assert(pRoot);

	pCur = (*pRoot);
	if ((pCur == NULL))
	{ // 树为空
		(*pRoot) = BuyNewNode(data);
	}
	else
	{ // 树不为空
		// 查找插入位置
		while (pCur)
		{
			if (pCur->_data == data)
			{ // 树中已经有这个元素
				return;
			}
			else if (data < pCur->_data)
			{ // 在左子树中找
				pParent = pCur;
				pCur = pCur->_pLeft;
			}
			else
			{ // 在右子树中找
				pParent = pCur;
				pCur = pCur->_pRight;
			}
		}

		// 插入新节点
		if (data < pParent->_data)
		{
			pParent->_pLeft = BuyNewNode(data);
		}
		else
		{
			pParent->_pRight = BuyNewNode(data);
		}
	}
}

// 在二叉搜索树中查找值为data的结点 
PBSTN FindBSTree(PBSTN pRoot, DataType data)
{
	PBSTN pCur = pRoot;
	if (pCur == NULL)
	{
		return NULL;
	}
	else
	{
		if (pCur->_data == data)
		{
			return pCur;
		}
		else if (data < pCur->_data)
		{
			return FindBSTree(pCur->_pLeft, data);
		}
		else
		{
			return FindBSTree(pCur->_pRight, data);
		}
	}
}

// 删除值为data的结点 
// 要删除的节点有四种情况
 // 1.要删除的节点没有孩子节点
 //   直接删除
 // 2.要删除的节点只有左孩子节点
 //   先链接,再删除
 // 3.要删除的节点只有右孩子节点
 //   先链接,再删除
 // 4.既有左孩子,又有右孩子
 //   (1)寻找一个替代节点:下面两种方法随便一种都行
 //      在当前节点左子树中找替代节点:左子树中最右下端的节点
 //      在当前节点右子树中找替代节点:右子树中最左下端的节点
 //   (2)交换当前节点和替代节点的值
 //   (3)修改要删除的标记----用替代节点覆盖
// 删除值为data的结点 
void DeleteBSTree(PBSTN* pRoot, DataType data)
{
	PBSTN pCur = NULL;
	PBSTN pParent = NULL;
	assert(pRoot);

	// 1.先找要删除的节点
	pCur = (*pRoot);
	while (pCur)
	{
		if (data == pCur->_data)
		{
			if (pParent == NULL)
			{
				// 根节点
				if (pCur->_pLeft == NULL)
				{ // 根节点左子树为空
					if (pCur->_pRight == NULL)
					{ // 根节点右子树也为空
						 // (*pRoot) = NULL; // 把根赋空  这种写法不对
						 pcur = *pRoot;
					}
					else
					{ // 根节点右子树不为空
						(*pRoot) = pCur->_pRight; // 让根节点指向当前节点的右孩子
					}
				}
				else
				{ // 根节点左子树不为空
					if (pCur->_pRight == NULL)
					{ // 根节点右子树为空
						(*pRoot) = pCur->_pLeft; // 让根节点指向当前节点的左孩子
					}
					else
					{ // 根节点右子树也不为空 需要找一个替代节点
						PBSTN _pReplace = pCur->_pLeft;
						pParent = pCur;
						while (_pReplace->_pRight) // 在左子树中找最大值----左子树的最右下端
						{
							pParent = _pReplace;
							_pReplace = _pReplace->_pRight;
						}
						
						pCur->_data = _pReplace->_data;
						if (pCur == pParent)
						{
							pParent->_pLeft = _pReplace->_pLeft;
						}
						else
						{
							pParent->_pRight = _pReplace->_pLeft;
						}
						pCur = _pReplace; // 将待删除节点更改为替代节点
					}
			}
			else
			{ // 要删除节点不是根节点
				if (pCur->_pLeft == NULL)
				{ // 左子树为空
					if (pParent->_pLeft == pCur)
					{
						pParent->_pLeft = pCur->_pRight;
					}
					else
					{
						pParent->_pRight = pCur->_pRight;
					}
				}
				else if (pCur->_pRight == NULL)
				{ // 右子树为空
					if (pParent->_pLeft == pCur)
					{
						pParent->_pLeft = pCur->_pLeft;
					}
					else
					{
						pParent->_pRight = pCur->_pLeft;
					}

				}
				else
				{ // 左、右子树都不为空  需要找替代节点
					PBSTN _pReplace = pCur->_pRight;

					// 在右子树中找最小值----右子树的最左下端
					// 最左下端的节点可以直接删除
					while (_pReplace->_pLeft)
					{
						pParent = _pReplace;
						_pReplace = _pReplace->_pLeft;
					}

					pCur->_data = _pReplace->_data;
					pParent->_pLeft = _pReplace->_pRight;
					pCur = _pReplace; // 将待删除节点更改为替代节点
				}

			}
			break;
		}
		if (data < pCur->_data)
		{
			pParent = pCur;
			pCur = pCur->_pLeft;
		}
		else
		{
			pParent = pCur;
			pCur = pCur->_pRight;
		}
	}

// 2.删除节点
	if (pCur)
	{
		if (pCur == *pRoot)
		{
			free(*pRoot);
			*pRoot = NULL;
		}
		else
		{
			free(pCur);
			pCur = NULL;
		}
	}
	else
	{
		printf("树中没有值为%d的节点\n", data);
	}
}



// 中序遍历二叉搜索树 
void InOrder(PBSTN pRoot)
{
	if (pRoot == NULL)
	{
		return;
	}

	InOrder(pRoot->_pLeft);
	printf("%d ", pRoot->_data);
	InOrder(pRoot->_pRight);
}

// 销毁二叉搜索树 
void DestroyBSTree(PBSTN* pRoot)
{
	assert(pRoot);

	if ((*pRoot) == NULL)
	{
		return;
	}

	DestroyBSTree(&(*pRoot)->_pLeft);
	DestroyBSTree(&(*pRoot)->_pRight);
	free(*pRoot);
	(*pRoot) = NULL;
}

  1. test.c
#include "BinarySearchTree.h"

void TestBinarySearchTree()
{
	PBSTN Root = NULL;
	int arr[] = { 5, 3, 4, 1, 7, 8, 2, 6, 0, 9 };
	int i = 0;
	int size = sizeof(arr) / sizeof(arr[0]);
	PBSTN ret_Find = NULL;

	InitBSTree(&Root);
	for (i = 0; i < size; i++)
	{
		InsertBSTree(&Root, arr[i]);
	}

	printf("InOrder:");
	InOrder(Root);
	printf("\n");

	InsertBSTree(&Root, 10);
	printf("InOrder:");
	InOrder(Root);
	printf("\n");

	ret_Find = FindBSTree(Root, 10);
	if (ret_Find == NULL)
	{
		printf("没找到!!!\n");
	}
	else
	{
		printf("找到了:%d\n", ret_Find->_data);
	}

	DeleteBSTree(&Root, 2);
	printf("InOrder:");
	InOrder(Root);
	printf("\n");

	DeleteBSTree(&Root, 1);
	printf("InOrder:");
	InOrder(Root);
	printf("\n");

	DeleteBSTree(&Root, 5);
	printf("InOrder:");
	InOrder(Root);
	printf("\n");


	DeleteBSTree(&Root, 3);
	printf("InOrder:");
	InOrder(Root);
	printf("\n");


	DestroyBSTree(&Root);
}

int main()
{
	TestBinarySearchTree();
	system("pause");
	return 0;
}

测试结果:
这里写图片描述


如有不正,还请指出,有劳!!!

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值