011——二叉树 (3)二叉搜索树/二叉排序树BST

目录

高级搜索树:        

分类:

二叉搜索树:

定义:

性质:

特点:

操作:

插入操作

递归方法插入

非递归方法插入

整体代码

删除操作

整体代码:


高级搜索树:        

用于数据的存储和查找的树

分类:

BST        AVL        红黑树        B树        B+树

二叉搜索树:

定义:

在二叉树的基础上增加一些规则:                

                1.如果某节点的左子树不空 ,左子树上所有的节点的值都要小于该节点的值
                2.如果某节点的右子树不空,右子树上所有的节点的值都要大于该节点的值
                3.所有节点都要满足以上约束。

性质:

中序遍历序列有序(从小到大,由规则可知)注意:如果变成从大到小,也是二叉排序树

特点:

优点:提高查找效率(如果是完全二叉树,高度为log2(n+1)向下取整)

缺点:如果用于建树的初始序列有序,建立的BST是一个斜树,高度为n

操作:

插入操作

在空树插入数据x时,将数据k作为根节点即可,左右指针为空

//二叉链表存树
typedef struct BSTnode {
	int data;
	struct BSTnode* left;
	struct BSTnode* right;
}BSTNode, * BSTree;
BSTree initBST(int k)
{
	BSTree r = (BSTNode*)malloc(sizeof(BSTNode));
	//if(r==NULL)
	r->data = k;
	r->left = r->right = NULL;
	return r;
}
递归方法插入

在非空树上插入数据时,假设此时树的根节点是r,判断插入数据k和根节点数据的大小关系:

如果k<r,k插入左子树中,再以r的左孩子作为根节点,让k与其比较,直到找到空结点

如果k>r,k插入右子树中,再以r的右孩子作为根节点,让k与其比较,直到找到空结点

递归出口:结点位置为空

代码:

BSTree insert(BSTree r, int k)
{
	if (r == NULL)
	{
		BSTree s = (BSTNode*)malloc(sizeof(BSTNode));
		//if(s==NULL)
		s->data = k;
		s->left = s->right = NULL;
		return s;
	}
	if (k < r->data)
	{
		r->left = insert(r->left, k);
	}
	if (k > r->data)
	{
		r->right = insert(r->right, k);
	}
	return r;
}
非递归方法插入

在上面的递归方法中,插入位置是在递归的过程中找到的,而在非递归方法中,要是想要插入数据,就需要我们先找到要插入的位置,将给位置的空结点换成要插入的数据结点

查找函数:

