剑指offer---二叉搜索树的实现(重点是删除)

二叉搜索树相比于其他数据结构的优势在于查找、插入的时间复杂度较低,插入的时间复杂度为O(log n), 二叉搜索树是基础性的数据结构,用于构建更为抽象的数据结构,如集合、multiset、关联数组等。

二叉搜索树的查找、插入、删除的时间复杂度等于树高的期望O(log n),最差时间复杂度为O(n)(数组有序,树退化成线性表)。

二叉搜索数的操作中的难点是二叉搜索树中特定节点的删除。在二叉搜索树中删除一个节点,分三种情况讨论:

1. *p结点为叶子结点,即PL(左子树)PR(右子树)均为空树。由于删去叶子结点不破坏整棵树的结构,则只需修改其双亲结点的指针即可。

2. 若*p结点只有左子树PL或右子树PR,此时只要令PLPR直接成为其双亲结点*f的左子树(当*p是左子树)或右子树(当*p是右子树)即可,作此修改也不破坏二叉查找树的 特性。即p=p->left 或者 p=p->right。

3.若*p的左右节点都不为空。在删除*p之后,为保持其他元素之间的相对位置不变,可按中序遍历保持有序进行调整 ,可以有两种做法:

方法(1):令*p的左子树直接为其父节点*f的左子树或右子树(依*p是*f的左孩子还是右孩子而定),若设*s为待删节点*p左子树上的最右下的节点(值最大的节点),则还需将*p的右子树变为*s的右子树。

方法(2):设*s为待删节点*p左子树上的最右下的节点(值最大的节点),将节点*s的右子树接到其父节点上,作为其父节点的右子树,而后用节点*s的值替换掉待删节点*p的节点的值。


方法(1)说明代码:

void delete_node1(ptrnode &p)//注意参数必须为引用
{
	ptrnode q,s;
	if(!p->left && !p->right)//when  p is a leaf node;
	{
		q=p;
		p=NULL;
		free(q);
	}
	else if(!p->left)//when p only have rightchild node;
	{
		q=p;
		p=p->right;
		free(q);
	}
	else if(!p->right)//when p only have leftchild node;
	{
		q=p;
		p=p->left;
		free(q);
	}
	else //when p have both leftchild and right child node;
	{
		s=p->left;
		while(s->right!=NULL)
		{
			s=s->right;
		}
		s->right=p->right;
		q=p;
		p=p->left;
		free(q);
	}
}

方法(2)说明代码:

void delete_node2(ptrnode &p)  //注意参数必须为引用
{	
	ptrnode q,s;
	if(!p->left && !p->right)//when  p is a leaf node;
	{
		q=p;
		p=NULL;
		free(q);
	}
	else if(!p->left)//when p only have rightchild node;
	{
		q=p;
		p=p->right;
		free(q);
	}
	else if(!p->right)//when p only have leftchild node;
	{
		q=p;
		p=p->left;
		free(q);
	}
	else //when p have both leftchild and right child node;
	{
        s=p->left;
		while(s->right!=NULL)
		{
			q=s;
			s=s->right;
		}
		p->element=s->element;
		if(p!=q)
			q->right=s->left;
		else
			q->left=s->left;
		free(s);
	}
}
注意:这里函数中的参数必须为引用,弄清楚原因


下面是二叉搜索树的完整代码,插入,删除,查找,遍历以及测试用例:

#include<iostream>
using namespace std;

typedef struct Node
{
	int element;
	struct Node * left;
	struct Node * right;	
}TreeNode,*BSTree,*ptrnode;

