二叉搜索树基本数据结构实现

二叉搜索树中一个结点包含3个指针left,right, prev和一个卫星数据key。这三个指针分别指向左儿子,右儿子,父节点。如果孩子结点和父亲结点不存在,相应指针为空。根结点的prev指向空。

    1)遍历(中序遍历,先序遍历,后续遍历)

    2)查找一个关键字,返回该关键字的结点指针

    3).返回最大关键字最小关键字结点指针

    4)寻找关键字key的后继结点

    5)插入关键字key

    6)构建一颗二叉搜索树

    7)删除关键字key

1.遍历之中序遍历:递归中序遍历比较简单不多哆嗦。中序遍历非递归方法:首先需要一个栈来保存待遍历的结点:

                 a.先将根结点T=root压入栈S中

                 b.若结点T不空或者栈不空,将结点T沿途的左儿子全部压入栈中

                 c.栈顶元素T=S.top()出栈并访问之,如果T的右儿子存在,则将T右儿子进栈,然后T=T->right

                 d.重复步骤b

2.查找一个关键字key的方法:首先从树根开始比较。若key==x.key则找到,若key>x.key,则含关键字key的结点在x的右子树中,否则在左字树中。未找到则返回NULL。

3.返回最大最小元素:根据二叉搜索树性质可知,最大元素一定在树的最右端(该结点没有右儿子),最小结点一定在树的最左端(该结点没有左儿子)。

4.寻找关键字key的后继结点。 后继结点:一个结点x的后是大于x->key的最小关键字的结点。方法:如果结点x的右子树非空,x的后继一定是x右子树中最左的结点(右子树中key值最小结点),若x的右儿子不存在。则x的后继就要向上找,设y是向上寻找中移动的结点,直到遇到y是y父节点的左儿子为止,此时的y的父节点就是x的后继。

5.插入关键字key,先找到插入的位置(一定是某个叶节点处),然后修改指针插入。下面是递归函数代码(后面有非递归代码)

  

<span style="font-size:12px;">BST* Insert(BST *BT, int key){    /*此代码中没有prev指针*/
	if (!BT){  //找到啦要插入的位置
		BT = new Tree; /*生成结点*/
		BT->key = key;//插入
		BT->left = BT->right = NULL;
	}
	else if (key > BT->key) 
		BT->right = Insert(BT->right, key);  //递归插入到左子树
	else if (key < BT->key)
		BT->left = Insert(BT->left,key);     //插入到右子树
	return BT;                                   //有相等的数就不用插入了
}</span>
6.构建二叉搜索树就是不断地插入关键字

7.删除相对来说有点麻烦;分为四种情况,要删除的结点无儿子,只有左儿子,只有右儿子,同时有左右儿子。递归代码如下:

<span style="font-size:12px;">template<typename T>
Node<T>* Delete(Node<T>*Root, T key){
	Node<T>*x = nullptr;
	if (!Root)
		return nullptr;                          //空指针无法删除
	if (key > Root->key){                        //右子树中删除 
		x = Delete(Root->right, key);
		Root->right = x;
		if (x)                                  //有可能x为空,要注意
			x->prev = Root;
	}
	else if (key < Root->key){                   //左子树中删除
		x = Delete(Root->left, key);
		Root->left = x;
		if (x)                                   //有可能x为空,要注意
	    	x->prev = Root;
	}
	else{                                        //找到了要删除的结点
		x = Root;
		if (!Root->left&&!Root->right)           //没有儿子
			Root = nullptr;
		else if (!Root->left){                   //只有右儿子
			Root = Root->right;
			if (!x->prev)                        //x是根结点
				Root->prev = nullptr;
			else if (x->prev->right == x)        //x是右儿子
				x->prev->right = Root;
			else                                 //x是左儿子
				x->prev->left = Root;
			Root->prev = x->prev;
			delete x;
		}
		else if (!Root->right){                 //只有左儿子
			Root = Root->left;
			if (!x->prev)                        //x是根结点
				Root->prev = nullptr;
			else if (x->prev->right == x)        //x是右儿子
				x->prev->right = Root;
			else                               //x是左儿子
				x->prev->left = Root;
			Root->prev = x->prev;
			delete x;
		}
		else{                                //两个儿子都有
			x = x->right;
			while (x->left)
				x = x->left;                //向左找到替换的结点
			Root->key = x->key;             //卫星数据覆盖
			Node<T>*y = Delete(Root->right, x->key);  //在Root右子树删除x->key
			if (y)                            //漏掉可能异常
		     	y->prev = Root;
			Root->right = y;
		}
	}
	return Root;
}
</span>
以下是二叉搜索树基本数据结构非递归的C++实现。注意模板类的定义和实现在都包含在头文件中。

/*bintree.head*/
#pragma once
#include<iostream>
#include<stack>
using namespace std;
template<typename T>
struct Node{
	T key;
	Node<T>*left = nullptr, *right = nullptr, *prev = nullptr;
};
template<typename T>
class BinTree{
private:
	Node<T>* root;
	int totalNode_; 
	void Transplant(Node<T>*u,Node<T>*v);
public:
	BinTree<T>(){ root = nullptr; totalNode_ = 0; }
	Node<T>*getRoot()const{ return root; }
	int getNumberOfNode()const{ return totalNode_; }
	void insertKey(T const &key);
	void creatBinTree(T const *a, int const &n);
	void inorderPrint();
	Node<T>* findKey(T const &key);                      
	bool deleteKey(T const &key);                               
	Node<T>* treeMaxMum();
	Node<T>* treeMinMum();
	Node<T>* treeSuccessor(Node<T>*z); 
};

