欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

程序员文章站 2022-06-05 17:14:07
...

查找二叉树:
一、定义

*:
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; 
} 

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