递归与非递归下二叉查找数的插入·查找和删除

 至于二叉查找数的特性和上述三个操作的具体分析我就不多阐述,具体直接看代码,注释中有解释和部分分析:

    非递归:

#include<iostream>
#include<cstdlib>
using namespace std;
struct Node{
	int key;
	Node *right,*left,*parent;
};
Node *root,*Nil;
//插入 
void insert(int k)
{
	Node *y=Nil;           //y是x的父节点 
	Node *x=root;           //插入新节点时,从根节点不断比较 
	Node *z=(Node *)malloc(sizeof(Node));
	z->key=k;
	z->left=Nil;
	z->right=Nil;
	while(x!=Nil)
	{
		y=x;                //因为下面x节点不断更新为x的左右节点,所以作为x的父节点,y也要不断更新 
		if(z->key<x->key)
			x=x->left;
		else
   		    x=x->right;
	}
	//退出循环时,找到插入的位置,就是x的空节点位置插入z作为叶子节点,y就是z的父节点
	z->parent=y; 
	
	//防止在第一次插入时,树还未建立,这时新插入的节点z就是根节点 
	if(y==Nil)
	    root=z;
	else if(z->key<y->key)
	   y->left=z;
	else y->right=z;
}
//根据值查找节点 ,找到则返回该节点,找不到返回Nil 
Node* search(int key)
{
	Node* cur=root;
	while(cur!=Nil && cur->key!=key)
	{
		if(key<cur->key)
		   cur=cur->left;
		else
		    cur=cur->right;
	}
	return cur;
}
//以curRoot为根的数中查找值最小的节点的值 
Node* finMin(Node *curRoot)
{
	if(curRoot==Nil) return Nil; //当前树为空 ,返回-1表示找不到 
	
	while(curRoot->left!=Nil)
	{
		curRoot=curRoot->left;
	}
	return curRoot;
}
//查找指定值的节点的父节点 
Node* findParent(int key)
{
	Node *result=Nil;
	if(root==Nil) return Nil; //当前树为空 ,返回空表示找不到 
	
	Node *p=Nil;     //p指向curRoot父节点 
	Node *cur=root;
	while(cur!=Nil && cur->key!=key)
	{
		p=cur;
		if(key<cur->key)
		  cur=cur->left;
		else
		cur=cur->right;
	}
	if(cur!=Nil)
	  return p;
	else
	return Nil;           //找不到要找父节点的该值 
}
bool deleteOk=true;
//删除树中指定的值 
void deleteNode(int key)
{
	//查找要删除值所在的节点 
	Node *target=search(key);
	Node *targetNode;
	if(target==Nil)
	{
		//cout<<"找不到要删除的节点\n";
		deleteOk=false;
		return ;
	} 
	//要删除的值所在的节点存在左右子树 
	if(target->left==Nil || target->right==Nil)  //要删除的值所在的节点的左右子树最多只存在一个  
		targetNode=target;   //这时要删除的节点就是该节点
	else    
		{
			 //要删除的值所在的节点的左右子树都存在 ,那么其实真正删除的节点是删除的值所在节点的右子树中最小值所在的节点
			 //该节点没有左子树 
			 //该右子树存在的情况下那么 finMin(target)不会返回空 
			 targetNode=finMin(target->right);
			 //cout<<targetNode->key<<":"<<(targetNode==Nil)<<endl;
		}
		
		//接下来的操作就是真正删除节点,该节点最多只有一个子树
		Node *kk;
		if(targetNode->left!=Nil)
		   kk=targetNode->left;
		else
		     kk=targetNode->right;
		 
	    if(kk!=Nil)     //存在一个子树,则该子树的父节点直接指向要删除节点的父节点
		   kk->parent= targetNode->parent;
	    //else
	    //{}               //不存在子树,则不用管子树的父节点
		
		//下面开始targetNode父节点的子树
		if(targetNode->parent==Nil)  //targetNode不存在父节点,那么说明要删除的节点就是根节点 
		  root=kk;
		else if(targetNode==targetNode->parent->left)   //如果要删除的节点是其父节点的左子树 
          targetNode->parent->left=kk;   
        else                //如果要删除的节点是其父节点的右子树 
          targetNode->parent->right=kk;
          
        if(targetNode!=target)
        {
        	 //将原来要删除值所在节点的额值替换成右子树中最小的值 
        	target->key=targetNode->key;
        }
}
void inOrder(Node *u)
{
	if(u==Nil)return ;
	inOrder(u->left);
	cout<<u->key<<" ";
	inOrder(u->right);
}

