(数据结构笔记)二叉查找树的实现

二叉查找树是一种比较基础的数据结构,其优化后可以变成AVL树,红黑树,treap树等等较为高效的树。使二叉树成为二叉查找树的方法是:对于树中的每个节点,使其左子树中的所有项均小于该节点,其右子树中的所有项均大于该节点。

二叉查找树可以利用递归较为简单地实现,其具体的定义和算法可以很方便地查询得到,故不再赘述。

二叉查找树应具有的公有成员函数:

1.contains(x):如果树中有值为x的节点,则返回true。

2.empty():如果树为空,返回true。

3.insert(x):在树中的恰当位置插入x节点,如果x已存在则什么也不做。

4.remove(x):删除树中x节点,如果x不存在则什么也不做。

5.findmin():返回树中的最小值。

6.findmax():返回树中的最大值。

7.make_empty():清空树。

8.print_tree():递增地打印树中节点(中序历遍)。

二叉查找树的实现框架:

<span style="font-size:14px;">template<typename T>
class BinarySearchTree{
public:
	BinarySearchTree() = default;
	BinarySearchTree(const BinarySearchTree&);
	~BinarySearchTree();
	const BinarySearchTree& operator=(const BinarySearchTree &);

	bool contains(const T&);
	bool empty();
	const T& findmin();
	const T& findmax();
	void insert(const T&);
	void remove(const T&);
	void make_empty();
	void print_tree();
private:
	struct BinaryNode {                         //接口类
		T element;
		BinaryNode *left;
		BinaryNode *right;
		BinaryNode(const T& elem, BinaryNode * l, BinaryNode * r) :
			element(elem), left(l), right(r) {}
	};
	BinaryNode *root;
	bool contains(const T&,BinaryNode*);
	BinaryNode * findmin(BinaryNode*);
	BinaryNode * findmax(BinaryNode*);
	void insert(const T&, BinaryNode*&);
	void remove(const T&, BinaryNode*&);
	void make_empty(BinaryNode*&);
	void print_tree(BinaryNode*);
	BinaryNode * clone(BinaryNode*);            //递归实现拷贝
};</span>


contains、empty函数的实现

这两个函数较为简单,contains就是简单的调用递归查找。

<span style="font-size:14px;">template<typename T>
bool BinarySearchTree<T>::contains(const T& elem) {
	return contains(elem, root);
}

template<typename T>
bool BinarySearchTree<T>::contains(const T& elem, BinaryNode * bin) {
	if (bin == nullptr)
		return false;
	if (bin->element < elem)
		return contains(elem, bin->right);
	else if (bin->element >elem)
		return contains(elem, bin->left);
	else
		return true;
}

template<typename T>
bool BinarySearchTree<T>::empty() {
	if (root == nullptr)
		return true;
	return false;
}</span>

findmin、findmax函数以及print_tree函数的实现

前两个函数虽然可以简单地利用递归查找,但是我们应该尽量避免使用尾递归,所以使用while语句代替递归调用。

另外就是注意处理空树的情况。

<span style="font-size:14px;">template<typename T>
const T & BinarySearchTree<T>::findmin() {
	return findmin(root)->element;
}


template<typename T> typename
BinarySearchTree<T>::BinaryNode * 
BinarySearchTree<T>::findmin(BinaryNode *bin) {
	if (bin == nullptr)
		return nullptr;
	while (bin->left != nullptr)
		bin = bin->left;
	return bin;
}

template<typename T>
const T & BinarySearchTree<T>::findmax() {
	return findmax(root)->element;
}
template<typename T> typename
BinarySearchTree<T>::BinaryNode *
BinarySearchTree<T>::findmax(BinaryNode* bin) {
	if (bin == nullptr)
		return nullptr;
	while (bin->right != nullptr)
		bin = bin->right;
	return bin;
}template<typename T>
void BinarySearchTree<T>::print_tree() {
<span style="white-space:pre">	</span>print_tree(root);
}

template<typename T>
void BinarySearchTree<T>::print_tree(BinaryNode *bin) {
<span style="white-space:pre">	</span>if (bin != nullptr) {
<span style="white-space:pre">		</span>print_tree(bin->left);
<span style="white-space:pre">		</span>std::cout << bin->element<<" ";
<span style="white-space:pre">		</span>print_tree(bin->right);
<span style="white-space:pre">	</span>}
}</span>

insert、remove以及make_empty函数的实现

insert与contains的思路比较相似。

remove分两种情况:一是处理具有两个子树的节点,有两种方式,利用其右子树的最小节点(或是利用其左子树的最大节点)代替该节点并递归地删除那个节点。二是单子树或是无子树的节点,可以将子树绕过该节点链接到父节点,然后删除该节点。

特别要注意的是,因为这三个函数对树进行了插入或删除的操作,所以参数要使用引用类型,否则会出现错误。


<span style="font-size:14px;">template<typename T>
void BinarySearchTree<T>::insert(const T& elem) {                 
	insert(elem,root);
}

template<typename T>
void BinarySearchTree<T>::insert(const T& elem, BinaryNode* &bin) {
	if (bin == nullptr) {
		bin = new BinaryNode(elem, nullptr, nullptr);
	}
	else if (bin->element < elem) {
		insert(elem, bin->right);
	}
	else if (bin->element > elem) {
		insert(elem, bin->left);
	}
	                             //如果找到elem,什么也不做
}

template<typename T>
void BinarySearchTree<T>::remove(const T& elem) {
	remove(elem, root);
}

template<typename T>
void BinarySearchTree<T>::remove(const T& elem,BinaryNode* &bin) {
	if (bin == nullptr)                                       //找不到elem,什么也不做
		return;
	if (elem > bin->element)
		remove(elem, bin->right);
	else if (elem < bin->element)
		remove(elem, bin->left);
	else if (bin->left != nullptr && bin->right != nullptr) {   //删除拥有两个子树的节点
		auto t = findmin(bin->right);
		bin->element = t->element;
		remove(t->element, t);
	}
	else {                                                       //删除树叶或单子树节点
		auto old = bin;
		bin = (bin->left != nullptr) ? bin->left : bin->right;
		delete old;
	}
}

template<typename T>
void BinarySearchTree<T>::make_empty() {
	make_empty(root);
}

template<typename T>
void BinarySearchTree<T>::make_empty(BinaryNode* &bin) {
	if (bin != nullptr) {
		make_empty(bin->left);
		make_empty(bin->right);
		delete bin;
		bin = nullptr;
	}
}</span>

最后是拷贝构造函数、析构函数和拷贝赋值运算符

使用了clone工具函数来实现递归操作。

<span style="font-size:14px;">template<typename T> typename
BinarySearchTree<T>::
BinaryNode * BinarySearchTree<T>::clone(BinaryNode* bin) {
	if (bin == nullptr)
		return nullptr;
	return new BinaryNode(bin->element, clone(bin->left), clone(bin->right));
}

template<typename T>
BinarySearchTree<T>::
BinarySearchTree(const BinarySearchTree& bin) {
	root=clone(bin.root);                                         //同类或友元中可访问private成员
}


template<typename T>
inline BinarySearchTree<T>::~BinarySearchTree() {
	make_empty();
}
template<typename T> typename
const BinarySearchTree<T>& BinarySearchTree<T>::operator=(const BinarySearchTree & bin) {
	if (*this != bin) {
		make_empty();
		root = clone(bin.root);
	}
	return *this;
}</span>


新手一枚,望各位大大多提意见!



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值