目录
一,定义
二,性质
三,基本操作
1,初始化
2,查找
3,插入(建树)
4.删除结点
四,总结
一,定义
二叉查找树(Binary Search Tree),(又:二叉搜索树,二叉排序树)它或者是一棵空树,或者是具有下列性质的二叉树: 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值; 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值; 它的左、右子树也分别为二叉排序树。二叉搜索树作为一种经典的数据结构,它既有链表的快速插入与删除操作的特点,又有数组快速查找的优势;所以应用十分广泛,例如在文件系统和数据库系统一般会采用这种数据结构进行高效率的排序与检索操作。
二,性质
二叉搜索树的最主要的性质如下:
1,若它的左子树不空,则左子树上所有的节点的值均小于它的根节点的值
2,若它的右子树不空,则右子树上所有的节点的值均大于它的根节点的值
3,二叉搜索树的左,右子树也分别为二叉搜索树
三,基本操作
实际操作过程中,常常需要先进行预处理的一些定义,以便我们之后写代码更加明了。
typedef int TreeElement;
/*
#define less(A,B) (A<B)
#define eq(A,B) (!less(A,B) && !less(B,A))
#define swap(A,B) {TreeElement t = A;A=B;B=t;}
*/
typedef struct BINode{
TreeElement val;
struct BINode* lchild, *rchild;
}BiNode, *BiTree;
BiTree BuyNode(TreeElement val) {
BiTree tmp = (BiTree)malloc(sizeof(BiNode));
tmp->val = val;
tmp->lchild = NULL;
tmp->rchild = NULL;
return tmp;
}
对结构体以及结构体的指针进行typedef,便于之后的书写。(为了理解的方便,以及这里就尽量少使用自己define的结构)
1,初始化
对于树的初始化,很显然是返回一棵空树的指针。
BiTree IniTree() {
BiTree T = (BiTree)malloc(sizeof(BiNode));
return T;
}
2,查找
令要查找的数为key值。由于二叉搜索树的性质,所以,查找的步骤即为:
1,若key值小于结点值,那么继续寻找其左子树
2,若key值大于结点值,那么继续寻找其右子树
3,若key值等于结点值,那么找到该数,返回该位置节点
4,若一直查找到叶子结点,还未查找到该数,则找不到,返回空指针
//非递归
BiTree BSSearch(TreeElement x, BiTree root) {
BiTree p = root; //令p=树的根
while (p) {
if (x < p->val) p = p->lchild;
else if (x > p->val) p = p->rchild;
else break;
}
return p;
}
//递归
BiTree BSSearch(TreeElement x, BiTree root) {
if (!root) return NULL;
if (root->val = x) return root;
if (x < root->val) return BSSearch(x, root->lchild);
if (x> root->val) return BSSearch(x, root->rchild);
}
3,插入(建树)
创建树的过程,实际上就是不断插入数据的过程,也就是进行二叉搜索树的插入。
插入遵循若已有相同元素,则无需再进行插入的原则。
BiTree BSInsert(TreeElement x, BiTree root) {
BiTree pp,p,newnode;
pp = p = root;
while (p) {//p为搜索指针
pp = p;//指向p的双亲结点
if (x < p->val) p = p->lchild;
else if (x>p->val) p = p->rchild;
else return NULL;
}
//找到要插入的结点,即进行搜索的过程
newnode = BuyNode(x);
if (root) {
if (x < pp->val) pp->lchild = newnode;
else if (x>pp->val) pp->lchild = newnode;
}//如果树非空,就对pp操作,比pp指向值小,链接为左子树,否则为右子树
else {
root = newnode;//为空则让树为根节点
}
return newnode;
}
4.删除结点
删除结点比较麻烦,首先要找到存储x的结点。
1,若这只是一个叶结点,则只删除叶结点就行。
2,若只有左子树或者只有右子树,那么删除对应结点,使其左子树/右子树代替其位置即可
3,若既有左子树又有右子树,则需找到一个替代结点,可以是其前驱结点,也可以是后继结点。然后交换两者的值,删除替代结点即可。
(找前驱:从当前结点左转,之后右转到尽头
找后继:从当前结点右转,之后左转到尽头)
bool BSDelete(BiTree root,TreeElement x) {
BiTree p,pp; //搜索指针找到要删除的结点
pp = p = root;
while (p) {
pp = p;
if (x < p->val) p = p->lchild;
else if (x>p->val) p = p->rchild;
else break;
}
if (!p) return false;//找不到就不用删除
if (p->lchild && p->rchild){
//这里使用找前驱结点,左子树后一直找右子树
BiTree tmp, ptmp;
ptmp = p;
tmp = p->lchild;
while (tmp->rchild) {
ptmp = tmp;
tmp = tmp->rchild;
}
p->val = tmp->val;
pp = ptmp;
p = tmp;
}
//此时最多只有一个子树即左子树或右子树
BiTree tmp;
if (p->lchild) tmp = p->lchild;
else tmp = p->rchild;
if (p == root) {
root = tmp;
}
else {
if (pp->lchild == p) {
pp->lchild = tmp;
}
else{
pp->rchild = tmp;
}
}
free(p);
return true;
}
四,总结
本次也是很久没有更新文章了,趁着1024节日回来更新,希望各位能多点赞收藏支持一下,之后会重新开始坚持出c语言算法的实现的,各位的关注就是我写文章最大的动力,那么我们下次文章再见