void preOrder(Node *u)
{
	if(u==Nil)return ;
	cout<<u->key<<" ";
	preOrder(u->left);;
	preOrder(u->right);
}
int main()
{
	cout<<"非递归方法:"<<endl;
	int n,temp;
	cout<<"输入树的节点个数:\n";
	cin>>n;
	
	cout<<"依次输入树的节点的值:\n";
	for(int i=0;i<n;i++)
	{
		cin>>temp;
		insert(temp);
	}
	
	cout<<"\ninOrder:";
	inOrder(root);
	cout<<endl;
	cout<<"preOrder:";
    preOrder(root);
	cout<<endl;cout<<endl;
	
	int key;
	cout<<"输入一个要查找的节点的值:\n";
	cin>>key;
	Node* find=search(key);
	if(find)
	  	//cout<<"Yes "<<"key.left="<<find->left->key<<" key.right="<<find->right->key<<endl;   //测试使用 
	  	cout<<"Yes"<<endl; 
    else
	    cout<<"No"<<endl; 
	    
    //cout<<"findParent(12)->key:"<<findParent(12)->key<<endl;
	//cout<<"search(12)->parent->key:"<<search(12)->parent->key<<endl;
	
	/*insert(30);
	insert(88);
	insert(12);
	insert(1);
	insert(20);
	insert(17);
	insert(25);
	
	cout<<"\ninOrder:";
	inOrder(root);
	cout<<endl;
	cout<<"preOrder:";
    preOrder(root);
	cout<<endl;cout<<endl;*/       //测试使用 
	
	int k;
    cout<<"输入一个要删除的节点的值:\n";
    cin>>k;
    deleteNode(k);
    if(deleteOk)cout<<"删除成功!";
    else cout<<"找不到要删除的节点!";
    
    cout<<"上述操作后:\n";
    cout<<"\ninOrder:";
	inOrder(root);
	cout<<endl;
	cout<<"preOrder:";
    preOrder(root);
	cout<<endl;cout<<endl;
	
	return 0;	
}

递归:

#include<iostream>
#include<cstdlib>
using namespace std;
struct Node{
	int key;
	Node *right,*left;
};
Node *root,*Nil;
//在以curRoot为根的树中插入值为k的新节点 并返回这颗新树的根节点 
Node* insert(Node *curRoot,int k)
{
	//找到空节点,根据值k产生叶子节点 
	if(curRoot==Nil) 
	{
		curRoot=(Node *)malloc(sizeof(Node));
	    curRoot->key=k;
	    curRoot->left=Nil;
	    curRoot->right=Nil;
		return curRoot;
	}
	if(k<curRoot->key)
	   curRoot->left=insert(curRoot->left,k);
	else
	   curRoot->right=insert(curRoot->right,k);
	return curRoot; 
}

//一般查找:在以 curRoot为根的一般二叉树中查找值为k的节点       --适用于所有的二叉树 
Node* search1(Node *curRoot,int k)
{
	//找到了最后叶子节点的空节点,则未找到,返回空 
	if(curRoot==Nil) 
		return Nil;
    	
    //该树的根节点的值等于k,直接返回该节点 
	if(curRoot->key==k)
		return curRoot;
	    
    //对于一一般树,根节点和其左右子树大小关系不确定,所以要分别在左右子树中查找 
    Node *find_left=search1(curRoot->left,k);
    Node *find_right=search1(curRoot->right,k);
    //在哪课树中找到该节点,直接返回 
    if(find_left) return find_left;
    else if(find_right) return find_right;
    //左右子树都找不到该节点,返回空 
 	return Nil; 
}

