二叉搜索树基本实现

二叉搜索树----一般情况等于根节点就不存放

二叉搜索树又称为二叉排序树具有以下性质:
1.若它的左子树不为空,则左子树上的所有节点的值都小于根节点的值
2.若它的右子树不为空,则右字树上的所有节点的值都大于根节点的值
3.它的左右子树也分别为二叉搜索树

实现的操作:

1.搜索查找------接近二分的查找(与树的特点相关)------平均查找次数(logn)
2.插入:如果树中已经存在需要插入的数据,则不重复插入
插入的位置:叶子,子树不完全的非叶子节点(度为0和度为1的节点)

3.删除操作

左子树:左子树的最右节点是所有左子树中最大的节点
右子树:右子树的最左节点是所有右子树中最小的节点

删除度为2的节点:
1.找到此节点中左子树的最右节点或者右子树的最左节点
2.要删除的节点val替换成最左节点或者左右节点的val
3.真正需要删除的为最左或者最右节点-------转换成删除度为0或者度为1的节点
二叉搜索树------中序遍历有序(左–>根—>右)–得到递增顺序

4.拷贝操作-----------进行深拷贝

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

template<class T>
struct BSTNode{

	T _val; //节点
	BSTNode<T>* _left;
	BSTNode<T>* _right;

	BSTNode(const T& val = T()) 
		:_val(val)
		, _left(nullptr)
		, _right(nullptr)
	{}
};

template<class T>
class BSTree{

public:
	typedef BSTNode<T> Node;//BSTNode<T>类名+类型-----
	//查找一个数值
	//1>搜索查找------接近二分的查找(与树的特点相关)------平均查找次数(logn)
	Node* find(const T& val) {
		Node* cur = _root;
		while (cur) {
			if (cur->_val == val)
				return cur;
			else if (cur->_val < val)
				cur = cur ->right;
			else
				cur = cur->_left;
		}
		return nullptr;
	}

	//2>插入:如果树中已经存在需要插入的数据,则不重复插入-------不破坏已有的链接,改变新的连接关系
	//插入的位置:叶子,子树不完全的非叶子节点(度为0和度为1的节点)

	bool insert(const T& val) {
		if (_root == nullptr) {
			_root = new Node(val);
			return true;
		}

		Node* cur = _root;//当前的根节点
		Node* parent = nullptr;//上一个节点需要记录走的路径----刚开始处于空指针的位置
		//1.先查找空的插入的位置
		while (cur) { //先找到空的位置
			parent = cur;
			if (cur->_val == val)
				return false;
			else if (cur->_val < val)
				cur = cur->_right;
			else
				cur = cur->_left;
		}
		//2.进行数据的插入
		//上一步循环结束的时候cur==nullptr
		//此时创造新的节点
		cur = new Node(val);
		//判断放到parent的那一边
		if (parent->_val < val)
			parent->_right = cur;
		else
			parent->_left = cur;
		return true;
	}
	//删除操作-------存在删除4种情况的值
	//----直接删除会破坏结构,因此找一个可以替代当前情况的点
	bool erase(const T& val) {
		//查找
		Node* cur = _root;//当前的根节点
		Node* parent = nullptr;//上一个节点需要记录走的路径----刚开始处于空指针的位置
		while (cur) { 
			if (cur->_val == val)
				break;
			else if (cur->_val < val) {
				parent = cur;
				cur = cur->_right;
			}
			else{
				parent = cur;
				cur = cur->_left;
			}
		}
	//判断是否找到了需要删除的节点
		if (cur == nullptr)
			return false;
	//删除
		//1.叶子 度为0的节点
		if (cur->_left == nullptr && cur->_right == nullptr) {

			if (cur == _root) { //特殊情况,只有一个节点
				//如果是根节点,更新根节点
				_root = nullptr;
			}

			if (parent->_left == cur)
				parent->_left = nullptr;
			else 
				parent->_right = nullptr;

			delete cur;
		}
		else if (cur->_left == nullptr) { //2.删除度为1 的节点
		//2.左孩子为空,只有右子树
			if (cur == _root) {
				_root = cur->_right;
			}
			else {
				if (parent->_left == cur)
					parent->_left = cur->_right;
				else
					parent->_right = cur->_right;
			}
			delete cur;
		}
		else if (cur->_right == nullptr) {
		//3.右孩子为空,只有左子树
			if (cur == _root) {
				_root = cur->_left;
			}
			else {
				if (parent->_left == cur)
					parent->_left = cur->_left;
				else
					parent->_right = cur->_left;
			}
			delete cur;
		}
		else {
		//4.左右孩子都存在
			//a.找最左或者最右节点
			//找右子树的左节点
			Node* leftMostChild = cur->_right;
			Node* parent = cur;
			while (leftMostChild->_left) {
				parent = leftMostChild;
				leftMostChild = leftMostChild->_left;
			}
			//b.值替换
			cur->_val = leftMostChild->_val;
			//c.删除最左或者最右节点 
			if (parent->_left == leftMostChild)
				parent->_left = leftMostChild->_right;
			else 
			parent->_right = leftMostChild->_right;
			delete leftMostChild;
		}
		return true;
	}
	//中序遍历====递归实现
	void inorder() {
		_inorder(_root);
		cout << endl;
	}
	void _inorder(Node* root) {
		if (root) {
			_inorder(root->_left);
			cout << root->_val << " ";
			_inorder(root->_right);
		}
	}
	//销毁操作
	void destory(Node* root) {
		if (root) {
			destory(root->_left);
			destory(root->_right);
			delete root;
		}
	}
	//析构函数----
	~BSTree() {
		destory(_root);
	}
	拷贝1
	//void copyTree(Node* root) { //遍历的过程走一个插入的过程
	//	if (root){
	//		insert(root->_val);
	//		copyTree(root->_left);
	//		copyTree(root->_right);
	//	}
	//}
	//拷贝2-------拷贝2逻辑上比拷贝1更简单一点
	Node* copyTree(Node* root) { 
		if (root){
			Node* cur = new Node(root->_val);
			cur->_left = copyTree(root->_left);
			cur->_right = copyTree(root->_right);
			return cur;
		}
		return nullptr;
	}

