二叉搜索树(BST)

BST(binary search tree)是具有下列性质的二叉树:
1.若左子树不为空,则左子树上所有结点的值均小于它的根结点的值;
2.若右子树不为空,则右子树上所有结点的值均大于它的根结点的值;
3.左、右子树也分别为二叉排序树;
4.没有键值相等的节点。

BST的一些基本操作(添加结点,查找,删除,遍历)
添加:
添加元素elem从根结点开始比较,如果elem比根结点小,与根结点的左子树比较,如果elem比根节点大,与根结点的右子树比较;再以此子树作为根结点。
如此递归下去...
如果找到某结点的左/右子树结点为NULL,则添加到这个结点的左/右子树结点上。
添加新元素后的BST完全满足上述(BST)性质。

查找:
查找元素elem从根结点开始比较,如果elem比根结点小,与根结点的左子树比较,如果elem比根结点大,与根结点的右子树比较;再以此子树作为根结点。
如此递归下去...
相等则查找到。

删除(分3种情况):
1.删除元素elem没有子树,直接删除
2.删除元素elem有一个子树,则elem的父结点指向elem的子树(elem元素被它的子树取代),删除elem结点
3.删除元素elem左右子树完整,有2种方法:
  1)取元素elem结点的右子树中的最小值来取代elem,然后删除elem。
  2)取元素elem结点的左子树中的最大值来取代elem,然后删除elem。
  这样做不会破坏BST的属性。

遍历:
DLR(前序遍历),LDR(中序遍历),LRD(后序遍历) ,是以根结点的位置来决定名称的(D在L与R中间就是中序遍历)。对于BST,中序遍历的结果就是排序(升序)之后的结果。
Level Order Traverse(层序遍历),就是从树的最上层依次想最下层遍历,遍历的过程就是“广度优先搜索”的过程。

BST的属性与操作还是很简单的,只要在纸上多画画就会比较清楚;难点是用递归的方式来表达出来,一不小心就忘记自己丢到哪一层去了...*&#%&$^&*...

详情见代码吧:

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

class binarySearchsTree
{
public:
	binarySearchsTree()
	{
	    //初始化根结点
		root = NULL;
	}

	struct bstNode
	{
	  int data;
	  bstNode *left;
	  bstNode *right;
	};  
    //添加结点
	//添加结点elem从根结点开始比较,如果elem比根结点小,与根结点左子树比较,如果elem比根结点大,与根结点右子树比较;
	//如此递归下去,直到找到某结点的左/右子树结点为NULL,添加到这个结点的左/右子树结点上。
	int add(int elem)
	{
		bstNode *pNode = new bstNode;
		pNode->left = NULL;
		pNode->right = NULL;
		pNode->data = elem;

		if(NULL == root)
		{
			root = pNode;
			return 1;
		}
		
		bstNode *pCurrent = root;
		bstNode *pPreNode;

        //这里也可以用递归
		while(NULL != pCurrent)
		{	
		    //pPreNode临时指针,用于定位到某结点(添加结点elem的父结点);pCurrent在移动过程中最后指向NULL(pPreNode->left/right == pCurrent == NULL).
			pPreNode = pCurrent;			
			if( elem < pCurrent->data)
				pCurrent = pCurrent->left;		
			else 
				pCurrent = pCurrent->right;	  
		}

		if( pPreNode->data > elem)
			pPreNode->left = pNode;
		else 
			pPreNode->right = pNode;	

		return 1;
	} 	

    //find 
	bstNode *find(bstNode* f_root, int elem)
	{
		bstNode *f_node;
		if(NULL == f_root)
		{
			return NULL;
		}
		//递归退出条件
		if(elem == (f_root->data))
		{	  
			return f_root;
		}
		if(elem < f_root->data)
			return find(f_root->left, elem);
		else 
			return find(f_root->right, elem);  	
	}  
	int find(int elem)
	{
	    bstNode *f_node = find(root, elem); 
	    cout<<f_node->data<<endl;
		return 1; 
	}
	
