二叉查找树BinarySearchTree(BST)类模板的实现

一、基础理论

1.树

  • 没有儿子的节点称为树叶,具有相同父亲的节点为兄弟。
  • 对任意节点ki,ki的深度为从根到k的唯一路径长,即根的深度为0。节点k的高是从k到一片树叶的最长路径的长。
  • 一个结点拥有孩子的个数称为该结点的度,树中各结点度的最大值称为该树的度。
  • 一棵树是N个节点和N-1条边的集合

2.二叉树

在这里插入图片描述
重要性质:

  • 二叉树中,第 i 层最多有 2i-1 个结点。

  • 如果二叉树的深度为 K,那么此二叉树最多有 2K-1 个结点。

  • 二叉树中,终端结点数(叶子结点数)为 n0,度为 2 的结点数为 n2,则 n0=n2+1。
    证明:在这里插入图片描述

  • 每一棵具有N个节点的二叉树都需要N+1个nullptr链。
    证明:每棵二叉树共有2N个链域,其中除根节点外每个节点都有父节点,即共有N-1个指针指向某个节点,空指针为2N-(N-1)=N+1。

  • 如果二叉树中除了叶子结点,每个结点的度都为 2,则此二叉树称为满二叉树。

  • 满二叉树中第 i 层的节点数为 2n-1 个。

  • 具有 n 个节点的满二叉树的深度为 log2(n+1)。

3. 完全二叉树

如果二叉树中除去最后一层节点为满二叉树,且最后一层的结点依次从左到右分布,则此二叉树被称为完全二叉树。在这里插入图片描述

  • n 个结点的完全二叉树的深度为 ⌊log2n⌋+1。
  • 对于任意一个完全二叉树来说,如果将含有的结点按照层次从左到右依次标号(如图 a)完全二叉树),对于任意一个结点 i ,完全二叉树还有以下几个结论成立:
  1. 当 i>1 时,父亲结点为结点 [i/2] 。(i=1 时,表示的是根结点,无父亲结点)
  2. 如果 2i>n(总结点的个数) ,则结点 i 肯定没有左孩子(为叶子结点);否则其左孩子是结点 2i 。
  3. 如果 2i+1>n ,则结点 i 肯定没有右孩子;否则右孩子是结点 2i+1 。

4.二叉查找树

使二叉树成为二叉查找树的性质是,对于树中的每个节点X,它的左子树中所有项的值均小于X中的项,而它的右子树中所有项的值均大于X中的项。如:二叉查找树
这样,在有n个元素的该数据结构中查找一个元素的时间复杂度为log2n。

二、 代码实现

#include<ostream>
using namespace std;
template<typename Comparable>
class BinarySearchTree {
private:
	struct BinaryNode {
		Comparable element;
		BinaryNode* left;
		BinaryNode* right;
		BinaryNode(const Comparable&theElement,BinaryNode*lt,BinaryNode*rt)
			:element{theElement},left{lt},right{rt}{}
		BinaryNode(Comparable&&theElement,BinaryNode*lt,BinaryNode*rt)
			:element{std::move(theElement)},left{lt},right{rt}{}
	};
	BinaryNode* root;

	/**
	* 向子树插入元素的内部方法
	* x是要插入的项
	* t为该子树的根节点
	* 置子树的新根
	**/
	void insert(const Comparable& x, BinaryNode*& t)
	{
		if (t == nullptr)
			t = new BinaryNode{ x,nullptr,nullptr };
		else if (x < t->element)
			insert(x, t->left);
		else if (t->element < x)
			insert(x, t->right);
		else
			; //重复元,什么也不做
	}

	/**
	* 向子树插入元素的内部方法
	* x是通过移动实现要插入的项
	* t为该子树的根节点
	* 置子树的新根
	*/
	void insert(Comparable&& x, BinaryNode*& t)
	{
		if (t == nullptr)
			t = new BinaryNode{ std::move(x),nullptr,nullptr };
		else if (x < t->element)
			insert(std::move(x), t->left);
		else if (x > t->element)
			insert(std::move(x), t->right);
		else
			; //重复元,什么也不做
	}