	//默认构造
	BSTree() 
		:_root(nullptr)
	{}

	//拷贝构造
	BSTree(const BSTree<T>& bst) 
		:_root(nullptr)
	{
		copyTree(bst._root);
	}
	


private:
	Node* _root = nullptr;
};

void test1() {
	BSTree<int> bst;
	bst.insert(5);
	bst.insert(3);
	bst.insert(4);
	bst.insert(1);
	bst.insert(2);
	bst.insert(0);
	bst.insert(7);
	bst.insert(6);
	bst.insert(8);
	bst.insert(9);
	bst.inorder();

	bst.erase(0);
	bst.inorder();
	bst.erase(8);
	bst.inorder();
	bst.erase(3);
	bst.inorder();
	bst.erase(2); 
	bst.inorder();
	bst.erase(1);
	bst.inorder();
	bst.erase(4);
	bst.inorder();
	bst.erase(5); 
	bst.inorder();

}
void test2() {
	BSTree<int> bst;
	bst.insert(5);
	bst.insert(3);
	bst.insert(4);
	bst.insert(1);
	bst.insert(2);
	bst.insert(0);
	bst.insert(7);
	bst.insert(6);
	bst.insert(8);
	bst.insert(9);
	bst.inorder();

	BSTree<int> copy(bst);
	bst.inorder();
}
int main() {
	//test1();
	test2();
	system("pause");
	return 0;
}

二叉搜索树应用-------

二叉搜索树明显的缺点-------由于插入数字的顺序不同产生的也会不相同

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

template<class K,class V>//里面的K相当于索引
struct BSTNode{
	K _key;//K相当于索引
	V _val; //节点
	BSTNode<K,V>* _left;
	BSTNode<K,V>* _right;

	BSTNode(const K& key = K(),const V& val = V())
		:_key(key)
		,_val(val)
		, _left(nullptr)
		, _right(nullptr)
	{}
};

template<class K, class V>
class BSTree{

public:
	typedef BSTNode<K,V> Node;//BSTNode<T>类名+类型-----
	//查找一个数值
	//1>搜索查找------接近二分的查找(与树的特点相关)------平均查找次数(logn)
	Node* find(const K& key) {
		Node* cur = _root;
		while (cur) {
			if (cur->_key == key)
				return cur;
			else if (cur->_key < key)
				cur = cur->right;
			else
				cur = cur->_left;
		}
		return nullptr;
	}

	//2>插入:如果树中已经存在需要插入的数据,则不重复插入-------不破坏已有的链接,改变新的连接关系
	//插入的位置:叶子,子树不完全的非叶子节点(度为0和度为1的节点)