void find(BSTree r, int x)
{
	BSTNode* p = r;
	while (p != NULL)
	{
		if (x == p->data)
		{
			cout << "存在" << endl;
			break;
		}
		if (x < p->data)
		{
			p = p->left;
		}
		if (x > p->data)
		{
			p = p->right;
		}
	}
	if (p == NULL)
	{
		cout << "不存在" << endl;
	}
}
BSTree insert_1(BSTree r, int k)
{
	BSTree s = (BSTNode*)malloc(sizeof(BSTNode));
	//if(s==NULL)
	s->data = k;
	s->left = s->right = NULL;
	//空树插入 
	if (r == NULL)
	{
		return s;
	}
	//非空树插入 
	BSTNode* p = r;//遍历
	BSTNode* pre = NULL;//p的父亲
	//遍历找插入位置 
	while (p != NULL)
	{
		if (k < p->data)
		{
			pre = p;
			p = p->left;
		}
		else {
			pre = p;
			p = p->right;
		}
	}
	//插入 
	if (k < pre->data)
	{
		pre->left = s;
	}
	else {
		pre->right = s;
	}
	return r;
}
整体代码
#include <iostream>
using namespace std;
//二叉链表存树
typedef struct BSTnode {
	int data;
	struct BSTnode* left;
	struct BSTnode* right;
}BSTNode, * BSTree;
BSTree initBST(int k)
{
	BSTree r = (BSTNode*)malloc(sizeof(BSTNode));
	//if(r==NULL)
	r->data = k;
	r->left = r->right = NULL;
	return r;
}
BSTree insert(BSTree r, int k)
{
	if (r == NULL)
	{
		BSTree s = (BSTNode*)malloc(sizeof(BSTNode));
		//if(s==NULL)
		s->data = k;
		s->left = s->right = NULL;
		return s;
	}
	if (k < r->data)
	{
		r->left = insert(r->left, k);
	}
	if (k > r->data)
	{
		r->right = insert(r->right, k);
	}
	return r;
}
//-----------非递归-------
BSTree insert_1(BSTree r, int k)
{
	BSTree s = (BSTNode*)malloc(sizeof(BSTNode));
	//if(s==NULL)
	s->data = k;
	s->left = s->right = NULL;
	//空树插入 
	if (r == NULL)
	{
		return s;
	}
	//非空树插入 
	BSTNode* p = r;//遍历
	BSTNode* pre = NULL;//p的父亲
	//遍历找插入位置 
	while (p != NULL)
	{
		if (k < p->data)
		{
			pre = p;
			p = p->left;
		}
		else {
			pre = p;
			p = p->right;
		}
	}
	//插入 
	if (k < pre->data)
	{
		pre->left = s;
	}
	else {
		pre->right = s;
	}
	return r;
}
void inOrder(BSTree r)
{
	if (r == NULL)
	{
		return;
	}
	inOrder(r->left);
	cout << r->data << endl;
	inOrder(r->right);
}
void find(BSTree r, int x)
{
	BSTNode* p = r;
	while (p != NULL)
	{
		if (x == p->data)
		{
			cout << "存在" << endl;
			break;
		}
		if (x < p->data)
		{
			p = p->left;
		}
		if (x > p->data)
		{
			p = p->right;
		}
	}
	if (p == NULL)
	{
		cout << "不存在" << endl;
	}
}
int main()
{
	int n;
	int a[105];
	cin >> n;
	for (int i = 1; i <= n; i++)
	{
		cin >> a[i];

	}
	BSTree r = NULL;
	//-----递归版 不单独初始化根节点------------ 
		 /*
		 for(int i=1;i<=n;i++)
		{
			r=insert(r,a[i]);
		}
		 */
		 //-----递归版 单独初始化根节点------------- 
			  /*
			  r=initBST(a[1]);
			  for(int i=2;i<=n;i++)
			 {
				 r=insert(r,a[i]);
			 }
			 */
			 //------非递归版 ------------------ 
	for (int i = 1; i <= n; i++)
	{
		r = insert_1(r, a[i]);
	}
	//--------------------------- 
	inOrder(r);//中序遍历输出验证 
	cout << endl;
	//查找 
	int x;
	cin >> x;
	find(r, x);

	return 0;
}
/*
9
8 3 10 1 6 14 4 7 13
*/

删除操作

首先要找到要删除的结点p,同时找p的父亲结点pre

在删除的过程,分为三种情况

1)如果p的度为2:在删掉p后,将p的左子树的最靠右的结点m或者是右子树最靠左的结点n移动到删除位置(相当于p的前驱或者是后继),而左子树的最靠右的结点m或者是右子树最靠左的结点n一定是度为0或1的结点

这样的话我们就可以把问题转化为将mn的数据复制到要删除的数据位置来代替,在将mn的原来位置的结点删除

2)如果p的度为1:直接让pre指向p的指针指向p的孩子(即将p删除后,让p唯一的孩子顶替p的位置)

3)如果p的度为0:直接删除

注意:这里度为0的情况我们也可以看作度为1的情况去处理,认为他也右一个孩子,只不过一个孩子是NULL孩子

递归查找的思路:在以r为根节点的树中,删除数据x----->递归

(1)x<r->data:问题转化为在以r->left为根的子树上删除x

(2)x>r->data :问题转化为在以r->right为根的子树上删除x

(3)x==r->data:r就是要被删除的节点,去根据r的度 判断如何删除