ptrnode Insert(int x,BSTree &T)
{
	if(NULL==T)
	{
		T=(ptrnode)malloc(sizeof(TreeNode));
		if(T==NULL)
		{
			cout<<"out of space!"<<endl;
			exit(0);
		}
		T->element=x;
		T->left=T->right=NULL;
	}
	else if(x<T->element)
	{
		T->left=Insert(x,T->left);
	}
	else if(x>T->element)
	{
		T->right=Insert(x,T->right);
	}
    return T;
}
ptrnode  Find(int x,BSTree &T)
{
	if(NULL==T)
		return NULL;
	if(x<T->element)
		return Find(x,T->left);
	else if(x>T->element)
		return Find(x,T->right);
	else
		return T;
}
ptrnode FindMin(int x,BSTree &T)
{
	if(NULL==T)
		return NULL;
	if(NULL==T->left)
		return T;
	else 
		return FindMin(x,T->left);
}
ptrnode FindMax(int x,BSTree &T)
{
	if(NULL==T)
		return NULL;
	if(NULL==T->right)
		return T;
	else
		return FindMax(x,T->right);
}
void delete_node1(ptrnode &p)//注意参数必须为引用
{
	ptrnode q,s;
	if(!p->left && !p->right)//when  p is a leaf node;
	{
		q=p;
		p=NULL;
		free(q);
	}
	else if(!p->left)//when p only have rightchild node;
	{
		q=p;
		p=p->right;
		free(q);
	}
	else if(!p->right)//when p only have leftchild node;
	{
		q=p;
		p=p->left;
		free(q);
	}
	else //when p have both leftchild and right child node;
	{
		s=p->left;
		while(s->right!=NULL)
		{
			s=s->right;
		}
		s->right=p->right;
		q=p;
		p=p->left;
		free(q);
	}
}
void delete_node2(ptrnode &p)  //注意参数必须为引用
{	
	ptrnode q,s;
	if(!p->left && !p->right)//when  p is a leaf node;
	{
		q=p;
		p=NULL;
		free(q);
	}
	else if(!p->left)//when p only have rightchild node;
	{
		q=p;
		p=p->right;
		free(q);
	}
	else if(!p->right)//when p only have leftchild node;
	{
		q=p;
		p=p->left;
		free(q);
	}
	else //when p have both leftchild and right child node;
	{
        s=p->left;
		while(s->right!=NULL)
		{
			q=s;
			s=s->right;
		}
		p->element=s->element;
		if(p!=q)
			q->right=s->left;
		else
			q->left=s->left;
		free(s);
	}
}
bool delete_BSTree(int x,BSTree &T)//参数必须为引用
{
	if(NULL==T)
		return false;
	else
	{
		if(x<T->element)
			return delete_BSTree(x,T->left);
		else if(x>T->element)
			return delete_BSTree(x,T->right);
		else
		{
			//delete_node1(T);
			delete_node1(T);
			return true;
		}
	}
}
void MakeEmpty(BSTree &T)//destroy the BSTree
{
	if(NULL==T)
		return ;
	else
	{
		if(T->left!=NULL)
			MakeEmpty(T->left);
		if(T->right!=NULL)
			MakeEmpty(T->right);
        free(T);
	}
}
void Preorder_traverse(BSTree &T)
{
	if(T==NULL)
		return;
	else
	{
		cout<<T->element<<" ";
		Preorder_traverse(T->right);
		Preorder_traverse(T->left);
	}
}
void Inorder_traverse(BSTree &T)
{
	
	if(T==NULL)
		return;
	else
	{
		Inorder_traverse(T->left);
		cout<<T->element<<" ";
		Inorder_traverse(T->right);
	}
}
void Postorder_traverse(BSTree &T)
{
	if(T==NULL)
		return;
	else
	{
		Postorder_traverse(T->left);
		Postorder_traverse(T->right);
		cout<<T->element<<" ";
	}
}
//-----------------------------------------------------测试用例 test case
void Test1()// p only have a child node(left child)
{
	BSTree T=NULL;
	T=Insert(6,T);
	T=Insert(2,T);
	T=Insert(8,T);
	T=Insert(1,T);
	T=Insert(4,T);
	T=Insert(3,T);
	cout<<"the inorder_traverse is "<<endl;
	Inorder_traverse(T);
	cout<<endl;
	delete_BSTree(4,T);
	cout<<"after the delete,the inorder_traverse is "<<endl;
	Inorder_traverse(T);
	cout<<endl;
	MakeEmpty(T);
}
void test2()//p have no child
{
	BSTree T=NULL;
	T=Insert(6,T);
	T=Insert(2,T);
	T=Insert(8,T);
	T=Insert(1,T);
	T=Insert(4,T);
	T=Insert(3,T);
	cout<<"the inorder_traverse is "<<endl;
	Inorder_traverse(T);
	cout<<endl;
	delete_BSTree(3,T);//the node 3 is a leaf node
	cout<<"after the delete,the inorder_traverse is "<<endl;
	Inorder_traverse(T);
	cout<<endl;
	MakeEmpty(T);
}
void test3()
{
	BSTree T=NULL;
	T=Insert(6,T);
	T=Insert(2,T);
	T=Insert(8,T);
	T=Insert(1,T);
	T=Insert(5,T);
	T=Insert(3,T);
	T=Insert(4,T);
	cout<<"the inorder_traverse is "<<endl;
	Inorder_traverse(T);
	cout<<endl;	
	delete_BSTree(2,T);
	cout<<"after the delete,the inorder_traverse is "<<endl;	
	Inorder_traverse(T);
	cout<<endl;
	cout<<"after the delete,the preorder_traverse is "<<endl;
	Preorder_traverse(T);
	cout<<endl;
	cout<<"after the delete,the postorder_traverse is "<<endl;
	Postorder_traverse(T);
	cout<<endl;
}
int main(void)
{
	cout<<"----------------------------------------test case1"<<endl;
	Test1();
	cout<<"----------------------------------------test case2"<<endl;
	test2();
	cout<<"----------------------------------------test case3"<<endl;
	test3();
	return 0;
}

运行结果:





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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值