搜索二叉树(Key-Value)

搜索二叉树保证了对于每个根节点,左子树上所有节点值小于根节点,右子树上,所有节点的值大于根节点。由此性质保证了二叉搜索树高效的查找效率,一棵优秀的二叉搜索树可达到搜索效率log(N)的级别,但搜索二叉树如果在创建时是以有序插入,那么它会退化为单链表,搜索二叉树的性质决定了其先序遍历结果一定是按照Key递增顺序。

节点结构如下

	template<class K,class V>
	class SBTreeNode{
	public:
		SBTreeNode():left(nullptr),right(nullptr),key(0),value(0){
		}
		SBTreeNode(K key = 0, V value = 0){
			this->key = key;
			this->value = value;
			this->left = nullptr;
			this->right = nullptr;
		}
		SBTreeNode<K, V>*left;
		SBTreeNode<K, V>*right;
		K key;
		V value;
	};

template<class K,class V>
	class SBTree{
	public:
		SBTree():root(nullptr){

		}
	private:
		SBTreeNode<K, V>*root;
	};

创建一个搜索二叉树:如果要加入的这个节点Key值大于目前根节点,则一定要插入到这个根节点的右子树上,如果要加入的Key值小于目前根节点,就要插入到这个根节点的左子树。如果相等,就不插入,当前根为空的时候就是这个Key值对应节点的位置。如果Key值等于当前根节点的Key值停止插入,达到去重目的。

		void insert( K k,V v=0){//二叉树的插入,由于要使用根,所以用子函数实现
			_insert(this->root, k,v);
		}
        bool _insert(SBTreeNode<K, V>*& root,K k,V v ){//插入子函数
			if (root == nullptr){//到了要插入的位置
				root = new SBTreeNode<K,V>(k, v);
				return true;
			}
			if (k > root->key){//往右子树插入
				return _insert(root->right, k, v);
			}
			else if (k < root->key){//往左子树插入
				return _insert(root->left, k, v);
			}
			else{
				return false;//遇到相同的Key返回失败结果
			}
		}

先序遍历:

		vector<V> InOrder(){//先序遍历,返回value组成的vector
			vector<V>v;
			_InOrder(this->root, v);
			return v;
		}
        void _InOrder(const SBTreeNode<K, V>*root,vector<V>&v){//前序遍历,顺便将value放入vector
			if (root == nullptr){
				return;
			}
			_InOrder(root->left,v);
			v.push_back(root->value);
			_InOrder(root->right,v);
		}

根据Key查找(返回相应节点地址):

SBTreeNode<K, V>* find(K key){//按Key查找
    return _find(root,key);
}
SBTreeNode<K, V>* _find(SBTreeNode<K,V>*root,K key)const{
    if (root == nullptr||root->key==key){//如果没找到返回空
        return root;
	}
	return key > root->key ? _find(root->right, key) : _find(root->left, key);//key大于根往右找,key小于根往左找
}

按Key删除节点:对于两个孩子节点中有至少一个为空的情况和两个孩子都为空的情况分开处理

假设当前节点叫做P

如果P的两个孩子都为空直接删除P即可

如果P的两个孩子中有一个为空,那么让P的父亲连接上P不为空的那个节点

如果P的两个孩子都不为空,我们采取覆盖删除,选取有孩子的最左节点Q(由于SBTree的性质,这个节点的Key一定是右孩子中最小的),将Q的value和Key与P交换,这是要删的节点就是右孩子的最左节点