BSTNode* find_leftmaxx(BSTree p)
{
	while (p->right != NULL)
	{
		p = p->right;
	}
	return p;
}
BSTree delet(BSTree r, int k)
{
	if (k < r->data)
	{
		r->left = delet(r->left, k);
	}
	if (k > r->data)
	{
		r->right = delet(r->right, k);
	}
	if (k == r->data)
	{//r就是要被删除的节点 
		if (r->left != NULL && r->right != NULL)
		{//r的度为2
			//找到r的左子树中最靠右的节点
			BSTNode* lmaxx = find_leftmaxx(r->left);
			r->data = lmaxx->data;
			r->left = delet(r->left, lmaxx->data);//删掉顶替的节点 
		}
		else
		{//r的度为1/0(0也看成1) 
			BSTNode* p = r;
			if (r->left != NULL)
			{
				r = r->left;
			}
			else
			{
				r = r->right;
			}
			free(p);
			p = NULL;
		}

	}
	return r;//返回删除后的新树 
}
整体代码:
#include <iostream>
using namespace std;
//二叉链表存树
typedef struct BSTnode {
	int data;
	struct BSTnode* left;
	struct BSTnode* right;
}BSTNode, * BSTree;
BSTree initBST(int k)
{
	BSTree r = (BSTNode*)malloc(sizeof(BSTNode));
	//if(r==NULL)
	r->data = k;
	r->left = r->right = NULL;
	return r;
}
BSTree insert(BSTree r, int k)
{
	if (r == NULL)
	{
		BSTree s = (BSTNode*)malloc(sizeof(BSTNode));
		//if(s==NULL)
		s->data = k;
		s->left = s->right = NULL;
		return s;
	}
	if (k < r->data)
	{
		r->left = insert(r->left, k);
	}
	if (k > r->data)
	{
		r->right = insert(r->right, k);
	}
	return r;
}
//-----------非递归-------
BSTree insert_1(BSTree r, int k)
{
	BSTree s = (BSTNode*)malloc(sizeof(BSTNode));
	//if(s==NULL)
	s->data = k;
	s->left = s->right = NULL;
	//空树插入 
	if (r == NULL)
	{
		return s;
	}
	//非空树插入 
	BSTNode* p = r;//遍历
	BSTNode* pre = NULL;//p的父亲
	//遍历找插入位置 
	while (p != NULL)
	{
		if (k < p->data)
		{
			pre = p;
			p = p->left;
		}
		else {
			pre = p;
			p = p->right;
		}
	}
	//插入 
	if (k < pre->data)
	{
		pre->left = s;
	}
	else {
		pre->right = s;
	}
	return r;
}
void inOrder(BSTree r)
{
	if (r == NULL)
	{
		return;
	}
	inOrder(r->left);
	cout << r->data << endl;
	inOrder(r->right);
}
void find(BSTree r, int x)
{
	BSTNode* p = r;
	while (p != NULL)
	{
		if (x == p->data)
		{
			cout << "存在" << endl;
			break;
		}
		if (x < p->data)
		{
			p = p->left;
		}
		if (x > p->data)
		{
			p = p->right;
		}
	}
	if (p == NULL)
	{
		cout << "不存在" << endl;
	}
}
//-------删除------------------- 
BSTNode* find_leftmaxx(BSTree p)
{
	while (p->right != NULL)
	{
		p = p->right;
	}
	return p;
}
BSTree delet(BSTree r, int k)
{
	if (k < r->data)
	{
		r->left = delet(r->left, k);
	}
	if (k > r->data)
	{
		r->right = delet(r->right, k);
	}
	if (k == r->data)
	{//r就是要被删除的节点 
		if (r->left != NULL && r->right != NULL)
		{//r的度为2
			//找到r的左子树中最靠右的节点
			BSTNode* lmaxx = find_leftmaxx(r->left);
			r->data = lmaxx->data;
			r->left = delet(r->left, lmaxx->data);//删掉顶替的节点 
		}
		else
		{//r的度为1/0(0也看成1) 
			BSTNode* p = r;
			if (r->left != NULL)
			{
				r = r->left;
			}
			else
			{
				r = r->right;
			}
			free(p);
			p = NULL;
		}

	}
	return r;//返回删除后的新树 
}
int main()
{
	int n;
	int a[105];
	cin >> n;
	for (int i = 1; i <= n; i++)
	{
		cin >> a[i];
	}
	BSTree r = NULL;
	//-----递归版 不单独初始化根节点------------ 
		 /*
		 for(int i=1;i<=n;i++)
		{
			r=insert(r,a[i]);
		}
		 */
		 //-----递归版 单独初始化根节点------------- 
			  /*
			  r=initBST(a[1]);
			  for(int i=2;i<=n;i++)
			 {
				 r=insert(r,a[i]);
			 }
			 */
			 //------非递归版 ------------------ 
	for (int i = 1; i <= n; i++)
	{
		r = insert_1(r, a[i]);
	}
	//--------------------------- 
	inOrder(r);//中序遍历输出验证 
	cout << endl;
	//删除 
	int x;
	cin >> x;
	r = delet(r, x);
	inOrder(r);//中序遍历输出验证 
	printf("\n");

	return 0;
}
/*
14
8 6 13 5 7 9 14 1 12 3 11 2 4 10
*/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值