	/**
	* 从一棵子树删除一项的内部方法
	* 参数x是要被删除的项
	* 参数t为该子树的根节点
	* 置该子树的新的根
	*/
	void remove(const Comparable& x, BinaryNode*& t)
	{
		if (t == nullptr)
			return; //项没找到,什么也不做
		if (x < t->element)
			remove(x, t->left);
		else if (t->element < x)
			remove(x, t->right);
		else if (t->left != nullptr && t->right != nullptr) //有两个儿子
		{
			t->element = findMin(t->right)->element;
			remove(t->element, t->right);
		}
		else {
			BinaryNode* oldNode = t;
			t = (t->left != nullptr) ? t->left : t->right;
			delete oldNode;
		}
	}

	/**
	* 找出子树t中最小项的内部方法
	* 返回包含最小项的节点
	* 递归实现
	*/
	BinaryNode* findMin(BinaryNode* t) const
	{
		if (t == nullptr)
			return nullptr;
		if (t->left == nullptr)
			return t;
		return findMin(t->left);
	}

	/**
	* 找出子树t中最大项的内部方法
	* 返回包含最大项的节点
	* 非递归实现
	*/
	BinaryNode* findMax(BinaryNode* t) const
	{
		if (t != nullptr) {
			while (t->right != nullptr)
				t = t->right;
		}
		return t;
	}

	/**
	* 测试一项是否在子树上的内部方法
	* x是要查找的项
	* t是作为该子树的根的节点
	*/
	bool contains(const Comparable& x, BinaryNode* t) const
	{
		if (t == nullptr)
			return false;
		else if (t->element < x) { //x比当前节点大,去右子树找
			return contains(x, t->right);
		}
		else if (t->element > x) { //x比当前节点小,去左子树找
			return contains(x, t->left);
		}
		else
			return true; //匹配,找到了
	}

	/**
	* 使子树为空的内部方法
	*/
	void makeEmpty(BinaryNode*& t)
	{
		if (t != nullptr) {
			makeEmpty(t->left);
			makeEmpty(t->right);
			delete t;
		}
		t = nullptr;
	}

	//以排序顺序打印根在t处的子树的内部方法
	void printTree(BinaryNode* t, ostream& out)const
	{
		if (t != nullptr) {
			printTree(t->left, out);
			out << t->element << endl;
			printTree(t->right, out);
		}
	}

	/**
	* 克隆子树的内部方法
    */
	BinaryNode* clone(BinaryNode* t)const {
		if (t == nullptr)
			return nullptr;
		else
			return new BinaryNode{ t->element,clone(t->left),clone(t->right) };
	}

	/**
	* 计算根在t处子树的高度的内部方法
	* 后序遍历计算树的高度
	*/
	int height(BinaryNode* t)const {
		if (t == nullptr) {
			return -1;
		}
		else
			return 1 + max(height(t->left), height(t->right));
	}

public:
	BinarySearchTree() :root{ nullptr } {}
	BinarySearchTree(const BinarySearchTree& rhs) :root{ nullptr }
	{
		root = clone(rhs.root);
	}
	BinarySearchTree(BinarySearchTree&& rhs) :root{ rhs.root } {
		rhs.root = nullptr;
	}
	~BinarySearchTree() {
		makeEmpty();
	}

	const Comparable& findMin()const {
		return findMin(root)->element;
	}
	const Comparable& findMax()const {
		return findMax(root)->element;
	}
	//如果在树中找到x,则返回true
	bool contains(const Comparable& x)const { 
		return contains(x, root);
	}
	bool isEmpty()const {
		return root == nullptr;
	}

	int height()const
	{
		return height(root);
	}

	//按排列顺序打印树的内容
	void printTree(ostream& out)const {
		if (isEmpty())
			out << "Empty tree" << std::endl;
		else
			printTree(root, out);
	}

	void makeEmpty() {
		makeEmpty(root);
	}
	//将x插入到树中,忽略重复元
	void insert(const Comparable& x) { 
		insert(x, root);
	}
	void insert(Comparable&& x) {
		insert(std::move(x), root);
	}
	//将x从树中删除,若没找到x,则什么也不做
	void remove(const Comparable& x) { 
		remove(x, root);
	}

	/**
	* Copy assignment
	*/
	BinarySearchTree& operator=(const BinarySearchTree& rhs)
	{
		BinarySearchTree copy = rhs;
		std::swap(*this, copy);
		return *this;
	}

	/**
	 * Move assignment
	 */
	BinarySearchTree& operator=(BinarySearchTree&& rhs)
	{
		std::swap(root, rhs.root);
		return *this;
	}
};
posted @ 2022-10-18 08:48  aw11  阅读(57)  评论(0)    收藏  举报