二叉查找树

二叉查找树的特点

对于树中的每个节点 n,它的左子树中所有节点的值均小于 n节点的值,而它的右子树中所有节点的值均大于 n节点的值。

//二叉树的节点
struct Node
{
	Type element;
	Node *left;
	Node *right
};

关于重复值的问题有三种情况:

  1. 将重复的数据忽略,只保留一个。
  2. 将重复的数据放在不同节点,但是这样会破坏树节点“左小右大”的特点。
  3. 在每个节点都加一个计数器,记录重复值有多少个。

第三种情况稍微复杂一点,对应的节点数据结构如下:

struct Node
{
	Type element;
	int count;
	Node *left;
	Node *right;
};
//count就是添加的计数器。
/*相应的,对数据的添加、删除等操作也要对计数器的值进行判断*/

二叉查找树类

/*
这里实现了一些二叉查找树的基本功能:
1. 插入数据(左小右大)
2. 检索数据集中是否包含某个数据
3. 删除单个数据节点
4. 将树置空(数据全部删除)
5. 打印数据集
*/
#include <iostream>

template <typename T>
class BinarySearchTree
{
public:
	BinarySearchTree();
	BinarySearchTree(const BinarySearchTree & bst);
	~BinarySearchTree();

	const T & findMin() const;
	const T & findMax() const;
	bool contains(const T & x) const;
	bool isEmpty() const;
	void printTree() const;

	void makeEmpty();
	void insert(const T & x);
	void insert(T && x);
	void remove(const T & x);

private:
	struct Node 
	{
		T element;
		Node *left;
		Node *right;
		/*节点的拷贝*/
		Node(const T & theElement, Node *lt, Node *rt) : element{ theElement }, left{ lt }, right{ rt } { }
		Node(T && theElement, Node *lt, Node *rt) : element{ std::move(theElement) }, left{ lt }, right{ rt } { }
	};

	Node *root;		//根节点

	void insert(const T & x, Node * & t);	// * & 是指针的引用传递
	void insert(T && x, Node * & t);	// && 是右值引用
	void remove(const T & x, Node * & t);
	Node * findMin(Node *t) const;
	Node * findMax(Node *t) const;
	bool contains(const T & x, Node * t) const;
	void makeEmpty(Node * & t);
	void printTree(Node *t) const;
	Node * clone(Node *t) const;	//树的拷贝

};

成员函数实现


构造函和析构函数
/*无参构造函数*/
template <typename T>
BinarySearchTree<T>::BinarySearchTree() : root{ nullptr }
{
	
}

/*
拷贝构造函数
调用了clone方法,从树根开始递归的进行节点拷贝
*/
template <typename T>
BinarySearchTree<T>::BinarySearchTree(const BinarySearchTree & bst) : root{ nullptr }
{
	root = clone(bst.root);		//从根开始递归拷贝
}

/*clone方法*/
template <typename T>
typename BinarySearchTree<T>::Node* BinarySearchTree<T>::clone(Node *t) const 
{
	if (t == nullptr)
		return nullptr;
	else
		return new Node{ t->element, clone(t->left), clone(t->right) };
}

/*析构函数:调用了makeEmpty方法*/
template <typename T>
BinarySearchTree<T>::~BinarySearchTree()
{
	makeEmpty();
}

/*makeEmpty*/
template <typename T>
void BinarySearchTree<T>::makeEmpty()
{
	makeEmpty(root);
}
/*递归删除*/
template <typename T>
void BinarySearchTree<T>::makeEmpty(Node * & t)
{
	if (t != nullptr)
	{
		makeEmpty(t->left);
		makeEmpty(t->right);
		delete t;
	}
	t = nullptr;
}

数据插入和删除
/*插入数据,这里忽略了重复的数据*/
template <typename T>
void BinarySearchTree<T>::insert(const T & x)
{
	insert(x, root);
}

template <typename T>
void BinarySearchTree<T>::insert(T && x)
{
	insert(x, root);
}

template <typename T>
void BinarySearchTree<T>::insert(const T & x, Node * & t)
{
	if (t == nullptr)
		t = new Node(x, nullptr, nullptr);
	else if (x < t->element)
		insert(x, t->left);
	else if (x > t->element)
		insert(x, t->right);
	else
		;		//重复元则不做插入
}

template <typename T>
void BinarySearchTree<T>::insert(T && x, Node * & t)
{
	if (t == nullptr)
		t = new Node(std::move(x), nullptr, nullptr);
	else if (x < t->element)
		insert(std::move(x), t->left);
	else if (x > t->element)
		inset(std::move(x), t->right);
	else
		;		//重复元不做插入
}

