二叉查找树的实现

实现一个简单的二叉查找树,支持常规操作。

代码如下:

#ifndef _BINARYSEARCHTREE_
#define _BINARYSEARCHTREE_

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

template <typename T>
class BinarySearchTree
{
private:
	struct BinarySearchTreeNode
	{
		T key;
		BinarySearchTreeNode* left;
		BinarySearchTreeNode* right;
		BinarySearchTreeNode(): left(NULL),right(NULL) {}
		BinarySearchTreeNode(const T& v, BinarySearchTreeNode* l,BinarySearchTreeNode* r): key(v),left(l),right(r) {}
	};

public:
	BinarySearchTree(): root(NULL) {}
	~BinarySearchTree() { Clear(); }
	BinarySearchTree( const BinarySearchTree& rhs) : root(NULL) { operator=(rhs); }
	const BinarySearchTree& operator= ( const BinarySearchTree& rhs)
	{
		if( this != &rhs )
		{
			this->Clear();
			this->Copy(root,rhs.root);
		}
		return *this;
	}

	bool Contains( const T& v) const
	{
		return Contains(root,v);
	}

	bool IsEmpty() const { return root == NULL; }
	void PrintTree() const { PrintTree(root); }
	const T& FindMin() const
	{
		if(IsEmpty())
			throw logic_error("Tree is empty");

		BinarySearchTreeNode* targetNode = FindMin(root);
		return targetNode->key;
	}
	const T& FindMax() const
	{
		if(IsEmpty())
			throw logic_error("Tree is empty");

		BinarySearchTreeNode* targetNode = FindMax(root);
		return targetNode->key;
	}

	void Clear()
	{
		Clear(root);
		root= NULL;
	}

	void Insert(const T& v)
	{
		Insert(root,v);
	}

	void Remove(const T& v)
	{
		Remove(root,v);
	}

private:
	void Clear(BinarySearchTreeNode* subroot);
	void Copy(BinarySearchTreeNode* &subroot,BinarySearchTreeNode* source);

	void Insert(BinarySearchTreeNode* & subroot,const T& v);
	void Remove(BinarySearchTreeNode* & subroot, const T& v);

	BinarySearchTreeNode* FindMin(BinarySearchTreeNode* subroot) const
	{
		if( subroot == NULL )
			return NULL;

		while( subroot->left != NULL)
			subroot = subroot->left;

		return subroot;
	}

	BinarySearchTreeNode* FindMax(BinarySearchTreeNode* subroot) const
	{
		if( subroot == NULL )
			return NULL;

		while( subroot->right != NULL )
			subroot = subroot->right;

		return subroot;
	}

	void PrintTree(BinarySearchTreeNode* subroot) const;
	bool Contains(BinarySearchTreeNode* subroot,const T& v) const;

private:
	BinarySearchTreeNode* root;
};

template <typename T>
void BinarySearchTree<T>::Copy(BinarySearchTreeNode* &subroot,BinarySearchTreeNode* source)
{
	if(source != NULL)
	{
		subroot = new BinarySearchTreeNode(source->key,NULL,NULL);
		Copy(subroot->left,source->left);
		Copy(subroot->right,source->right);
	}
}

template <typename T>
void BinarySearchTree<T>::Clear(BinarySearchTreeNode* subroot)
{
	if(subroot != NULL )
	{
		Clear(subroot->left);
		Clear(subroot->right);
		delete subroot;
	}
}

template <typename T>
void BinarySearchTree<T>::PrintTree(BinarySearchTreeNode* subroot) const
{
	if( subroot != NULL )
	{
		PrintTree(subroot->left);
		cout << subroot->key << ",";
		PrintTree(subroot->right);
	}
}

template <typename T>
bool BinarySearchTree<T>::Contains(BinarySearchTreeNode* subroot,const T& v) const
{
	if( subroot == NULL )
		return false;
	else if ( v < subroot->key )
		return Contains(subroot->left,v);
	else if ( subroot->key < v)
		return Contains(subroot->right,v);
	else
		return true;
}

template <typename T>
void BinarySearchTree<T>::Insert(BinarySearchTreeNode* & subroot,const T& v)
{
	if( subroot == NULL )
		subroot = new BinarySearchTreeNode(v,NULL,NULL);
	else if ( v < subroot->key )
		Insert(subroot->left,v);
	else if( subroot->key < v)
		Insert(subroot->right,v);
	else
		// Don't handle duplicate key at here
		// Because duplicate key will increase the overall tree height obviously
		// So it is not a good way to save same keys in one single binary search tree
		// we can keep a list to store all values related same key in somewhere else
		throw logic_error("Duplicate key");
}

template <typename T>
void BinarySearchTree<T>::Remove(BinarySearchTreeNode* & subroot, const T& v)
{
	if( subroot == NULL )
		return;
	else if( v < subroot->key )
		return Remove(subroot->left,v);
	else if( subroot->key < v)
		return Remove(subroot->right,v);
	else if( subroot->left != NULL && subroot->right != NULL )
	{
		BinarySearchTreeNode* successor = FindMin(subroot->right);
		subroot->key = successor->key;
		Remove(subroot->right,successor->key);
	}
	else
	{
		BinarySearchTreeNode* oldNode = subroot;
		if( subroot->left != NULL )
			subroot = subroot->left;
		else
			subroot = subroot->right;

		delete oldNode;
	}
}

#endif

这里的公共函数,基本都是通过调用内部的私有递归函数来实现的。

注意Insert和Remove方法都是采用的指向节点指针的引用,这样可以达到在递归调用里面直接修改主调函数中的指针值的目的。Insert很直观,找到对应的空节点,然后创建一个新的节点挂接上去。

Remove要麻烦一点,需要区分几种情况,比如要被删除的目标节点 (1)无子节点 (2) 仅有左子结点 (3) 仅有右子结点  (4) 有左右子节点,前三种情况都很好处理,删除该节点,然后把对应的子节点挂接到它的父节点对应的位置。最后一种情况要复杂点,一般的做法是,找到目标节点的后继节点(也就是它的右子树中的最小节点),然后交换目标节点和后继节点的值,最后再删除后继节点,因为这个后继节点肯定是没有左子节点的,所以删除后继节点必然是情况1或者2.


测试代码如下:

void BinarySearchTreeTest1()
{
	BinarySearchTree<int> bst;
	bst.Insert(10);
	bst.Insert(6);
	bst.Insert(18);
	bst.Insert(13);
	bst.Insert(15);
	bst.Insert(8);
	bst.Insert(3);
	bst.PrintTree();
	cout << endl;

	cout << "Contains 15 is " << bst.Contains(15) << endl;
	cout << "Contains 11 is " << bst.Contains(11) << endl;

	cout << "Min is " << bst.FindMin() << endl;
	cout << "Max is " << bst.FindMax() << endl;
	bst.Remove(19);
	bst.PrintTree();
	cout << endl;

	bst.Remove(18);
	bst.PrintTree();
	cout << endl;
	bst.Remove(10);
	bst.PrintTree();
	cout << endl;
	bst.Remove(3);
	bst.PrintTree();
	cout << endl;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值