void Delete(K key){
    _Delete(root, key);
}
void _Delete(SBTreeNode<K, V>*&root, K key){//删除key的节点
	if (root == nullptr){//如果走到空,说明没有树上没有这个节点,直接返回
		return;
	}
	if (root->key == key){
		if (root->left == nullptr || root->right == nullptr){//如果左右有一个是空
			SBTreeNode<K, V>*del=root;
			if (root->right != nullptr){//如果右子树不是空
				root = root->right;
			}
			else{
				root = root->left;//如果右子树为空而左子树不为空(指向不为空的节点)或左右子树都为空(指向空节点)
			}
			delete del;//直接删除当前节点
			return;
		}
		else{
			SBTreeNode<K, V>*cur=root->right;
			while (cur->left != nullptr){
				cur = cur->left;
			}
			swap(cur->value, root->value);
			swap(cur->key, root->key);//将key-value覆盖后递归到右孩子删除键为key的节点,这个节点此时一定满足上面的情况
			_Delete(root->right,cur->key);
		}
	}
	else if(root->key<key){
		_Delete(root->right, key);
	}
	else{
		_Delete(root->left, key);
	}
}

在删除时由于要修改父节点 left/right 指针的指向,还要判断当前这个节点是父亲的左孩子还是右孩子,所以要在递归函数中将父节点指针信息传递进来,较为麻烦,故这里使用了指针引用,对root的操作相当与直接对父节点指向孩子的指针进行操作。所以不需要额外传递父节点的信息。

完整代码如下:

#pragma once 
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
namespace ljc{
	template<class K,class V>
	class SBTreeNode{
	public:
		SBTreeNode():left(nullptr),right(nullptr),key(0),value(0){
		}
		~SBTreeNode(){
		}
		SBTreeNode(K key = 0, V value = 0){
			this->key = key;
			this->value = value;
			this->left = nullptr;
			this->right = nullptr;
		}
		SBTreeNode<K, V>*left;
		SBTreeNode<K, V>*right;
		K key;
		V value;
	};
	template<class K,class V>
	class SBTree{
	public:
		SBTree():root(nullptr){

		}
		void insert( K k,V v=0){//二叉树的插入,由于要使用根,所以用子函数实现
			_insert(this->root, k,v);
		}
		vector<V> InOrder(){//先序遍历,返回value组成的vector
			vector<V>v;
			_InOrder(this->root, v);
			return v;
		}
		SBTreeNode<K, V>* find(K key){//按Key查找
			return _find(root,key);
		}
		void Delete(K key){
			_Delete(root, key);
		}
	private:
		SBTreeNode<K, V>*root;
		bool _insert(SBTreeNode<K, V>*&root,K k,V v ){//插入子函数
			if (root == nullptr){//到了要插入的位置
				root = new SBTreeNode<K,V>(k, v);
				return true;
			}
			if (k > root->key){//往右子树插入
				return _insert(root->right, k, v);
			}
			else if (k < root->key){//往左子树插入
				return _insert(root->left, k, v);
			}
			else{
				return false;//遇到相同的Key返回失败结果
			}
		}
		void _InOrder(const SBTreeNode<K, V>*root,vector<V>&v){//前序遍历,顺便将value放入vector
			if (root == nullptr){
				return;
			}
			_InOrder(root->left,v);
			v.push_back(root->value);
			_InOrder(root->right,v);
		}
		SBTreeNode<K, V>* _find(SBTreeNode<K,V>*root,K key)const{
			if (root == nullptr||root->key==key){//如果没找到返回空
				return root;
			}
			return key > root->key ? _find(root->right, key) : _find(root->left, key);//key大于根往右找,key小于根往左找
		}
		void _Delete(SBTreeNode<K, V>*&root, K key){//删除key的节点
			if (root == nullptr){
				return;
			}
			if (root->key == key){
				if (root->left == nullptr || root->right == nullptr){
					SBTreeNode<K, V>*del=root;
					if (root->right != nullptr){
						root = root->right;
					}
					else{
						root = root->left;
					}
					delete del;
					return;
				}
				else{
					SBTreeNode<K, V>*cur=root->right;
					while (cur->left != nullptr){
						cur = cur->left;
					}
					swap(cur->value, root->value);
					swap(cur->key, root->key);
					_Delete(root->right,cur->key);
				}
			}
			else if(root->key<key){
				_Delete(root->right, key);
			}
			else{
				_Delete(root->left, key);
			}
		}
	};
}

由于技术局限,难免有不恰之处,如果发现有错误,还望指正。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值