数据结构 二叉检索树的C++实现

  1. 定义
    二叉检索树或者是一棵空树,或者是具有下列性质的二叉树: 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值; 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值; 它的左、右子树也分别为二叉检索树。又称二叉搜索树,二叉排序树。

  2. 结点的实现

template<typename Key, typename E>
struct BSTNode {
	typedef BSTNode<Key, E>node;
	node* left;
	node* right;
	Key key;
	E val;
	BSTNode(const Key& k, const E& v,
         node* l = nullptr, node* r = nullptr)
		:key(k), val(v), left(l), right(r) {}
	void setleft(node* t) { left = t; }
	void setright(node* t) { right = t; }
};
  1. 基本操作
  • 查找

    设查找的值为K,若k小于当前结点的值,则检索该节点的左子树,否则检索该节点的右子树。该过程一直持续到查找到该值或到达叶结点。若到达叶结点还未找到,则该值不在该树中。

//E为数值的数据类型,Key为键值的数据类型 
E* find(const Key& k) {
        return findhelp(root, k);
}
E* findhelp(node* t, const Key& k) {
        //已空或为空子树,未查找到,返回空指针
		if (t == nullptr) return nullptr;
		//查询左子树
		if (k < t->key)return findhelp(t->left, k);    
		//查询右子树
		else if (k > t->key)return findhelp(t->right, k);
		//返回键对应的值
		else return &(t->val);
}
  • 插入

要插入一个值,首先要明确它应该被插到什么地方。递归查询它应该被插入的地方,最终达到一个叶结点或在待插入方向上没有子节点的分支结点。最后将该值插进去。

