操作二叉排序树 c++

一、任务目标

创建二叉排序树并对其进行增加、删除、查询操作。

补充:什么是二叉排序树?
一棵空树,或者是具有下列性质的二叉树:
1、若左子树不空,则左子树上所有结点的值均小于它的根结点的值;
2、若右子树不空,则右子树上所有结点的值均大于它的根结点的值;
3、左、右子树也分别为二叉排序树;

二、思路分析和代码展示

1.二叉排序树的存储表示

// 数据 
struct ElemType { 
	int key; // 关键字项 
	char info; // 信息 
}; 
// 结点 
typedef struct BSTNode {
	ElemType data; // 每个结点的数据域 
	BSTNode * lchild; // 左孩子指针 
	BSTNode * rchild; // 右孩子指针 
}*BSTree; 

二叉排序树的一个结点有三个部分:数据域、左孩子、右孩子(见BSTNode结构体)(BSTree是指向BSTNode结构的指针类型名)
其中数据域包含两个内容:关键字项、信息(见ElemType结构体)

2.二叉排序树的创建

// 二叉排序树的创建 
void CreateBST(BSTree &T) {
	T = NULL; // 将二叉排序树初始化为空树 
	ElemType e;
	int key;
	char info;
	int n;
	cout<<"请输入二叉排序树结点总个数:";
	cin>>n;
	cout<<"请输入"<<n<<"组关键字项和信息:"<<endl;
	for(int i = 1; i <= n; i++) {
		cin>>key>>info;
		e.key = key;
		e.info = info;
		InsertBST(T, e);
	}
} 

通过输入关键字项和信息,确定结点的数据域。至于结点如何插入,重点在于InsertBST函数。

// 二叉排序树的插入
void InsertBST(BSTree &T, ElemType e) {
	if(T == NULL) {
		BSTree temp = new BSTNode; // 指针temp指向一个新结点 
		temp->data = e;
		temp->lchild = temp->rchild = NULL;
		T = temp;
	} else if(e.key < T->data.key) {
		InsertBST(T->lchild, e); // 将*temp插入左子树 
	} else if(e.key > T->data.key) {
		InsertBST(T->rchild, e); // 将*temp插入右子树 
	}
} 

InsertBST函数中包括两个参数:指向二叉排序树根结点的指针T、数据e
1、如果指向根结点的指针为空:创建一个新结点,用temp指针指向它,将数据填入,并将其左右孩子都置空;
2、如果指向根结点的指针不为空,表面根节点数据域存在(注意:根节点的左右孩子都为空!!!因为在1中有置空操作):
如果e的关键字项小于根节点的关键字项,就应当将存放e的结点接在根结点的左侧,运用递归,调用InsertBST函数;
反之,接在右侧

经过以上一系列操作,就完成了排序二叉树的创建

3.二叉排序树的遍历

创建完成后,可以打印二叉排序树,进行检验:

// 遍历二叉树 中序 左根右 
void InOrderTree(BSTree T) {
	if(T == NULL) {
		return;
	} else {
		InOrderTree(T->lchild);
		cout<<T->data.key<<"|"<<T->data.info<<"  ";
		InOrderTree(T->rchild);
	}
}  

该遍历是采用中序遍历(左根右),把每个结点中的关键字项和信息项都打印出来
关于几种方法遍历二叉树的详细解析请点击此处查看另一篇博文

4.二叉排序树的查找

关于在二叉排序树中通过关键字项查找对应信息项,以下给出两种方法,分别为递归法非递归法

4.1 递归法的查找
// 1.1 递归方法 
BSTree SearchBST1(BSTree T, int key) { // T是指向根结点的指针 
	if((T == NULL) || key == T->data.key) return T; // 如果根结点为空 直接返回NULL 如果遍历到空 返回上一层;如果相等 直接返回 
	else if (key < T->data.key) return SearchBST1(T->lchild, key); // 在左子树中查找
	else return SearchBST1(T->rchild, key); // 在右子树中找	 
} 
4.2 非递归法的查找
// 1.2 非递归方法
void SearchBST2(BSTree T, int key, BSTree &p, BSTree &f) {
	f = NULL; // 指针f用与指示p的双亲结点 
	p = T; // 指针p用于遍历整棵树 初始时指向根结点 
	while(p != NULL) {
		if(key < p->data.key) {
			f = p;
			p = p->lchild; // 到左子树上继续找 
		} else if(key > p->data.key) {
			f = p;
			p = p->rchild; // 到右子树 
		} else {
			// 查找成功 退出
			break; 
		}
	} 
	// 如果没有匹配的 则p为NULL 
} 

5.二叉排序树的删除