template <typename T>
void BinTree<T>::insertKey(T const &key){
	Node<T>* y = new Node<T>;              //申请空间
	y->key = key;
	y->left = y->right = y->prev = NULL;   //初始化指针
	if (!root){                            //插入到头结点
		root = y;
		return;
	}
	Node<T>* x = root;
	Node<T>* X_Prev = nullptr;             //表示x的前驱
	while (x != nullptr){
		X_Prev = x;
		if (key > x->key)
			x = x->right;
		else
			x = x->left;
	}                                     //将y插入在X_Prev后面
	y->prev = X_Prev;
	if (key > X_Prev->key)
		X_Prev->right = y;
	else
		X_Prev->left = y;
	totalNode_++;
}

template<typename T>
void BinTree<T>::inorderPrint(){
	stack<Node<T>*> S;
	Node<T>*nowNode = root;
	while (nowNode || !S.empty()){
		while (nowNode){    //沿途左儿子全部压入栈
			S.push(nowNode);
			nowNode = nowNode->left;
		}
		if (!S.empty()){
			nowNode = S.top();
			S.pop();        //顶元素出栈
			cout << nowNode->key << "  ";
			nowNode = nowNode->right;    //转向右儿子
		}
	}
	cout << endl;
}

template <typename T>
void BinTree<T>::creatBinTree(T const *a, int const &n){
	int i;
	for (i = 0; i < n; i++)
		insertKey(a[i]);
}

template <typename T>
Node<T>* BinTree<T>::findKey(T const &key){
	Node<T>*x = root;
	while (x){
		if (key>x->key)    //比当前节点大,则一定在当前节点右子树
			x = x->right;
		else if (key < x->key)  //小则在左子树
			x = x->left;
		else
			break;            //相等时即为找到
	}
	return x;                 //找到就返回此节点,否则返回空
}

template<typename T>
Node<T>* BinTree<T>::treeMaxMum(){
	Node<T>*x = root;
	while (x->right != nullptr){
		x = x->right;
	}
	return x;
}

template<typename T>
Node<T>* BinTree<T>::treeMinMum(){
	Node<T>* x = root;
	while (x->left != nullptr){
		x = x->left;
	}
	return x;
}

template<typename T>
Node<T>* BinTree<T>::treeSuccessor(Node<T>* z){
	Node<T>*x = z;
	if (x->right) {      //如果有右子树,则一定是右子树的最小结点
		x = x->right;
		while (x->left) x = x->left;
		return x;
	}
	/*否则一定在x的有左孩子的最低层祖先*/
	Node<T>*y = x->prev;
	while (y&&x != y->left){    //向上寻找
		x = y;
		y = x->prev;
	}
	return y;
}

template<typename T>
void BinTree<T>::Transplant(Node<T>*u, Node<T>*v){//用使用根结点为v的子树替代根结点为u的子树
	if (!u->prev)                                 //u是总的树根
		root = v;
	else if (u->prev->right == u)                 //u是右儿子
		u->prev->right = v;
	else                                          //u是左儿子
		u->prev->left = v;
	if (v != nullptr)                               //空间点单独处理
		v->prev = u->prev;
}

template<typename T>
bool BinTree<T>::deleteKey(T const &key){
	Node<T>*DeleteNode = findKey(key);
	if (!DeleteNode)
		return false;
	if (!DeleteNode->left)                        //如果没有左儿子或者没有儿子
		Transplant(DeleteNode, DeleteNode->right); //直接用右子树代替
	else if (!DeleteNode->right)                  //如果没有右儿子
		Transplant(DeleteNode, DeleteNode->left);  //直接用左子树代替
	else{                                         //同时有左儿子和右儿子
		Node<T>*y = DeleteNode->right;            //寻找右边关键字最小的结点
		while (y->left)
			y = y->left;                          //沿路向左找到来替换的儿子结点y
		if (y != DeleteNode->right){              //如若顶替的结点不是要删除结点的右儿子
			Transplant(y, y->right);
			y->right = DeleteNode->right;
			DeleteNode->right->prev = y;         /*这部分if语句是将结点y变为待替换子树结点的根*/
		}
		Transplant(DeleteNode, y);               //完成右边子树代替
		y->left = DeleteNode->left;                //处理DeleteNode左边子树
		DeleteNode->left->prev = y;
	}
	return true;
}</span>

/*源.cpp*/
#include"binTree.h"
int main(){
	/*测试*/
    char a[8] = { 'i','d','y','b', 's','h','c','f'};
	BinTree<char>NewTree;
	NewTree.creatBinTree(a,8);  //构建二叉搜索树
	NewTree.inorderPrint();

	Node<char>*pos = NewTree.findKey('h');
	cout << pos->key << endl;

	pos = NewTree.treeMinMum();
	cout << pos->key << endl;

	pos = NewTree.findKey('c');
	pos = NewTree.treeSuccessor(pos);
	cout << pos->key << endl;

    NewTree.insertKey('a');
	NewTree.inorderPrint();

	NewTree.deleteKey('b');   
	NewTree.inorderPrint();
	return 0;
}



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值