/*删除数据(比较复杂)*/
template <typename T>
void BinarySearchTree<T>::remove(const T & x)
{
	remove(x, root);
}
/*
树叶:和有一个子节点的情况一起。因为树叶有两个空链,调整父节点的链即可
有一个子节点:调整父节点的链
有两个子节点:用右子树的最小数据代替该节点的数据,并删除右子树最小的节点(也可以用左子树的最大节点,效果一样)
*/
template <typename T>
void BinarySearchTree<T>::remove(const T & x, Node * & t)
{
	if (t == nullptr)	//空树直接返回
		return;
	if (x < t->element)
		remove(x, t->left);		//递归查找目标节点
	else if (x > t->element)
		remove(x, t->right);	//递归查找目标节点
	else if ((t->left != nullptr) && (t->right != nullptr))		//有两个儿子
	{
		t->element = findMin(t->right)->element;	//右子树最小数据替换该节点数据
		remove(t->element, t->right);	//删除右子树最小节点
	}
	else	//有一个儿子 或者 没有儿子
	{
		Node *oldNode = t;
		t = (t->left != nullptr) ? t->left : t->right;
		delete oldNode;
	}
}

查找数据

/**
* 是否包含某个数据
*/
template <typename T>
bool BinarySearchTree<T>::contains(const T & x) const
{
	return contains(x, root);
}

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

/**
* 查找最大数据
*/
template <typename T>
const T & BinarySearchTree<T>::findMax() const
{
	typename BinarySearchTree<T>::Node *temp;
	temp = findMax(root);
	int max = temp->element;
	return max;
}

template <typename T>
typename BinarySearchTree<T>::Node * BinarySearchTree<T>::findMax(Node *t) const
{
	if (t == nullptr)
		return nullptr;
	if (t->right == nullptr)
		return t;
	return findMax(t->right);
}

/**
* 查找最小值
*/
template <typename T>
const T & BinarySearchTree<T>::findMin() const
{
	typename BinarySearchTree<T>::Node *temp;
	temp = findMin(root);
	int min = temp->element;
	return min;
}

template <typename T>
typename BinarySearchTree<T>::Node * BinarySearchTree<T>::findMin(Node *t) const
{
	if (t == nullptr)
		return nullptr;
	if (t->left == nullptr)
		return t;
	return findMin(t->left);
}

判断是否空树和打印

/**
* 判断是否为空树
*/
template <typename T>
bool BinarySearchTree<T>::isEmpty() const
{
	if (root == nullptr)
		return true;
	else
		return false;
}

/**
* 打印树--中序遍历
*/
template <typename T>
void BinarySearchTree<T>::printTree() const
{
	if (isEmpty())
		cout << "空树“ << endl;
	else
		printTree(root);
}

template <typename T>
void  BinarySearchTree<T>::printTree(Node *t) const
{
	if (t == nullptr)
		return;
	printTree(t->left);
	std::cout << t->element << "  ";
	printTree(t->right);
}

用个小例子测试二叉树

#include "BinarySearchTree.h"
#include <iostream>
#include <ctime>
using namespace std;

#define random(x) (rand()%x)

int main()
{
	srand((int)time(0));
	BinarySearchTree<int> bt;

	//插入数据:1-20	
	for (int i = 20; i >= 1; --i)
	{
		bt.insert(random(101));
	}
	//打印数据
	bt.printTree();
	cout << endl;

	//测试拷贝构造函数
	BinarySearchTree<int> bt2(bt);
	//打印bt2
	cout << "bt2: ";
	bt2.printTree();
	cout << endl;

	//查找最大数据
	cout << bt.findMax() << endl;
	
	//查找最小值
	cout << bt.findMin() << endl;

	//查看是否为空树
	if (bt.isEmpty())
		cout << "空树" << endl;
	else
		cout << "不是空树" << endl;

	//查看是否包含10
	if (bt.contains(10))
		cout << "10在数据集里" << endl;
	else
		cout << "10不在数据集里" << endl;
	
	//删除10
	bt.remove(10);

	//查看是否包含10
	if (bt.contains(10))
		cout << "10在数据集里" << endl;
	else
		cout << "10不在数据集里" << endl;

	//置空
	bt.makeEmpty();

	//查看是否为空树
	if (bt.isEmpty())
		cout << "空树" << endl;
	else
		cout << "不是空树" << endl;


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值