// 二叉排序树的删除
void DeleteBST(BSTree &T, int key) {
	BSTree p, f; 
	SearchBST2(T, key, p, f);
	if(p == NULL) { // 没有该结点 直接退出 
		cout<<"没有该结点,请重新输入"<<endl;
		return;
	} else {
		BSTree t = p;  
		// 考虑要删除的结点度数:0 1 2
		if(p->lchild && p->rchild) { // 2
			BSTree s = p->lchild; // 来到该二叉排序树的要删除结点的左部分 寻找其前驱
			while(s->rchild != NULL) {
				t = s; // 保存s的前驱 
				s = s->rchild;
			} 
			p->data = s->data; // s的指代替原本要删除的p 
			if(t != p) t->rchild = s->lchild; // s->lchild有内容则接上 为空则为空 
			else t->lchild = s->lchild; // t == p 即 s为 p 的左子树 
			delete s;
			return;
		} else { // 0 1
			t = p->lchild ? p->lchild : p->rchild; 
			if(f == NULL) T = t; // 如果被删除的是树根 以其子树(t的指向)为新根
			else if(p == f->lchild) f->lchild = t;
			else f->rchild = t;
			delete p; // 释放p 
		} 
		cout<<"删除成功"<<endl;
	}
} 

在删除二叉排序树的一个结点时,用p指向要删除的结点,用t指向该结点的双亲结点。要考虑该结点的度数(可能为0、1、2)

