您的位置:首页 > 理论基础 > 数据结构算法

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

2016-03-04 14:49 369 查看
二叉搜索树中一个结点包含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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: