二叉查找树--插入、查找、遍历、打印、删除(重点)

查找二叉树:
一、定义

维基百科:
https://zh.wikipedia.org/wiki/%E4%BA%8C%E5%85%83%E6%90%9C%E5%B0%8B%E6%A8%B9
在这里插入图片描述

二、代码:

1、结构体:

struct Node
{
	int value;
	Node *lchild,*rchild;
	Node(int _value)
	{
		value = _value;
		lchild = NULL;
		rchild = NULL;
	}
};

2、搜索元素:
(1)递归:
在这里插入图片描述

Node *search(Node *root,int x) //在二叉查找树中查找关键码(这里是value)的结点
{							   //不成功返回NULL 
	if(root == NULL) return NULL;
	else if(x == root->value)  return root;
	else if(x < root->value) return search(root->lchild,x);
	else return search(root->rchild,x); 
} 

(2)非递归:
成功则返回该结点及其双亲结点,否则返回NULL,father为要插入结点的父结点

Node *search_iter(Node *root,int x,Node *&father)  //非递归算法 
{	//成功则返回该结点及其双亲结点,否则返回NULL,father为要插入结点的父结点 
	Node *p = root;
	father = NULL;
	while(p != NULL && p->value != x)		
	{
		father = p;
		if(x < p->value)
		{
			p = p->lchild;
		} 
		else
		{
			p = p->rchild;
		}
	} 
	return p;
}

3、插入元素:
在这里插入图片描述

bool insert(Node *&root,int x)
{//向以根为*root的二叉查找树插入一个关键码为x的结点,如果root为空插入新结点为根结点 
 //如果已存在则不插入,否则插入,返回插入状态 
	Node *p,*father;
	p = search_iter(root,x,father);
	if(p != NULL)   return false;       //查找成功不插入
	Node *newNode = new Node(x);
	if(root == NULL)  root = newNode;
	else if(x < father->value) father->lchild = newNode;
	else father->rchild = newNode; 

	return true;	
}

4、创建查找二叉树:
通过插入来创建

void createBST(Node *&root,vector<int>values)
{ 
	root = NULL;
	for(int i = 0; i < values.size(); i++)
	{
		insert(root,values[i]);
	}
}

5、水平树形打印:

void printBST(Node *root,int k)
{ 
	if(root != NULL)
	{
		printBST(root->rchild,k+5);	//先打右子树
		for(int i = 0; i < k; i++)
		{
			cout<<" ";
		}
		cout<<root->value<<endl;
		printBST(root->lchild,k+5);
	}
}

6、中序遍历可得到升序序列:

void printOrder(Node *root)
{
	if(root != NULL)
	{
		printOrder(root->lchild);
		cout<<root->value<<",";
		printOrder(root->rchild);
	} 
}

7、删除(最麻烦)😗*

在这里插入图片描述

事实上可以分为两种情况:

(1)被删结点有一个子女或没有一个子女;
(2)被删结点有两个子女;
设被删结点为*p,被删结点的双亲为*father,被删结点的子女为*son(一个,如果一开始时是两个那就处理成一个)**

(1)种情况处理:

(1)种简单点,如果有一个子女,那么:

	if(father->lchild == p)
	{
		father->lchild = son; 
	} 
	else
	{
		father->rchild = son;
	}

如果*p没有子女:

	son = NULL;
	if(father->lchild == p)
	{
		father->lchild = son; 
	} 
	else
	{
		father->rchild = son;
	}

还需要注意的是,被删节点可能是根结点root,那么father = NULL,因此,令root=son即可。

(2)种情况处理:

(2)种就复杂点了,因为如果*p有两个结点那么就得保证在删去*p之后,为保持其它元素之间的相对位置不变,确保查找二叉树的性质不变。有两种方法:
1)*p右子树下找中序遍历时第一个结点,它的值是右子树下最小的;
2)*p的左子树下找中序遍历的最后一个结点,它的值是左子树下最大的;
选其中一种方法,把这个结点的值填充到要删除的结点*p,然后p指向这个结点,father指向这个结点的双亲,son指向这个结点的子女 ( 如果是方法1),这个结点没有左子女;如果是方法2),这个结点没有左右子女,这个结点现在被p指着现在),所以现在被删结点只有一个或没有一个子女了,那么就可以使用第(1)种情况的方法来处理了。

代码实现:


bool deleteNode(Node *&root,int x)    
{//在*root为根结点的二叉查找树中删除关键码为x的结点,删除成功函数返回true,否则返回false
	Node *p;      //指向待删结点 
	Node *son;    //指向待删结点的子女(当然如果都空就是NULL) 
	Node *father; //查找后为待删结点的双亲结点 
	if((p = search_iter(root,x,father)) == NULL) return false;	//查找失败不删除 
	if(p->lchild != NULL && p->rchild != NULL)	//第(2)种情况左右子女不为空 
	{			
		son = p->rchild;	  //找p结点的右子树的中序后继(右子树下值最小的)	
		father = p;
		while(son->lchild != NULL )		//找到退出循环 
		{
			father = son;
			son = son->lchild;
		} //找到时son指向用来代替待删的结点(开始那个有左右结点的子女),father指向该结的双亲 
		p->value = son->value;   //代替 
		p = son;//用 p来指向待删结点,p->lchild = NULL,son下一步指向待删结点的右子女(即使为空) 
	} 
	//son需要指向待删结点的子女(当然如果都空就是NULL) 
	if(p->lchild != NULL) son = p->lchild;	//开始时是单子女(并且是左子女才会执行 
	else son = p->rchild;	//如果一开始p是双子女,在上面也会处理为单子女(左子女为空)
	 
	if(p == root) //如果待删的结点是根结点,只出现在开始就是情况(1) 
	{	//因为如果是一开始是情况(2),在上面处理完后,删的结点肯定是root的子女(子孙)了 
		root = son; 
	}
	else if(father->lchild == p)
	{
		father->lchild = son; 
	} 
	else
	{
		father->rchild = son;
	} 
	delete p;
	return true;
}  

8、全部代码+测试:

#include<iostream>
#include<vector>
using namespace std;

struct Node
{
	int value;
	Node *lchild,*rchild;
	Node(int _value)
	{
		value = _value;
		lchild = NULL;
		rchild = NULL;
	}
};

Node *search(Node *root,int x) //在二叉查找树中查找关键码(这里是value)的结点
{							   //不成功返回NULL 
	if(root == NULL) return NULL;
	else if(x == root->value)  return root;
	else if(x < root->value) return search(root->lchild,x);
	else return search(root->rchild,x); 
} 
Node *search_iter(Node *root,int x,Node *&father)  //非递归算法 
{	//成功则返回该结点及其双亲结点,否则返回NULL,father为要插入结点的父结点 
	Node *p = root;
	father = NULL;
	while(p != NULL && p->value != x)		
	{
		father = p;
		if(x < p->value)
		{
			p = p->lchild;
		} 
		else
		{
			p = p->rchild;
		}
	} 
	return p;
}
bool insert(Node *&root,int x)
{//向以根为*root的二叉查找树插入一个关键码为x的结点,如果root为空插入新结点为根结点 
 //如果已存在则不插入,否则插入,返回插入状态 
	Node *p,*father;
	p = search_iter(root,x,father);
	if(p != NULL)   return false;       //查找成功不插入
	Node *newNode = new Node(x);
	if(root == NULL)  root = newNode;
	else if(x < father->value) father->lchild = newNode;
	else father->rchild = newNode; 
	
	return true;	
}
void createBST(Node *&root,vector<int>values)
{ 
	root = NULL;
	for(int i = 0; i < values.size(); i++)
	{
		insert(root,values[i]);
	}
} 
void printBST(Node *root,int k)
{ 
	if(root != NULL)
	{
		printBST(root->rchild,k+5);
		for(int i = 0; i < k; i++)
		{
			cout<<" ";
		}
		cout<<root->value<<endl;
		printBST(root->lchild,k+5);
	}
}
void printOrder(Node *root)
{
	if(root != NULL)
	{
		printOrder(root->lchild);
		cout<<root->value<<",";
		printOrder(root->rchild);
	} 
}
bool deleteNode(Node *&root,int x)    
{//在*root为根结点的二叉查找树中删除关键码为x的结点,删除成功函数返回true,否则返回false
	Node *p;      //指向待删结点 
	Node *son;    //指向待删结点的子女(当然如果都空就是NULL) 
	Node *father; //查找后为待删结点的双亲结点 
	if((p = search_iter(root,x,father)) == NULL) return false;	//查找失败不删除 
	if(p->lchild != NULL && p->rchild != NULL)	//第(2)种情况左右子女不为空 
	{			
		son = p->rchild;	  //找p结点的右子树的中序后继(右子树下值最小的)	
		father = p;
		while(son->lchild != NULL )		//找到退出循环 
		{
			father = son;
			son = son->lchild;
		} //找到时son指向用来代替待删的结点(开始那个有左右结点的子女),father指向该结的双亲 
		p->value = son->value;   //代替 
		p = son;//用 p来指向待删结点,p->lchild = NULL,son下一步指向待删结点的右子女(即使为空) 
	} 
	//son需要指向待删结点的子女(当然如果都空就是NULL) 
	if(p->lchild != NULL) son = p->lchild;	//开始时是单子女(并且是左子女才会执行 
	else son = p->rchild;	//如果一开始p是双子女,在上面也会处理为单子女(左子女为空)
	 
	if(p == root) //如果待删的结点是根结点,只出现在开始就是情况(1) 
	{	//因为如果是一开始是情况(2),在上面处理完后,删的结点肯定是root的子女(子孙)了 
		root = son; 
	}
	else if(father->lchild == p)
	{
		father->lchild = son; 
	} 
	else
	{
		father->rchild = son;
	} 
	delete p;
	return true;
} 
 
int main()
{
	vector<int>values = {53,17,78,9,45,65,94,23,81,95};
	Node *root  = NULL;
	createBST(root,values);
	printBST(root,0);
	cout<<endl<<endl;
	printOrder(root);
	cout<<endl<<endl;
	deleteNode(root,78);
	printOrder(root);
	cout<<endl<<endl;
	printBST(root,0);
	cout<<endl<<endl;
	return 0; 
} 

在这里插入图片描述

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值