二叉排序树
二叉排序树定义二叉排序树(Binary Sort Tree)又称二叉查找树,是一种特殊的二叉树。
二叉排序树或者是一棵空树;或者是具有下列性质的二叉树:
(1)若左子树不空,则左子树中所有结点的值均小于它的根结点的值;
(2)若右子树不空,则右子树中所有结点的值均大于它的根结点的值;
(3)左、右子树也分别为二叉排序树;
根据二叉排序树的定义,对二叉树进行LDR遍历得到是递增序列。
对这棵树中序遍历为:3-12-24-37-45-53-61-78-90-100
插入算法
若二叉树为空。则首先单独生成根结点。
若二叉树非空,则将插入值与二叉排序树根结点的关键字进行比较:
(1)如果key的值等于根结点的值,则停止插入;
(2)如果key的值小于根结点的值,则将结点插入左子树;
(3)如果key的值大于根结点的值,则将结点插入右孩子。
注意:新插入的结点总是叶子结点。
例:将序列:122、99、250、110、300、280 作为二叉排序树的结点的关键字值,生成二叉排序树。
算法描述:
//二叉排序树的插入
bool InsertBTNode(BTreeNode **BTNode, int value)
{
bool bRes = false;
if (SearchBTNode((*BTNode), value) == NULL)
{
BTreeNode *BTreeNewNode = (BTreeNode *)malloc(sizeof(BTreeNode));//新结点
BTreeNewNode->value = value;
BTreeNewNode->lChild = NULL;
BTreeNewNode->rChild = NULL;
if ((*BTNode) == NULL)
{
(*BTNode) = BTreeNewNode;
}
else if(value > (*BTNode)->value)
{
InsertBTNode(&(*BTNode)->rChild, value);//递归右子树插入
}
else if(value < (*BTNode)->value)
{
InsertBTNode(&(*BTNode)->lChild, value);//递归左子树插入
}
bRes = true;
}
else
{
bRes = false;
}
return bRes;
}
查找算法
因为二叉排序树可看做是一个有序表,所以在二叉排序树上进行查找,和折半查找类似,也是一个逐步缩小查找范围的过程。
算法思想:
首先将待查关键字key与根结点关键字t进行比较,如果:
a.key = t:则返回根结点地址;
b.key < t:则进一步查左子树;
c.key > t:则进一步查右子树。
算法描述:
//二叉排序树的查找
BTreeNode *SearchBTNode(BTreeNode *BTNode, int key)
{
if (NULL == BTNode)
{
return NULL;
}
if (BTNode->value == key)//找到,返回
{
return BTNode;
}
else if(key > BTNode->value)
{
return SearchBTNode(BTNode->rChild, key);
}
else
{
return SearchBTNode(BTNode->lChild, key);
}
return NULL;
}
删除结点算法
在二叉排序树中删除结点的原则是:删除结点后仍是二叉排序树。
设在二叉排序树被删除结点是p,其双亲结点为f。(假设结点p是结点f的左孩子)
情况讨论:
(1) 若p为叶结点,则可直接将其删除:f->lchild = NULL;free(p);
(2) 若p结点只有左子树或只有右子树,则可将p的左子树或右子树直接改为其双亲结点f的左子树:f->lchild = p->lchild;free(p);
(3) 若p既有左子树又有右子树,此时有两种处理方法:
方法1:首先找到p结点在中序序列中的直接前驱结点s,然后将p的左子树改为f的左子树,而将p的右子树改为s的右子树:
f->lchild = p->lchild;
s->rchild = p->rchild;
free(p);
方法2:首先找到p结点在中序序列中的直接前驱结点s,然后用s结点的值替代p结点的值,再将s结点删除,原s结点的左子树改为s的双亲结点q的右子树:
p->data = s->data;
q->rchild = s->lchild;
free(s);
算法描述:
void DeleteNode(BTreeNode **BTNode)
{
BTreeNode *q = NULL;
BTreeNode *s = NULL;
if (NULL == (*BTNode)->rChild)//右子树为空,则链接它的左子树
{
q = *BTNode;
(*BTNode) = (*BTNode)->lChild;
free(q);
}
else if(NULL == (*BTNode)->lChild)//左子树为空,则链接它的右子树
{
q = (*BTNode);
(*BTNode) = (*BTNode)->rChild;
free(q);
}
else//左右子树均不为空
{
q = (*BTNode);
s = (*BTNode)->lChild;
while (s->rChild != NULL)//转到左,然后向右到尽头
{
q = s;
s = s->rChild;
}
(*BTNode)->value = s->value;//s指向被删结点的直接前驱
if (q != (*BTNode))
{
q->rChild = s->lChild;
}
else
{
q->lChild = s->lChild;
}
free(s);
}
}
代码实现:
#ifndef BTreeSort_h__
#define BTreeSort_h__
#include <stdio.h>
#include <stdlib.h>
typedef struct _NODE
{
int value;
struct _NODE *lChild;
struct _NODE *rChild;
}BTreeNode;
//二叉排序树的查找
BTreeNode *SearchBTNode(BTreeNode *BTNode, int key);
//二叉排序树的插入
bool InsertBTNode(BTreeNode **BTNode, int value);
//二叉排序树的创建
void CreateBTNode(BTreeNode **BTNode, int *arr, int length);
//遍历输出值
void InOrderTree(BTreeNode *BTNode);
//删除结点值为key的结点
void Delete(BTreeNode **BTNode, int key);
//删除结点值为key的结点
void DeleteBTree(BTreeNode **BTNode, int key);
//删除结点
void DeleteNode(BTreeNode **BTNode);
#endif // BTreeSort_h__
以上代码的实现:
#include "BTreeSort.h"
//二叉排序树的查找
BTreeNode *SearchBTNode(BTreeNode *BTNode, int key)
{
if (NULL == BTNode)
{
return NULL;
}
if (BTNode->value == key)
{
return BTNode;
}
else if(key > BTNode->value)
{
return SearchBTNode(BTNode->rChild, key);
}
else
{
return SearchBTNode(BTNode->lChild, key);
}
return NULL;
}
//二叉排序树的插入
bool InsertBTNode(BTreeNode **BTNode, int value)
{
bool bRes = false;
if (SearchBTNode((*BTNode), value) == NULL)
{
BTreeNode *BTreeNewNode = (BTreeNode *)malloc(sizeof(BTreeNode));
BTreeNewNode->value = value;
BTreeNewNode->lChild = NULL;
BTreeNewNode->rChild = NULL;
if ((*BTNode) == NULL)
{
(*BTNode) = BTreeNewNode;
}
else if(value > (*BTNode)->value)
{
InsertBTNode(&(*BTNode)->rChild, value);
}
else if(value < (*BTNode)->value)
{
InsertBTNode(&(*BTNode)->lChild, value);
}
bRes = true;
}
else
{
bRes = false;
}
return bRes;
}
//二叉排序树的创建
void CreateBTNode(BTreeNode **BTNode, int *arr, int length)
{
for (int i = 0; i < length; i++)
{
InsertBTNode(&(*BTNode), arr[i]);
}
}
//遍历输出值
void InOrderTree(BTreeNode *BTNode)
{
if (NULL != BTNode)
{
InOrderTree(BTNode->lChild);
printf("%d,", BTNode->value);
InOrderTree(BTNode->rChild);
}
}
/*
二叉排序树中删除一个结点,不是把以该结点为根的都删掉
假设f结点为p结点的双亲结点
叶子结点--->f->lchild = NULL; free(p);
仅有左或者右子树的结点---->f->lchild = p->lchild;
左右子树都有的结点(比较复杂的情况)两中处理方法:
(1)首先找到p结点在中序序列中的直接前驱s结点,然后将p的左子树改为f的左子树,而将p的右子树改为s的右子树
f->lchild = p->lchild;s->rchild=p->rchild; free(p);
(2)首先找到p结点所在中序序列中的直接前驱s结点,然后用s结点的值替代p结点的值,再将s结点删除,原来
s结点的左子树改为s的双亲结点q的右子树
p->data=s->data;q->rchild=s->lchild;free(s);
*/
//删除结点值为key的结点
void DeleteBTree(BTreeNode **BTNode, int key)
{
if(NULL == (*BTNode))
{
return;
}
else
{
if (key == (*BTNode)->value)
{
DeleteNode(BTNode);
}
else if(key > (*BTNode)->value)
{
DeleteBTree(&(*BTNode)->rChild, key);
}
else
{
DeleteBTree(&(*BTNode)->lChild, key);
}
}
}
//删除结点
void DeleteNode(BTreeNode **BTNode)
{
BTreeNode *q = NULL;
BTreeNode *s = NULL;
if (NULL == (*BTNode)->rChild)//右子树为空,则链接它的左子树
{
q = *BTNode;
(*BTNode) = (*BTNode)->lChild;
free(q);
}
else if(NULL == (*BTNode)->lChild)//左子树为空,则链接它的右子树
{
q = (*BTNode);
(*BTNode) = (*BTNode)->rChild;
free(q);
}
else//左右子树均不为空
{
q = (*BTNode);
s = (*BTNode)->lChild;
while (s->rChild != NULL)//转到左,然后向右到尽头
{
q = s;
s = s->rChild;
}
(*BTNode)->value = s->value;//s指向被删结点的直接前驱
if (q != (*BTNode))
{
q->rChild = s->lChild;
}
else
{
q->lChild = s->lChild;
}
free(s);
}
}
测试:
#include "BTreeSort.h"
int main(void)
{
BTreeNode *Root = NULL;
int arrint[] = {62,88,58,47,35,73,51,99,37,93};
int len = sizeof(arrint)/sizeof(arrint[1]);
CreateBTNode(&Root, arrint, len);
InOrderTree(Root);
printf("\b \n");
DeleteBTree(&Root, 47);
InOrderTree(Root);
printf("\b \n");
return 0;
}