//特殊查找:在以 curRoot为根的二叉搜索树中查找值为k的节点       --仅适用于二叉搜索树 
Node* search2(Node *curRoot,int k)
{
	//找到了最后叶子节点的空节点,则未找到,返回空 
	if(curRoot==Nil) 
		return Nil;
    	
    //该树的根节点的值等于k,直接返回该节点 
	if(curRoot->key==k)
		return curRoot;
	
	//根据查找的值k和当前树的根节点值大小关系,只在左子树或者右子树中查找 
	if(k<curRoot->key)
       return search2(curRoot->left,k);
    else
       return search2(curRoot->right,k);
}
//以curRoot为根的数中查找值最小的节点 
Node *finMin(Node *curRoot)
{
	if(curRoot==Nil) return Nil; //当前树为空 ,返回空 
	else if(curRoot->left==Nil)   //右子树为空,则根节点就是最小的元素 
	   return curRoot;
	return finMin(curRoot->left);   //右子树不空,在右子树返回最小值 
}

bool deleteOk=true;
//在以curRoot为根的数中删除值为key的节点 
Node* deleteNode(Node *curRoot,int key)
{
	
	if(curRoot==Nil)      //找不到要删除的元素
	   {
	   	 //cout<<"Nil\n";
	   	 deleteOk=false;
	   	 return curRoot;
	   }
	   //cout<< curRoot->key<<endl;
	if(key<curRoot->key)
	{
		curRoot->left=deleteNode(curRoot->left,key);  //要删除的元素在左子树中 
	}
	else if(key>curRoot->key)
	{
		curRoot->right=deleteNode(curRoot->right,key);  //要删除的元素在右子树中 
	}
	else  if(curRoot->right!=Nil && curRoot->left!=Nil)//当前树的根节点就是要删除的节点 并且左右子树都有 
	{
		//cout<<"min-----"<<endl;
		//找到要删除节点右子树中最小值以替代当前要删除的节点 ,该右子树中最小节点肯定是最多只有一个孩子 
		// 这里curRoot->right不为空, 根本不用判断 finMin返回值为空 
		curRoot->key=finMin(curRoot->right)->key;
		//cout<<"curRoot->key:"<<curRoot->key<<endl;;
	    curRoot->right= deleteNode(curRoot->right,curRoot->key);//删除右子树中最小节点 
	    //cout<<"min-----"<<endl;
	}
	else//要删除的节点只有一个孩子或者是叶子节点 
	{
		curRoot=(curRoot->left!=Nil)?curRoot->left:curRoot->right;
	}
	return curRoot;
}
void inOrder(Node *u)
{
	if(u==Nil)return ;
	inOrder(u->left);
	cout<<u->key<<" ";
	inOrder(u->right);
}

void preOrder(Node *u)
{
	if(u==Nil)return ;
	cout<<u->key<<" ";
	preOrder(u->left);
	preOrder(u->right);
}
int main()
{
	cout<<"递归方法:"<<endl;
	
	int n,temp;
	cout<<"输入树的节点个数:\n";
	cin>>n;
	
	cout<<"依次输入树的节点的值:\n";
	for(int i=0;i<n;i++)
	{
		cin>>temp;
		root=insert(root,temp);
	}
	
	cout<<"\ninOrder:";
	inOrder(root);
	cout<<endl;
	cout<<"preOrder:";
    preOrder(root);
	cout<<endl;cout<<endl;
	 
	int key;
	cout<<"输入一个要查找的节点的值:\n";
	cin>>key;
	Node* find=search2(root,key);
	if(find)
	  	//cout<<"Yes"<<"key.left="<<find->left->key<<" key.right="<<find->right->key<<endl;   //测试使用 
	  	cout<<"Yes"<<endl;
    else
	    cout<<"No"<<endl;
	
	    
	/*root=insert(root,30);
	root=insert(root,88);
	root=insert(root,12);
	root=insert(root,1);
	root=insert(root,20);
	root=insert(root,17);
	root=insert(root,25);
	
	cout<<"\ninOrder:";
	inOrder(root);
	cout<<endl;
	cout<<"preOrder:";
    preOrder(root);
	cout<<endl;cout<<endl;*/               //测试使用 
	
	
	int k;
    cout<<"输入一个要删除的节点的值:\n";
    cin>>k;
    deleteNode(root,k);
    if(deleteOk)cout<<"删除成功!";
    else cout<<"找不到要删除的节点!";
    
    cout<<"上述操作后:\n";
    cout<<"\ninOrder:";
	inOrder(root);
	cout<<endl;
	cout<<"preOrder:";
    preOrder(root);
	cout<<endl;cout<<endl;
	return 0;	
}

PS:自己零零散散写了两天,根据书上非递归形式写出递归形式,新手建议收藏,大神请绕路~

点赞