本文原始地址:C / C++算法学习笔记(2)-二叉查找树
查找操作
若根结点的关键字值等于查找的关键字,成功。
否则,若小于根结点的关键字值,递归查左子树。
若大于根结点的关键字值,递归查右子树。
若子树为空,查找不成功。
/*
//二叉树查找算法
//T 二叉树
//x 要查找的值
*/
BiTree BSTSearch(BiTree T,int x)
{
BiTreeNode *p;
if (T != NULL)
{
p = T;
while (p != NULL)
{
if (p->data == x)//如果该结点就是我们想要的
{
return p;
}else if(x > p->data)//如果查找的值是该结点右子树
{
p = p->rchild;
}else//如果查找的值是该结点左子树
{
p = p->lchild;
}
}
}
return NULL;
}
插入操作
首先执行查找算法,找出被插结点的父亲结点。
判断被插结点是其父亲结点的左、右儿子。将被插结点作为叶子结点插入。
若二叉树为空。则首先单独生成根结点。
注意:新插入的结点总是叶子结点。
/*
//二叉树插入操作
//T 二叉树
//x 要插入的值
*/
int BSTInsert(BiTree *T,int x)
{
BiTreeNode *p = NULL;//把x组装成一个只有根结点的树
BiTreeNode *cur = NULL;//纪录当前遍历的结点
BiTreeNode *parent = NULL;//纪录上一次遍历的结点,最后一个值为我们需要插入的结点位置
cur = *T;
while (cur != NULL)
{
if (cur->data == x)//插入操作如果数值已存在,插入失败
{
return 0;
}
parent = cur;//将到该结点子树遍历,纪录下该结点,该循环最终输出值
if (x < cur->data)//到该结点左子树继续遍历
{
cur = cur->lchild;
}else//到该结点右子树继续遍历
{
cur = cur->rchild;
}
}
//申请内存空间
p = (BiTreeNode *)malloc(sizeof(BiTreeNode));
if (!p)//内存空间申请失败,内存不够用了,终止程序
{
exit(-1);
}
//初始化p结点
p->data = x;
p->lchild = NULL;
p->rchild = NULL;
if (!parent)
{
*T = p;//这本来就是棵空树,p将会作为根结点
}else if(x < parent->data)
{
parent->lchild = p;
}else
{
parent->rchild = p;
}
return 1;//插入成功
}
删除操作
1.若*p结点为叶子结点,即PL(左子树)和PR(右子树)均为空树。由于删去叶子结点不破坏整棵树的结构,则只需修改其双亲结点的指针即可。
2.若*p结点只有左子树PL或右子树PR,此时只要令PL或PR直接成为其双亲结点*f的左子树(当*p是左子树)或右子树(当*p是右子树)即可,作此修改也不破坏二叉排序树的特性。
3.若*p结点的左子树和右子树均不空。在删去*p之后,为保持其它元素之间的相对位置不变,可按中序遍历保持有序进行调整,可以有两种做法:
其一是令*p的左子树为*f的左/右(依*p是*f的左子树还是右子树而定)子树,*s为*p左子树的最右下的结点,而*p的右子树为*s的右子树;
其二是令*p的直接前驱(或直接后继)替代*p,然后再从二叉排序树中删去它的直接前驱(或直接后继)-即让*f的左子树(如果有的话)成为*p左子树的最左下结点(如果有的话),再让*f成为*p的左右结点的父结点。
/*
//删除结点
//删除的结点s
//原则:保持二叉树性质不变-根结点的值大于左子树的值小于右子树的值...
*/
void DeleteNode(BiTree *s)
{
if (!s) return;
BiTreeNode *q = NULL;//中间量,纪录旧的的s结点数据
BiTreeNode *x = NULL;
BiTreeNode *y = NULL;
if(!(*s)->rchild)//如果右子树不存在
{
q = (*s);
(*s) = (*s)->lchild;
free(q);
}else if(!(*s)->lchild)//如果左子树不存在
{
q = (*s);
(*s) = (*s)->rchild;
}else//如果左右都存在的话,令*p的直接前驱(或直接后继)替代*p,然后再从二叉排序树中删去它的直接前驱(或直接后继)-即让*f的左子树(如果有的话)成为*p左子树的最左下结点(如果有的话),再让*f成为*p的左右结点的父结点。
{
x = (*s);
y = (*s)->lchild;
while (y->rchild)//查找s的直接前驱结点,y为s的直接前驱结点,x为y的双亲结点
{
x = y;
y = y->lchild;
}
(*s)->data = y->data;//结点s被y取代
if (x != (*s))//如果结点s的左孩子结点不存在右子树
{
x->rchild = y->lchild;//使y的左子树成为x的右子树
}else
{
x->lchild = y->lchild;
}
free(y);
}
}
/*
//在二叉树中查找关键字为x的结点,并删除,删除成功返回1,否则返回0
//T 二叉树
//x 关键字
*/
int BSTDelete(BiTree *T,int x)
{
if (!*T) return 0;
if (x == (*T)->data)
{
DeleteNode(T);
}else if (x < (*T)->data)
{
BSTDelete(&(*T)->lchild,x);
}else
{
BSTDelete(&(*T)->rchild,x);
}
return 1;
}
附:中序遍历
//中序遍历
void InOrderTraverse(BiTree T)
{
if (T)
{
InOrderTraverse(T->lchild);
printf("%4d",T->data);
InOrderTraverse(T->rchild);
}
}
视频地址:BST:二叉查找树