【数据结构】基于树的查找法——二叉排序树(C语言)

1. 二叉排序树

二叉排序树又称二叉查找树,它是一种特殊的二叉树。
其定义为:二叉排序树或者是一棵空树,或者是具有如下性质的二叉树:
① 若它的左子树非空,则左子树上所有结点的值均均小于根结点的值。
② 若它的左子树非空,则左子树上所有结点的值均均大于(或大于等于)根结点的值。
③ 它的左右子树也分别为二叉排序树。
二叉排序树树二叉排序树的特性
由二叉排序树定义可得,按中序遍历可以得到一个递增有序序列,按逆中序遍历可以得到一个递减有序序列。
如上图中序遍历结果为1,2,3,4,5,6,7,8,9,是递增有序序列。
逆中序遍历结果为9,8,7,6,5,4,3,2,1,是递减有序序列。

2. 二叉排序树实现算法

2.1 存储结构
二叉排序树的存储结构同二叉树,使用二叉链表作为存储结构。

typedef int DataType;

/*二叉排序树的存储结构*/
typedef struct node {
    
    
	DataType data;
	struct node* lchild, * rchild;
}BSTNode, * BSTree;

2.2 二叉排序树的插入与创建
给定一个元素序列,可以采用逐个插入结点算法来创建一棵二叉排序树。
例如按45、24、53、12、28、90顺序输入序列,生成二叉排序树过程如下图:
生成过程注:输入的顺序不同建立的二叉排序树也不同。

/*二叉排序树的插入算法(递归)*/
void InsertBST(BSTree* bst, DataType data) {
    
    
	BSTree s;
	if (*bst == NULL) {
    
    
		s = (BSTree)malloc(sizeof(BSTNode));
		s->data = data;
		s->lchild = NULL;
		s->rchild = NULL;
		*bst = s;
	}
	else if (data < (*bst)->data)
		InsertBST(&((*bst)->lchild), data);		//将s插入左子树
	else if (data >= (*bst)->data)
		InsertBST(&((*bst)->rchild), data);		//将s插入左子树
}

/*创建二叉排序树*/
void CreatBST(BSTree* bst) {
    
    
	DataType data;
	*bst = NULL;
	scanf("%d", &data);
	while (data != 0) {
    
    
		InsertBST(bst, data);
		scanf("%d", &data);
	}
}

2.3 二叉排序树的查找
首先将待查数据data和根结点进行比较,如果:
① data = t,则返回根结点;
② data < t,则进一步查左子树;
③ data > t,则进一步查右子树。

/*二叉排序树的查找(递归)*/
BSTree SearchBST_recursion(BSTree bst, DataType data) {
    
    
	if (bst == NULL)
		return NULL;
	else if (bst->data == data)
		return bst;
	else if (bst->data > data)
		return SearchBST_recursion(bst->lchild, data);	//在左子树继续查找
	else
		return SearchBST_recursion(bst->rchild, data);	//在右子树继续查找
}

/*二叉排序树的查找(非递归)*/
BSTree SearchBST(BSTree bst, DataType data) {
    
    
	BSTree q;
	q = bst;
	while (q) {
    
    
		if (q->data == data)
			return q;
		if (q->data > data)
			q = q->lchild;						//查找左子树
		else
			q = q->rchild;						//查找右子树
	}
	return NULL;								//查找失败
}

2.4 二叉排序树的删除
删除操作首先查找要删除的结点,看是否在二叉排序树中,若不在不做任何操作;
否则假设要删除的结点为p,结点p的双亲结点为f,并假设结点p是结点f的左孩子:
① 若p为叶结点,则可直接删除:f->lchild=NULL
② 若p结点只有左子树,或只有右子树,则可将p的左子树或右子树直接改为双亲结点f的左子树:f->lchild=p->lchild(或f->lchild=p->rchild)
③ 若p既有左子树又有右子树,找到p结点在中序序列中的直接前驱s结点,然后用s结点的值替代p结点的值,再将s结点删除,原s结点的左子树改为s的双亲结点q的右子树:p->data = s->data;q->rchild = s->lchild;

BSTNode* DelBST(BSTree bst, DataType data) {
    
    
	BSTNode* p, * f, * s, * q;
	p = bst;
	f = NULL;
	while (p) {
    
    									//查找值为data的待删除结点	
		if (p->data == data)
			break;
		f = p;									//f指向p结点的双亲结点
		if (p->data > data)
			p = p->lchild;						//查找左子树
		else
			p = p->rchild;						//查找右子树
	}
	if (p == NULL)
		return bst;
	if (p->lchild == NULL) {
    
    				//若待删除结点p无左子树
		if (f == NULL)							//若p为原二叉排序树的根
			bst = p->rchild;
		else if (f->lchild == p)				//若p为f的左孩子
			f->lchild = p->rchild;
		else									//若p为f的右孩子
			f->rchild = p->rchild;
		free(p);
	}
	else {
    
    									//若待删除结点p有左子树
		q = p;
		s = p->lchild;
		while (s->rchild) {
    
    						//在p的左子树中查找最右下结点
			q = s;
			s = s->rchild;
		}
		if (q == p)								//结点s无右子树
			q->lchild = s->lchild;
		else
			q->rchild = s->lchild;
		p->data = s->data;
		free(s);
	}
	return bst;
}