	//delete 
	struct bstNode * deleteElem(struct bstNode *del_root, int elem)
	{
		if(del_root == NULL)
			return del_root;
		//定位删除结点elem的位置
		else if(elem < del_root->data)
			del_root->left = deleteElem(del_root->left, elem);
		else if(elem > del_root->data)
			del_root->right = deleteElem(del_root->right, elem);
		else 
		{
		    //如果删除结点elem没有子树,直接删除
			if(del_root->left == NULL && del_root->right == NULL)
			{
				delete del_root;
				del_root = NULL;
			}
			//如果删除结点elem左子树为NULL(只有右子树),则原elem指针指向下一(右子树)结点,删除原elem元素			
			else if(del_root->left == NULL)
			{
				struct bstNode *tmp = del_root;
				//删除结点elem被它的右子树取代
				del_root = del_root->right;
				delete tmp;
			}
			//如果删除结点elem右子树为NULL(只有左子树),则原elem指针指向下一(左子树)结点,删除原elem元素		
			else if(del_root->right == NULL)
			{
				struct bstNode *tmp = del_root;
				del_root = del_root->left;
				delete tmp;
			}
			//删除结点elem有左、右子树
			else 
			{
			    //查找右子树的最小值
				struct bstNode *tmp = findMin(del_root->right);
				//struct bstNode *tmp = findMax(del_root->left);
				del_root->data = tmp->data;
				//这里“很巧妙”,递归查找该删除的元素tmp->data,此时的tmp->data是没有子树的结点,将会被直接删除
				del_root->right = deleteElem(del_root->right, tmp->data);
			}
		}
		return del_root;
	} 
    //找最小值,最小值一定在左子树,且它的左子树为空	
	bstNode* findMin(bstNode* root) 
	{
		static bstNode* pre_node;
		if(root == NULL) 
		{
			return pre_node;
		}
		else 
		{
			pre_node = root;
			return findMin(root->left);
		}
	}  
 
	void deleteElem(int elem)
	{
		deleteElem(root,elem);
		cout<<endl;
	}  
	
	//traverse
	int LDR_traverse(bstNode* ldr_root)
	{
		if(NULL != ldr_root)
		{
			LDR_traverse(ldr_root->left);
			cout<<ldr_root->data<<" ";
			LDR_traverse(ldr_root->right);	
		}   
		return 1;
	}  
	void LDR_traverse()
	{
		LDR_traverse(root);
		cout<<endl;
	}
    
	//层序遍历二叉树,即广度优先。  
	//从根结点开始遍历,存入队列;出队列,遍历此结点左子树,有值,存入队列,再遍历此结点右子树,有值,存入队列;
	//递归:出队列,遍历此结点左子树,有值,存入队列,再遍历此结点右子树,有值,存入队列;
	int level_traverse()  
	{  
		if(root == NULL)  
		{  
			return 0;  
		}  
	  
		deque<bstNode *> dequesTree;  
		dequesTree.push_back(root);  
	  
		while(dequesTree.size())  
		{  
			bstNode *p = dequesTree.front();  
			dequesTree.pop_front();  
	  
			cout << (p->data)<<" ";
	  
			if(p->left)  
			{  
				dequesTree.push_back(p->left);  
			}  
			if(p->right)  
			{  
				dequesTree.push_back(p->right);  
			}  
		}  
		cout<<endl;
	}  	  
private:
	bstNode *root;
};

int main()
{
	binarySearchsTree oBST;
	int data[11] = {7,3,9,10,1,4,15,5,19,8,11};
	for(int i=0; i<11; i++)
	{	
	//init
	oBST.add(data[i]);
	}  
	oBST.LDR_traverse();

	//find 
	oBST.find(8);

	//add
	oBST.add(16);
	oBST.LDR_traverse();	
	oBST.level_traverse();

	//delete  
	oBST.deleteElem(7);
	oBST.LDR_traverse();
	oBST.level_traverse();
	return 1;
}


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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值