1、当度数为2时:找到中序遍历下要删除的结点的前驱,用s指向它,将其数据取出赋给要删除的结点,用t指向前驱结点的双亲结点。
如果要删除的结点的前驱结点不是其左子树:就将s的左子树接到t的右子树上(注意:s的左子树可能为空,那t的右子树就置空;s不肯有右子树,若有右子树,前驱结点就不是此时s指向的结点,而是它的右子树!!!
在这里插入图片描述
如果是其左子树(即t == p):就将s的左子树接到t的左子树
在这里插入图片描述

2、当度数为0或1时:如果p有左子树,就将t指向其左子树,否则就指向其右子树
如果被删除的是根结点:t指向的结点就是新根
在这里插入图片描述
如果被删除的不是根结点且是其双亲结点的左孩子:f的左孩子就是t
如果被删除的不是根结点且是其双亲结点的右孩子:f的右孩子就是t
在这里插入图片描述

6.完整代码

// 操作二叉排序树 
#include <iostream>
using namespace std;

// 二叉排序树的二叉链表存储表示
// 数据 
struct ElemType { 
	int key; // 关键字项 
	char info; // 信息 
}; 
// 结点 
typedef struct BSTNode {
	ElemType data; // 每个结点的数据域 
	BSTNode * lchild; // 左孩子指针 
	BSTNode * rchild; // 右孩子指针 
}*BSTree; 

// 1、二叉排序树的查找
// 1.1 递归方法 
BSTree SearchBST1(BSTree T, int key) { // T是指向根结点的指针 
	if((T == NULL) || key == T->data.key) return T; // 如果根结点为空 直接返回NULL 如果遍历到空 返回上一层;如果相等 直接返回 
	else if (key < T->data.key) return SearchBST1(T->lchild, key); // 在左子树中查找
	else return SearchBST1(T->rchild, key); // 在右子树中找	 
} 
// 1.2 非递归方法
void SearchBST2(BSTree T, int key, BSTree &p, BSTree &f) {
	f = NULL; // 指针f用与指示p的双亲结点 
	p = T; // 指针p用于遍历整棵树 初始时指向根结点 
	while(p != NULL) {
		if(key < p->data.key) {
			f = p;
			p = p->lchild; // 到左子树上继续找 
		} else if(key > p->data.key) {
			f = p;
			p = p->rchild; // 到右子树 
		} else {
			// 查找成功
			break; 
		}
	} 
	// 如果没有匹配的 则p为NULL 
} 

// 2、二叉排序树的插入
void InsertBST(BSTree &T, ElemType e) {
	if(T == NULL) {
		BSTree temp = new BSTNode; // 指针temp指向一个新结点 
		temp->data = e;
		temp->lchild = temp->rchild = NULL;
		T = temp;
	} else if(e.key < T->data.key) {
		InsertBST(T->lchild, e); // 将*temp插入左子树 
	} else if(e.key > T->data.key) {
		InsertBST(T->rchild, e); // 将*temp插入右子树 
	}
} 

// 二叉排序树的创建 
void CreateBST(BSTree &T) {
	T = NULL; // 将二叉排序树初始化为空树 
	ElemType e;
	int key;
	char info;
	int n;
	cout<<"请输入二叉排序树结点总个数:";
	cin>>n;
	cout<<"请输入"<<n<<"组关键字项和信息:"<<endl;
	for(int i = 1; i <= n; i++) {
		cin>>key>>info;
		e.key = key;
		e.info = info;
		InsertBST(T, e);
	}
} 

// 遍历二叉树 中序 左根右 
void InOrderTree(BSTree T) {
	if(T == NULL) {
		return;
	} else {
		InOrderTree(T->lchild);
		cout<<T->data.key<<"|"<<T->data.info<<"  ";
		InOrderTree(T->rchild);
	}
}  

// 二叉排序树的删除
void DeleteBST(BSTree &T, int key) {
	BSTree p, f; 
	SearchBST2(T, key, p, f);
	if(p == NULL) { // 没有该结点 直接退出 
		cout<<"没有该结点,请重新输入"<<endl;
		return;
	} else {
		BSTree t = p;  
		// 考虑要删除的结点度数:0 1 2
		if(p->lchild && p->rchild) { // 2
			BSTree s = p->lchild; // 来到该二叉排序树的要删除结点的左部分 寻找其前驱
			while(s->rchild != NULL) {
				t = s; // 保存s的前驱 
				s = s->rchild;
			} 
			p->data = s->data; // s的指代替原本要删除的p 
			if(t != p) t->rchild = s->lchild; // s->lchild有内容则接上 为空则为空 
			else t->lchild = s->lchild; // t == p 即 s为 p 的左子树 
			delete s;
			return;
		} else { // 0 1
			t = p->lchild ? p->lchild : p->rchild; 
			if(f == NULL) T = t; // 如果被删除的是树根 以其子树(t的指向)为新根
			else if(p == f->lchild) f->lchild = t;
			else f->rchild = t;
			delete p; // 释放p 
		} 
		cout<<"删除成功"<<endl;
	}
} 

int main() {
	cout<<"---创建二叉排序树---"<<endl;
	BSTree T;
	CreateBST(T);
	cout<<"---中序打印二叉排序树---"<<endl;
	InOrderTree(T);
	cout<<endl; 
	int key;
	cout<<"---根据关键字查找对应信息(输入0结束查询)---"<<endl;
	bool flag1 = true;
	while(flag1) {
		cout<<"请输入关键字:";
		cin>>key;
		if(key == 0) {
			cout<<"结束查询"<<endl;
			flag1 = false;
		} else {
			cout<<"递归遍历得:";
			BSTree p1 = SearchBST1(T, key);
			cout<<p1->data.info<<endl;
			cout<<"非递归遍历得:";
			BSTree p2, f;
			SearchBST2(T, key, p2, f); 
			cout<<p2->data.info<<endl;
		}
	} 
	cout<<"---根据关键字删除二叉排序树的结点(输入0结束查询)---"<<endl;
	bool flag2 = true;
	while(flag2) {
		cout<<"输入关键字:";
		cin>>key;
		if(key == 0) {
			cout<<"结束删除"<<endl;
			flag2 = false;
		} else {
			DeleteBST(T, key);
			cout<<"中序遍历此时的二叉排序树:";
			InOrderTree(T);
			cout<<endl;
		}
	}
	return 0;
}

三、运行结果

测试用例:
在这里插入图片描述

在这里插入图片描述

二叉链表是一种常用的数据结构,可以用来实现二叉排序树二叉排序树是一种特殊的二叉树,它满足以下两个条件: 1. 左子树上所有节点的值都小于根节点的值; 2. 右子树上所有节点的值都大于根节点的值。 在C++中,我们可以通过定义一个二叉树结构体来实现二叉排序树。具体实现步骤如下: 1. 定义二叉树结构体: ``` struct TreeNode { int val; TreeNode *left; TreeNode *right; TreeNode(int x) : val(x), left(NULL), right(NULL) {} }; ``` 2. 实现插入操作: ``` void insert(TreeNode*& root, int val) { if (!root) { root = new TreeNode(val); return; } if (val < root->val) { insert(root->left, val); } else if (val > root->val) { insert(root->right, val); } } ``` 3. 实现查找操作: ``` bool search(TreeNode* root, int val) { if (!root) { return false; } if (root->val == val) { return true; } else if (val < root->val) { return search(root->left, val); } else { return search(root->right, val); } } ``` 4. 实现删除操作: ``` void remove(TreeNode*& root, int val) { if (!root) { return; } if (root->val == val) { if (!root->left && !root->right) { delete root; root = NULL; } else if (!root->left) { TreeNode* temp = root; root = root->right; delete temp; } else if (!root->right) { TreeNode* temp = root; root = root->left; delete temp; } else { TreeNode* temp = root->right; while (temp->left) { temp = temp->left; } root->val = temp->val; remove(root->right, temp->val); } } else if (val < root->val) { remove(root->left, val); } else { remove(root->right, val); } } ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值