	bool insert(const K& key,const V& val) {
		if (_root == nullptr) {
			_root = new Node(key, val);
			return true;
		}
		Node* cur = _root;//当前的根节点
		Node* parent = nullptr;//上一个节点需要记录走的路径----刚开始处于空指针的位置
		//1.先查找空的插入的位置
		while (cur) { //先找到空的位置
			parent = cur;
			if (cur->_key == key)
				return false;
			else if (cur->_key < key)
				cur = cur->_right;
			else
				cur = cur->_left;
		}
		//2.进行数据的插入
		//上一步循环结束的时候cur==nullptr
		//此时创造新的节点
		cur = new Node(key, val);
		//判断放到parent的那一边
		if (parent->_key < key)
			parent->_right = cur;
		else
			parent->_left = cur;
		return true;
	}
	//删除操作-------存在删除4种情况的值
	//----直接删除会破坏结构,因此找一个可以替代当前情况的点
	bool erase(const K& key) {
		//查找
		Node* cur = _root;//当前的根节点
		Node* parent = nullptr;//上一个节点需要记录走的路径----刚开始处于空指针的位置
		while (cur) {
			if (cur->_key == key)
				break;
			else if (cur->_key < key) {
				parent = cur;
				cur = cur->_right;
			}
			else{
				parent = cur;
				cur = cur->_left;
			}
		}
		//判断是否找到了需要删除的节点
		if (cur == nullptr)
			return false;
		//删除
		//1.叶子 度为0的节点
		if (cur->_left == nullptr && cur->_right == nullptr) {

			if (cur == _root) { //特殊情况,只有一个节点
				//如果是根节点,更新根节点
				_root = nullptr;
			}

			if (parent->_left == cur)
				parent->_left = nullptr;
			else
				parent->_right = nullptr;

			delete cur;
		}
		else if (cur->_left == nullptr) { //2.删除度为1 的节点
			//2.左孩子为空,只有右子树
			if (cur == _root) {
				_root = cur->_right;
			}
			else {
				if (parent->_left == cur)
					parent->_left = cur->_right;
				else
					parent->_right = cur->_right;
			}
			delete cur;
		}
		else if (cur->_right == nullptr) {
			//3.右孩子为空,只有左子树
			if (cur == _root) {
				_root = cur->_left;
			}
			else {
				if (parent->_left == cur)
					parent->_left = cur->_left;
				else
					parent->_right = cur->_left;
			}
			delete cur;
		}
		else {
			//4.左右孩子都存在
			//a.找最左或者最右节点
			//找右子树的左节点
			Node* leftMostChild = cur->_right;
			Node* parent = cur;
			while (leftMostChild->_left) {
				parent = leftMostChild;
				leftMostChild = leftMostChild->_left;
			}
			//b.值替换
			cur->_val = leftMostChild->_val;
			//c.删除最左或者最右节点 
			if (parent->_left == leftMostChild)
				parent->_left = leftMostChild->_right;
			else
				parent->_right = leftMostChild->_right;
			delete leftMostChild;
		}
		return true;
	}
	//中序遍历====递归实现
	void inorder() {
		_inorder(_root);
		cout << endl;
	}
	void _inorder(Node* root) {
		if (root) {
			_inorder(root->_left);
			cout << root->_key << "-->" << root->_val << " ";
			_inorder(root->_right);
		}
	}
	//销毁操作
	void destory(Node* root) {
		if (root) {
			destory(root->_left);
			destory(root->_right);
			delete root;
		}
	}
	//析构函数----
	~BSTree() {
		destory(_root);
	}
	拷贝1
	void copyTree(Node* root) { //遍历的过程走一个插入的过程
		if (root){
			insert(root->_key, root->_val);
			copyTree(root->_left);
			copyTree(root->_right);
		}
	}
	拷贝2-------拷贝2逻辑上比拷贝1更简单一点
	//Node* copyTree(Node* root) {
	//	if (root){
	//		Node* cur = new Node(root->_key, root->_val);
	//		cur->_left = copyTree(root->_left);
	//		cur->_right = copyTree(root->_right);
	//		return cur;
	//	}
	//	return nullptr;
	//}

	//默认构造
	BSTree()
		:_root(nullptr)
	{}

	//拷贝构造
	BSTree(const BSTree<K,V>& bst)
		:_root(nullptr)
	{
		copyTree(bst._root);
	}
private:
	Node* _root = nullptr;
};

void test1() {
	BSTree<int,string> bst;
	bst.insert(5,"five");
	bst.insert(3,"three");
	bst.insert(4,"four");
	bst.insert(1,"one");
	bst.insert(2,"two");
	bst.insert(0,"zero");
	bst.insert(7,"seven");
	bst.insert(6,"two");
	bst.insert(8,"one");
	bst.insert(9,"nine");
	bool ret= bst.insert(8, "eight");//插入失败,因为Key的值已经存在
	cout << ret << endl;
	bst.inorder();

	BSTree<int,string> copy(bst);
	bst.inorder();
}

void test2() {
	//二叉搜索树明显的缺点-------由于插入数字的顺序不同产生的也会不相同
	BSTree<int, string> bst;
	bst.insert(0, "zero");
	bst.insert(1, "one");
	bst.insert(2, "two");
	bst.insert(3, "three");
	bst.insert(4, "four");
	bst.insert(5, "five");
	bst.insert(6, "two");
	bst.insert(7, "seven");
	bst.insert(8, "one");
	bst.insert(9, "nine");
	bool ret = bst.insert(8, "eight");//插入失败,因为Key的值已经存在
	cout << ret << endl;
	bst.inorder();

	BSTree<int, string> copy(bst);
	bst.inorder();
}
int main() {
	test2();
	system("pause");
	return 0;
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值