【概念】
什么是二叉搜索树?
二叉搜索树又称二叉排序树(按照中序遍历,可以得到一组有序的序列),它或者是一颗空树,或者是具有以下性质的二叉树:
若他的左子树不为空,则左子树上所有节点的值都小于根结点的值。
若他的右子树不为空,则右子树上所有节点的值都大于根结点的值。
他的左右子树也分别为二叉搜索树。
【二叉搜索树的简单操作】
查找
根据二叉搜索树的性质可知,在一棵树中,根节点比其左子树任何一个值都大,比右子树任何一个值都小,所以可将查找分为三步(前提:根节点不为空):
- 用待查找的值=根节点的值,则直接返回true;
- 如果待查找的值>根节点的值,则在其右子树中查找;
- 如果待查找的值<根节点的值,在其左子树中查找。
话不多说,直接上代码(首先是非递归)
int BSTreeNodeFindNor(BSTreeNode pRoot,DataType data)//查找(非递归)
{
if (NULL == pRoot)
{
printf("树为空\n");
}
while (pRoot)
{
if (pRoot->_data == data)
{
return 1;
}
else if (pRoot->_data > data)
{
pRoot = pRoot->_pLeft;
}
else if (pRoot->_data < data)
{
pRoot = pRoot->_pRight;
}
else
{
return 0;
}
}
return 0;
}
递归
int BSTreeNodeFind(BSTreeNode pRoot, DataType data)//查找(递归)
{
if (NULL == pRoot)
{
return 0;
}
else
{
if (data == pRoot->_data)
return 1;
else if (data < pRoot->_data)
return BSTreeNodeFind(pRoot->_pLeft, data);
else if (data > pRoot->_data)
return BSTreeNodeFind(pRoot->_pRight, data);
}
return 0;
}
插入
在二叉搜索树中插入新元素时,必须确保该元素不在二叉树中,如果在则不进行插入,否则将新元素插入到搜索停止的地方。具体步骤分为两步:
- 树为空,则直接插入,然后返回;
- 树不为空,按二叉搜索树的性质查找插入的位置,若带插入的元素小于她的双亲,则插入到双亲左侧,否则插入到双亲右侧。
具体代码框架如图所示:
非递归代码如下:
void BSTreeNodeInsertNor(BSTreeNode* pRoot, DataType data)//插入(非递归)
{
//树为空,直接插入
if (NULL == *pRoot)
{
*pRoot = BuyBSTreeNode(data);
return;
}
//树不为空
//找插入位置
else
{
BSTreeNode pCur = NULL;
BSTreeNode pParent = NULL;
assert(pRoot);
pCur = *pRoot;
while (pCur)
{
if (data == pCur->_data)
{
return;
}
else if (data < pCur->_data)
{
pParent = pCur;
pCur = pCur->_pLeft;
}
else if (data > pCur->_data)
{
pParent = pCur;
pCur = pCur->_pRight;
}
else
{
return;
}
}
if (pParent->_data<data)
pParent->_pRight = BuyBSTreeNode(data);
else if (pParent->_data>data)
pParent->_pLeft = BuyBSTreeNode(data);
}
}
递归代码如下:
int BSTreeNodeInsert(BSTreeNode* pRoot, DataType data)//插入(递归)
{
if (NULL == *pRoot)
{
*pRoot = BuyBSTreeNode(data);
return 1;
}
else
{
if (data < (*pRoot)->_data)
BSTreeNodeInsert(&(*pRoot)->_pLeft, data);
else if (data>(*pRoot)->_data)
BSTreeNodeInsert(&(*pRoot)->_pRight, data);
else
return 0;
}
}
删除
首先查找元素是否在二叉树中,如果不存在,则返回,否则要删除的节点可能分下面四种情况:
- 要删除的节点无孩子节点
- 要删除的节点只有左孩子节点
- 要删除的节点只有右孩子节点
- 要删除的节点左右孩子都存在
四种情况的具体分析过程如图所示:
非递归代码如下:
void DeleteBSTreeNodeNor(BSTreeNode* pRoot, DataType data)//删除(非递归)
{
assert(pRoot);
//查找值为data的节点
BSTreeNode pCur = NULL;//要删除的的节点
BSTreeNode pParent = NULL;
pCur = *pRoot;
while (pCur)
{
if (data == pCur->_data)
{
//pParent = pCur;
break;
}
else if (data < pCur->_data)
{
pParent = pCur;
pCur = pCur->_pLeft;
}
else
{
pParent = pCur;
pCur = pCur->_pRight;
}
}
//没找到,直接返回
if (NULL == pCur)
{
printf("待删除节点不在二叉树中\n");
return;
}
//找到了,分情况讨论
//1.要删除的节点没有左孩子,即只有右孩子或左右孩子都没有
if (pCur->_pLeft == NULL)
{
if (pCur == *pRoot)
*pRoot = pCur->_pRight;
else
{
if (pCur == pParent->_pLeft)
{
pParent->_pLeft = pCur->_pRight;
}
else
{
pParent->_pRight = pCur->_pRight;
}
}
}
//2.要删除的节点没有右孩子,即只有左孩子或左右孩子都没有
else if (pCur->_pRight == NULL)
{
if (pCur == *pRoot)
{
*pRoot = pCur->_pLeft;
}
else
{
if (pCur == pParent->_pLeft)
{
pParent->_pLeft = pCur->_pLeft;
}
else
{
pParent->_pRight = pCur->_pLeft;
}
}
}
//3.要删除的节点左右孩子都存在,在其右子树中找一个最小的节点,替代待删除节点
else
{
BSTreeNode pDel = pCur->_pRight;
pParent = pCur;
while (pDel->_pLeft)
{
pParent = pDel;
pDel = pDel->_pLeft;
}
pCur->_data = pDel->_data;
if (pDel == pParent->_pLeft)
{
pParent->_pLeft = pDel->_pRight;
}
else
{
pParent->_pRight = pDel->_pRight;
}
pCur = pDel;
free(pDel);
}
}
递归代码如下:
int DeleteBSTreeNode(BSTreeNode* pRoot, DataType data)//删除(递归)
{
if (NULL == *pRoot)
{
return 0;
}
if (data == (*pRoot)->_data)
return 1;
else if (data > (*pRoot)->_data)
return DeleteBSTreeNode(&(*pRoot)->_pRight, data);
else if (data < (*pRoot)->_data)
return DeleteBSTreeNode(&(*pRoot)->_pLeft, data);
else
{
BSTreeNode pDel = *pRoot;
if (NULL == pDel->_pLeft)
(*pRoot) = pDel->_pRight;
else if (NULL == pDel->_pRight)
(*pRoot) = pDel->_pLeft;
else
{
//左右子树都存在
BSTreeNode pDel = (*pRoot)->_pRight;
while (pDel->_pLeft)
{
pDel = pDel->_pLeft;
}
(*pRoot)->_data = pDel->_data;
return DeleteBSTreeNode(&(*pRoot)->_pRight, pDel->_data);
}
}
}
完整代码
#pragma once
#include<assert.h>
#include<malloc.h>
#include<stdio.h>
typedef int DataType;
typedef struct BSTreeNode
{
struct BSTreeNode* _pLeft;
struct BSTreeNode* _pRight;
DataType _data;
}BSTNode,*BSTreeNode;
void BSTreeNodeInit(BSTreeNode* pRoot)
{
*pRoot = NULL;
}
BSTreeNode BuyBSTreeNode(DataType data)
{
BSTreeNode pNewNode = (BSTreeNode)malloc(sizeof(BSTNode));//malloc函数开辟的空间一定要判空
if (NULL == pNewNode)
{
assert(0);
return NULL;
}
pNewNode->_data = data;
pNewNode->_pLeft = NULL;
pNewNode->_pRight = NULL;
return pNewNode;
}
void BSTreeNodeInsertNor(BSTreeNode* pRoot, DataType data)//插入(非递归)
{
//树为空,直接插入
if (NULL == *pRoot)
{
*pRoot = BuyBSTreeNode(data);
return;
}
//树不为空
//找插入位置
else
{
BSTreeNode pCur = NULL;
BSTreeNode pParent = NULL;
assert(pRoot);
pCur = *pRoot;
while (pCur)
{
if (data == pCur->_data)
{
return;
}
else if (data < pCur->_data)
{
pParent = pCur;
pCur = pCur->_pLeft;
}
else if (data > pCur->_data)
{
pParent = pCur;
pCur = pCur->_pRight;
}
else
{
return;
}
}
if (pParent->_data<data)
pParent->_pRight = BuyBSTreeNode(data);
else if (pParent->_data>data)
pParent->_pLeft = BuyBSTreeNode(data);
}
}
int BSTreeNodeInsert(BSTreeNode* pRoot, DataType data)//插入(递归)
{
if (NULL == *pRoot)
{
*pRoot = BuyBSTreeNode(data);
return 1;
}
else
{
if (data < (*pRoot)->_data)
BSTreeNodeInsert(&(*pRoot)->_pLeft, data);
else if (data>(*pRoot)->_data)
BSTreeNodeInsert(&(*pRoot)->_pRight, data);
else
return 0;
}
}
int BSTreeNodeFindNor(BSTreeNode pRoot,DataType data)//查找(非递归)
{
if (NULL == pRoot)
{
printf("树为空\n");
}
while (pRoot)
{
if (pRoot->_data == data)
{
return 1;
}
else if (pRoot->_data > data)
{
pRoot = pRoot->_pLeft;
}
else if (pRoot->_data < data)
{
pRoot = pRoot->_pRight;
}
else
{
return 0;
}
}
return 0;
}
int BSTreeNodeFind(BSTreeNode pRoot, DataType data)//查找(递归)
{
if (NULL == pRoot)
{
return 0;
}
else
{
if (data == pRoot->_data)
return 1;
else if (data < pRoot->_data)
return BSTreeNodeFind(pRoot->_pLeft, data);
else if (data > pRoot->_data)
return BSTreeNodeFind(pRoot->_pRight, data);
}
return 0;
}
void DeleteBSTreeNodeNor(BSTreeNode* pRoot, DataType data)//删除(非递归)
{
assert(pRoot);
//查找值为data的节点
BSTreeNode pCur = NULL;//要删除的的节点
BSTreeNode pParent = NULL;
pCur = *pRoot;
while (pCur)
{
if (data == pCur->_data)
{
//pParent = pCur;
break;
}
else if (data < pCur->_data)
{
pParent = pCur;
pCur = pCur->_pLeft;
}
else
{
pParent = pCur;
pCur = pCur->_pRight;
}
}
//没找到,直接返回
if (NULL == pCur)
{
printf("待删除节点不在二叉树中\n");
return;
}
//找到了,分情况讨论
//1.要删除的节点没有左孩子,即只有右孩子或左右孩子都没有
if (pCur->_pLeft == NULL)
{
if (pCur == *pRoot)
*pRoot = pCur->_pRight;
else
{
if (pCur == pParent->_pLeft)
{
pParent->_pLeft = pCur->_pRight;
}
else
{
pParent->_pRight = pCur->_pRight;
}
}
}
//2.要删除的节点没有右孩子,即只有左孩子或左右孩子都没有
else if (pCur->_pRight == NULL)
{
if (pCur == *pRoot)
{
*pRoot = pCur->_pLeft;
}
else
{
if (pCur == pParent->_pLeft)
{
pParent->_pLeft = pCur->_pLeft;
}
else
{
pParent->_pRight = pCur->_pLeft;
}
}
}
//3.要删除的节点左右孩子都存在,在其右子树中找一个最小的节点,替代待删除节点
else
{
BSTreeNode pDel = pCur->_pRight;
pParent = pCur;
while (pDel->_pLeft)
{
pParent = pDel;
pDel = pDel->_pLeft;
}
pCur->_data = pDel->_data;
if (pDel == pParent->_pLeft)
{
pParent->_pLeft = pDel->_pRight;
}
else
{
pParent->_pRight = pDel->_pRight;
}
pCur = pDel;
free(pDel);
}
}
int DeleteBSTreeNode(BSTreeNode* pRoot, DataType data)//删除(递归)
{
if (NULL == *pRoot)
{
return 0;
}
if (data == (*pRoot)->_data)
return 1;
else if (data > (*pRoot)->_data)
return DeleteBSTreeNode(&(*pRoot)->_pRight, data);
else if (data < (*pRoot)->_data)
return DeleteBSTreeNode(&(*pRoot)->_pLeft, data);
else
{
BSTreeNode pDel = *pRoot;
if (NULL == pDel->_pLeft)
(*pRoot) = pDel->_pRight;
else if (NULL == pDel->_pRight)
(*pRoot) = pDel->_pLeft;
else
{
//左右子树都存在
BSTreeNode pDel = (*pRoot)->_pRight;
while (pDel->_pLeft)
{
pDel = pDel->_pLeft;
}
(*pRoot)->_data = pDel->_data;
return DeleteBSTreeNode(&(*pRoot)->_pRight, pDel->_data);
}
}
}
void CreatBSTree(BSTreeNode* pRoot, DataType a[], int size) { int i = 0; for (; i < size; ++i) { BSTreeNodeInsert(&(*pRoot), a[i]); } } void InpRoot(BSTreeNode pRoot)//中序遍历(递归) { if (pRoot) { InpRoot(pRoot->_pLeft); printf("%d ", pRoot->_data); InpRoot(pRoot->_pRight); } } void TestBSTreeNode() { BSTreeNode pRoot=NULL; BSTreeNodeInit(&pRoot); int a[] = { 5, 3, 4, 1, 7, 8, 2, 6, 0, 9 }; CreatBSTree(&pRoot, a, sizeof(a) / sizeof(a[0])); InpRoot(pRoot); printf("\n"); if (!BSTreeNodeFindNor(pRoot, 4)) printf("Not Found\n"); else printf("Found\n"); printf("\n"); if (!BSTreeNodeFind(pRoot, 4)) printf("Not Found\n"); else printf("Found\n"); DeleteBSTreeNodeNor(&pRoot, 10); InpRoot(pRoot); printf("\n"); DeleteBSTreeNode(&pRoot, 10); InpRoot(pRoot); printf("\n"); }