void insert(const Key& k, const E& v) {
        //n为结点数目
	     ++n; root = inserthelp(root, k, v);
}
node* inserthelp(node* t, const Key& k, const E& v) {
        //空树,直接new一个结点
		if (t == nullptr)return new node(k, v);
		//键值大于要插入的键值,往左边插
		if (k < t->key)
			t->setleft(inserthelp(t->left, k, v));
		//否则插入右边
		else
			t->setright(inserthelp(t->right, k, v));
		//返回新的根节点
		return t;
}
  • 删除
    在考虑如何删除任一结点时,先着眼于如何删除键值最小(大)的结点。
    由于二叉检索树的性质,只要沿着左边的链一直移动直到叶结点,该叶结点就是键值最小的结点。要移走该叶结点,只需将它的父节点指向它的左子树(如果有的话
node* deletemin(node* t) {
        //直到没有左节点,返回右结点
		if (t->left == nullptr)return t->right;
		else {
		    //删除最小键值结点
			t->setleft(deletemin(t->left));
			//返回新的根节点
			return t;
		}
}

还可以根据这个性质来找到最小键值结点

node* getmin(node* t) {
        //搜索到空指针,返回
		if (t->left == nullptr)return t;
		//一直沿着左边移动
		return getmin(t->left);
}

接下来就考虑如何删除任一结点了。首先找到这一节点,
如果它没有子节点,就将它的父节点指向它的指针设为空指针。
如果它有一个子节点,那么将它的父节点指向它的指针改为指向它的子节点的指针。
如果它有两个子节点,较好的做法是从它的子树中找到一个可以替代它的值。为了保持二叉检索树的性质,我们应该选择大于等于被替换值的最小值或小于等于它的最大值。即左子树中值最大的结点或右子树中值最小的结点。由于我们在建立二叉检索树时,大于等于结点的值都在结点的右子树,故我们最好选择右子树的最小值。否则树的性质就会发生改变。

void remove(const Key& k) {
		root = removehelp(root, k);
		--n;    //结点数减一
}
node* removehelp(node* t, const Key& k) {
        //k不在树中
		if (t == nullptr)return nullptr;
		//改变父节点的指向
		if (k < t->key)
			t->setleft(removehelp(t->left, k));
		else if (k > t->key)
			t->setright(removehelp(t->right, k));
		//找到对应结点
		else {
			node* temp = t;
			//左子树为空的情况
			if (t->left == nullptr) {
				t = t->right;
				safe_delete(temp);
			}
			//右子树为空的情况
			else if (t->right == nullptr) {
				t = t->left;
				safe_delete(temp);
			}
			else {
			    //找到右子树的最小值
				temp = getmin(t->right);
				//替换
				t->val = temp->val;
				t->key = temp->key;
				//删除该节点
				t->setright(deletemin(t->right));
				safe_delete(temp);
			}
		}
		//放hi新的根节点
		return t;
	}
  • 完整代码

#include <iostream>
#include <cstdio>
#include <algorithm>
#define safe_delete(p) if(p){delete p;p=nullptr;}
using namespace std;

template<typename Key, typename E>
struct BSTNode {
	typedef BSTNode<Key, E>node;
	node* left;
	node* right;
	Key key;
	E val;
	BSTNode(const Key& k, const E& v,
         node* l = nullptr, node* r = nullptr)
		:key(k), val(v), left(l), right(r) {}
	void setleft(node* t) { left = t; }
	void setright(node* t) { right = t; }
};

template<typename Key, typename E>
class BST {
typedef BSTNode<Key, E>node;
private:
	node* root;
	int n;
	node* inserthelp(node* t, const Key& k, const E& v) {
		if (t == nullptr)return new node(k, v);
		if (k < t->key)
			t->setleft(inserthelp(t->left, k, v));
		else
			t->setright(inserthelp(t->right, k, v));
		return t;
	}
	node* deletemin(node* t) {
		if (t->left == nullptr)return t->right;
		else {
			t->setleft(deletemin(t->left));
			return t;
		}
	}
	node* getmin(node* t) {
		if (t->left == nullptr)return t;
		return getmin(t->left);
	}
	node* removehelp(node* t, const Key& k) {
		if (t == nullptr)return nullptr;
		if (k < t->key)
			t->setleft(removehelp(t->left, k));
		else if (k > t->key)
			t->setright(removehelp(t->right, k));
		else {
			node* temp = t;
			if (t->left == nullptr) {
				t = t->right;
				safe_delete(temp);
			}
			else if (t->right == nullptr) {
				t = t->left;
				safe_delete(temp);
			}
			else {
				temp = getmin(t->right);
				t->val = temp->val;
				t->key = temp->key;
				t->setright(deletemin(t->right));
				safe_delete(temp);
			}
		}
		return t;
	}
	E* findhelp(node* t, const Key& k) {
		if (t == nullptr) return nullptr;
		if (k < t->key)return findhelp(t->left, k);
		else if (k > t->key)return findhelp(t->right, k);
		else return &(t->val);
	}
	void clearhelp(node* t) {
		if (t == nullptr)return;
		clearhelp(t->left);
		clearhelp(t->right);
		safe_delete(t);
	}
	void printhelp(node* t, int dep) {
		if (t == nullptr)return;
		printhelp(t->left, dep + 1);
		for (int i = 0; i < dep; ++i)
			putchar(' ');
		cout << t->key << " " << t->val << endl;
		printhelp(t->right, dep + 1);
	}
public:
	BST() { n = 0; root = nullptr; }
	~BST() { clearhelp(root); }
	void clear() {
	    clearhelp(root); n = 0; root = nullptr;
    }
	void insert(const Key& k, const E& v) {
	     ++n; root = inserthelp(root, k, v);
    }
	void remove(const Key& k) {
		root = removehelp(root, k);
		--n;
	}
	E* find(const Key& k) {
        return findhelp(root, k);
    }
	int size()const { return n; }
	void print() {
		if (root != nullptr)
			printhelp(root, 1);
	}
};

int main(int argc, char** argv) {
	BST<int, int>t;
	int n = 5;
	int a, b;
	for (int i = 0; i < n; ++i){
        scanf("%d%d",&a,&b);
		t.insert(a, b);
	}
	t.print();
	scanf("%d",&a);
	int *x = t.find(a);
	if (x != nullptr)
		cout << *x << endl;
    safe_delete(x);
	t.clear();
	return 0;
}

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值