二叉排序树的一些简单操作

二叉排序树就是左孩子比根节点小,右孩子比根节点大,左小右大的那种二叉树。从定义来看,二叉排序树是不可能有俩个数是相同的。

二叉排序树是为了查找时更加有效率,查找的时候如果小,就往左边跑,一下子就去掉了整个右边。

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

typedef float datatype;

typedef struct BiTNode {
	datatype data;
	struct BiTNode *lchild, *rchild;
}BiTNode,*BiTree;
//===================================================
//中序遍历
void MidTraverse(BiTree tree) {
	if(tree) {
		MidTraverse(tree->lchild);
		printf("%.1f ",tree->data);//修改数据类型的时候这里也要改
		MidTraverse(tree->rchild);
	}//if
}//MidTraverse
//=======================================================
//找数值是否已经在排序树中了
/*
这是在网上看到的递归写法,parent代表要找节点的父节点,
*find返回要找节点
*/
bool SearchBST(BiTree tree, datatype item, BiTree *parent, BiTree *find) {
	if(!tree) {//空树
		*find = *parent;
		return false ;
	}//if
	else if(item == tree->data) {
		*find = tree;//找到了节点
		return true;
	}//else if
	else if(item < tree->data) {//找左子树
		return SearchBST(tree->lchild, item, &tree, find);
	}//else if
	else //找右子树
		return SearchBST(tree->rchild, item, &tree, find);
}//SearchBST 
//================================================================
//上面函数非递归法
/*传指针是因为后面的插入删除都要用到parent find的返回值
如果找到了find就是要找的节点,否则为空
找到了parent就是find的父节点,否则parent就是叶子节点。
*/
bool SearchBST1(BiTree tree, datatype item, BiTree *parent, BiTree *find) {
	*find = tree;//开始当然从根节点开始
	while( (*find) && item != (*find)->data) {
		*parent = *find;//parent作为find的父节点
		//不要写成parent= find虽然语法上没错,但逻辑上不对
		if(item < (*find)->data) //找左孩子
			*find = (*find)->lchild ;
		else//找右孩子
			*find = (*find)->rchild;
	}//while
	if(!(*find)) {
		printf("没找到\n");
		return false;
	}
	else
		return true;
}//SearchBST1
//=============================================================
//二叉排序树中插入节点
/*
插入一个数之前判断树中是否已经有了(二叉排序树定义就是没有相同的数)
插入树的过程就是建立二叉排序树的过程,开始建立树为空,那么第一个插入的数
就做根节点,然后接下来插入数,就同样判断是否存在,找到插入数在树中的parent,
小点就做parent左孩子,大点就做parent右孩子。原理就酱紫。
*/
bool InsertBST(BiTree *tree, datatype item) {
	BiTree p = *tree;
	BiTree find;
	BiTree pNew;
	BiTree parent = NULL ;
	if(SearchBST1(p, item, &parent, &find)) {
		printf("该元素已经存在!\n");
		return false ;
	}//if
	else {
	/*在判断条件里创建节点比一进函数就创要好,因为条件不满足
就不用浪费空间了,小知识吧,慢慢进步
*/	
		printf("进入赋值:");
		pNew = (BiTree )malloc(sizeof(BiTNode ));
		pNew->data = item;
		pNew->lchild = pNew->rchild = NULL;
		if(!*tree) {
			*tree = pNew;
			printf("做根节点\n");
		}//if
		else if(item < parent->data) {
			printf("左孩子\n");
			parent->lchild = pNew;
		}//else if
		else {
			printf("右孩子\n");
			parent->rchild = pNew;
		}//else
		printf("遍历:\n");
		MidTraverse (*tree);
		printf("\n");
		return true;
	}//else
}//InsertBST
//=========================================================
//删除节点
/*
删除节点有三种情况,一种是删除的节点没有左右孩子,光杆司令,第二种是
只有一个孩子,这俩种可以归纳为一种方式:
	if(!find->lchild || !find->rchild)
假如要删除的节点a是她父节点的左孩子,那么反正a最多也就只有一个孩子,
就相当于这个唯一的孩子把a给挤走了,自己做a父节点的左孩子
而第三种接口就是要删除的节点有俩个孩子,假如我们我删除节点3,这时候解决的关键是谁来
顶替3,如果做的多的话就可以知道,我们要找的其实是按中序遍历(左中右)的
直接前驱,也就是3.5。

                            6
                           / \
                          3   7
                         / \   \
                        2   4   10
                       /   / \   /
                      1   3.6 5  8
                           /      \
                        3.5        9
                         \
                         3.7
                           \
                           3.8
						
*/
bool DeleteBST(BiTree tree, datatype item) {
	BiTree p = tree;
	BiTree parent = NULL;
	BiTree find;
	if(!SearchBST1(p, item, &parent, &find)) {
		printf("删除的元素不在树中\n");
		return false ;
	}//if
	if(!find->lchild || !find->rchild) {//一个或俩者都为空
		if(parent->lchild == find) 
			parent->lchild = (find->lchild) ? find->lchild : find->rchild;
		else
			parent->rchild = (find->lchild) ? find->lchild : find->rchild;
		free(find);
	}//if
	else {//有俩个孩子
		BiTree temp = find->rchild;//要删除节点的右孩子
		BiTree p;//直接前驱的父节点
		while(temp->lchild) {
			p = temp;//父节点
			temp = temp->lchild;
			//直接前驱也就是find的右孩子的最左节点,temp是直接前驱
		}//while
		find->data = temp->data;//直接前驱的值给要删除节点
		//前驱肯定没有左孩子的,要不然就不是直接前驱了。
		if(temp->rchild) {//如果直接前驱有右孩子
			p->rchild = temp->rchild;
			//直接前驱的右孩子占据前驱的位置	
		}//if
		free(p->lchild);//看,最后释放的却不是要删除的节点空间,变相理解这里删除
		p->lchild = NULL ;
	//	free(temp);
	//	temp = NULL;//这样子却不对,按道理p->lchild和temp应该一样的,还是我程序写错了?不明白求指教
	}//else
}//DeleteBST
//===================================================
//测试程序
int main() {
	BiTree tree = NULL;
//	int a[] = {62,58,88,47,73,99,35,51,93,37};
	float a[] = {6,3,7,2,4,1,5,3.6,3.5,3.8,3.7,10};
	for(int i = 0 ; i < 12; i++) {
		InsertBST(&tree,a[i]);	
	}
	MidTraverse (tree);
	printf("\n");
	DeleteBST(tree,3);
	MidTraverse (tree);
	return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值