3. 完整实现代码及运行结果

/*二叉排序树*/
# include<stdio.h>
# include<malloc.h>

typedef int DataType;

/*二叉排序树的存储结构*/
typedef struct node {
    
    
	DataType data;
	struct node* lchild, * rchild;
}BSTNode, * BSTree;

/*二叉排序树的插入算法(递归)*/
void InsertBST(BSTree* bst, DataType data) {
    
    
	BSTree s;
	if (*bst == NULL) {
    
    
		s = (BSTree)malloc(sizeof(BSTNode));
		s->data = data;
		s->lchild = NULL;
		s->rchild = NULL;
		*bst = s;
	}
	else if (data < (*bst)->data)
		InsertBST(&((*bst)->lchild), data);		//将s插入左子树
	else if (data >= (*bst)->data)
		InsertBST(&((*bst)->rchild), data);		//将s插入左子树
}

/*创建二叉排序树*/
void CreatBST(BSTree* bst) {
    
    
	DataType data;
	*bst = NULL;
	scanf("%d", &data);
	while (data != 0) {
    
    
		InsertBST(bst, data);
		scanf("%d", &data);
	}
}

/*中序遍历输出二叉树*/
void InOrder(BSTree bst) {
    
    
	if (bst != NULL) {
    
    
		InOrder(bst->lchild);
		printf("%d ", bst->data);
		InOrder(bst->rchild);
	}
}

/*二叉排序树的查找(递归)*/
BSTree SearchBST_recursion(BSTree bst, DataType data) {
    
    
	if (bst == NULL)
		return NULL;
	else if (bst->data == data) {
    
    
		printf("%d", bst->data);
		return bst;
	}
	else if (bst->data > data)
		return SearchBST_recursion(bst->lchild, data);	//在左子树继续查找
	else
		return SearchBST_recursion(bst->rchild, data);	//在右子树继续查找
}

/*二叉排序树的查找(非递归)*/
BSTree SearchBST(BSTree bst, DataType data) {
    
    
	BSTree q;
	q = bst;
	while (q) {
    
    
		if (q->data == data) {
    
    
			printf("%d", q->data);
			return q;
		}
		if (q->data > data)
			q = q->lchild;						//查找左子树
		else
			q = q->rchild;						//查找右子树
	}
	return NULL;								//查找失败
}

/*二叉排序树的删除*/
void DelBST(BSTree bst, DataType data) {
    
    
	BSTNode* p, * f, * s, * q;
	p = bst;
	f = NULL;
	while (p) {
    
    									//查找值为data的待删除结点	
		if (p->data == data)
			break;
		f = p;									//f指向p结点的双亲结点
		if (p->data > data)
			p = p->lchild;						//查找左子树
		else
			p = p->rchild;						//查找右子树
	}
	if (p == NULL)
		return bst;
	if (p->lchild == NULL) {
    
    				//若待删除结点p无左子树
		if (f == NULL)							//若p为原二叉排序树的根
			bst = p->rchild;
		else if (f->lchild == p)				//若p为f的左孩子
			f->lchild = p->rchild;
		else									//若p为f的右孩子
			f->rchild = p->rchild;
		free(p);
	}
	else {
    
    									//若待删除结点p有左子树
		q = p;
		s = p->lchild;
		while (s->rchild) {
    
    						//在p的左子树中查找最右下结点
			q = s;
			s = s->rchild;
		}
		if (q == p)								//结点s无右子树
			q->lchild = s->lchild;
		else
			q->rchild = s->lchild;
		p->data = s->data;
		free(s);
	}
	return bst;
}

int main() {
    
    
	BSTree bst;
	CreatBST(&bst);
	printf("中序遍历输出:");
	InOrder(bst);
	printf("\n递归查找结果:");
	SearchBST_recursion(bst, 12);
	printf("\n非递归查找结果:");
	SearchBST(bst, 12);
	DelBST(bst, 24);
	printf("\n删除值为24的结点后中序遍历输出:");
	InOrder(bst);
	return 0;
}

运行结果
运行结果
参考:耿国华《数据结构——用C语言描述(第二版)》

更多数据结构内容关注我的《数据结构》专栏https://blog.csdn.net/weixin_51450101/category_11514538.html?spm=1001.2014.3001.5482

猜你喜欢

转载自blog.csdn.net/weixin_51450101/article/details/123172688