您的位置:首页 > 其它

二叉搜索树(BST)递归与非递归的插入、删除、查找的实现

2016-03-03 18:06 986 查看
昨天碰到了二叉搜索树(BST)这种数据结构,索性详细的学习了一遍。

BST的定义:

如果一棵树的左子树不为空,那么其所有节点的值均小于其根结点的值,如果右子树不为空,那么其所有节点的值均大于其根结点的值,它的左右子树也满足如上性质。空树也是BST。

我的BST的实现是以没有重复元素为前提,其实有重复元素也无大碍,只是把实现过程中相关的<改成<=即可,

节点结构定义:

class Node{
public:
int val;
Node *left, *right;
Node() {}
Node(int val) : val(val), left(NULL), right(NULL) {}
};


BST结构定义及实现方法:

class BST{
private:
Node *root;
void Recursion_Insert_Node(Node *&node, int x);//递归插入结点
void Non_Recursion_Insert_Node(Node **node, int x);//非递归插入结点
Node *Recursion_Find_Node(Node *node, int x);//递归查找结点
Node *Non_Recursion_Find_Node(Node *root, int x);//非递归查找结点
void Delete_Node(Node **root, int x);//删除结点
void preOrder_Traverse(Node *root);//前序遍历
void inOrder_Traverse(Node *root);//中序遍历
void postOrder_Traversal(Node *root);//后序遍历
void Delete_BST(Node *node);//释放空间
public:
BST();
~BST();
void Create_BST(int *num, int n);//创建BST
Node *Find_Node(int x);
void Delete_Node(int x);
void preOrder_Traverse();
void inOrder_Traverse();
void postOrder_Traversal();
};


让我们首先来看看插入结点是如何实现的:

对于第一个要存入的值,我们将它设置为根结点,然后对于小于根结点的值,我们将其移动到左子树上再进行比较,直到移动到成为叶子节点即可,大于根结点的值同理。

具体实现:

递归:

void BST::Recursion_Insert_Node(Node *&node, int x){
if(node == NULL){
node = new Node(x);
}
else if(node->val > x){
Recursion_Insert_Node(node->left, x);
}
else if(node->val < x){
Recursion_Insert_Node(node->right, x);
}
}


非递归:

void BST::Non_Recursion_Insert_Node(Node **root, int x){
Node *p = *root;
Node *fa = *root;
while(p){
if(p->val == x){
printf("%d is already exist!\n", x);
return;
}
fa = p;
if(p->val > x){
p = p->left;
}
else{
p = p->right;
}
}
if(fa == NULL){
*root = new Node(x);
}
else if(fa->val > x){
fa->left = new Node(x);
}
else{
fa->right = new Node(x);
}
}


注意对于非递归的情况,Node的类型为指向指针的指针,不能单单传指针,这是因为如果只传指针,形参为指针值的拷贝,当root指向NULL的时候,在函数内部new的节点并不会被实际的指针指到。还有用指针的引用也不行,因为这样会使得指向根结点的指针指向其子节点。

对于查找结点的实现:

思想和插入的一样,只是可以使用指针,而不用指向指针的指针,因为我们只需要找到所查找元素的地址,并不需要对其操作,使用指针可以很轻松的完成工作。

递归:

Node *BST::Recursion_Find_Node(Node *node, int x){
if(node == NULL)
return NULL;
if(node->val == x)
return node;
if(node->val > x)
return Recursion_Find_Node(node->left, x);
else
return Recursion_Find_Node(node->right, x);
}


非递归:

Node *BST::Non_Recursion_Find_Node(Node *node, int x){
if(node == NULL)
return NULL;
while(node){
if(node->val == x)
return node;
else if(node->val > x)
node = node->left;
else
node = node->right;
}
return node;
}


最后就是删除操作了:

删除操作实在是想不出递归写法。。。

对于BST的删除操作,有三种情况:

1:删除节点恰好为叶子节点

这种情况最好处理,只需要将其父节点指向空,然后delete该节点即可。

2:删除节点恰好有一个分支

我们只需要将其父亲节点指向其儿子节点即可,然后delete掉它,也比较简单。

3:删除节点恰好有两个分支

这种情况比较麻烦,有两种处理方法,在说这两种方法之前我们首先要知道两个概念:

节点的前驱:小于该节点的最大节点,前驱没有右子树

节点的后继:大于该节点的最小节点,后继没有左子树

了解后我们就可以阐述方法了:

第一种方法就是找到该节点的前驱,然后将它的值赋值给要删除的节点,最后删除这个前驱即可。第二种方法和第一种类似,就是找到该节点的后继,然后将它的值赋值给要删除的节点,最后删除这个后继即可。这里会用到前驱没有右子树,后继没有左子树的特性,具体实现看代码吧。

void BST::Delete_Node(Node **root, int x){
Node *p = *root;
Node *fa = *root;
while(p){
if(p->val == x){
break;
}
fa = p;
if(p->val > x){
p = p->left;
}
else{
p = p->right;
}
}
if(p == NULL){
printf("%d is not found!\n", x);
return;
}
if(p->left == NULL && p->right == NULL){//若p为叶子结点
if(p == *root){//p为根结点
*root = NULL;
}
else if(fa->left == p){
fa->left = NULL;
}
else{
fa->right = NULL;
}
delete p;
}
else if(p->left == NULL || p->right == NULL){//若p为单支结点
if(p == *root){
if(p->left != NULL){
*root = p->left;
}
else{
*root = p->right;
}
}
else{
if(fa->left == p){
if(p->left != NULL){
fa->left = p->left;
}
else{
fa->left = p->right;
}
}
else{
if(p->left != NULL){
fa->right = p->left;
}
else{
fa->right = p->right;
}
}
}
delete p;
}
else{//若p为双支结点
Node *parent = p;
Node *child = p->right;
while(child->left){
parent = child;
child = child->left;
}
p->val = child->val;
if(parent == p){
p->right = child->right;
}
else{
parent->left = child->right;
}
delete child;
}
}


程序总览:

#include <cstdio>
using namespace std;

class Node{ public: int val; Node *left, *right; Node() {} Node(int val) : val(val), left(NULL), right(NULL) {} };
class BST{ private: Node *root; void Recursion_Insert_Node(Node *&node, int x);//递归插入结点 void Non_Recursion_Insert_Node(Node **node, int x);//非递归插入结点 Node *Recursion_Find_Node(Node *node, int x);//递归查找结点 Node *Non_Recursion_Find_Node(Node *root, int x);//非递归查找结点 void Delete_Node(Node **root, int x);//删除结点 void preOrder_Traverse(Node *root);//前序遍历 void inOrder_Traverse(Node *root);//中序遍历 void postOrder_Traversal(Node *root);//后序遍历 void Delete_BST(Node *node);//释放空间 public: BST(); ~BST(); void Create_BST(int *num, int n);//创建BST Node *Find_Node(int x); void Delete_Node(int x); void preOrder_Traverse(); void inOrder_Traverse(); void postOrder_Traversal(); };

BST::BST(){
this->root = NULL;
}

void BST::Create_BST(int *num, int n){
for(int i = 0; i < n; i++){
// Recursion_Insert_Node(this->root, num[i]);
Non_Recursion_Insert_Node(&this->root, num[i]);
}
}

void BST::Recursion_Insert_Node(Node *&node, int x){ if(node == NULL){ node = new Node(x); } else if(node->val > x){ Recursion_Insert_Node(node->left, x); } else if(node->val < x){ Recursion_Insert_Node(node->right, x); } }

void BST::Non_Recursion_Insert_Node(Node **root, int x){ Node *p = *root; Node *fa = *root; while(p){ if(p->val == x){ printf("%d is already exist!\n", x); return; } fa = p; if(p->val > x){ p = p->left; } else{ p = p->right; } } if(fa == NULL){ *root = new Node(x); } else if(fa->val > x){ fa->left = new Node(x); } else{ fa->right = new Node(x); } }

void BST::Delete_Node(int x){
Delete_Node(&this->root, x);
}

void BST::Delete_Node(Node **root, int x){ Node *p = *root; Node *fa = *root; while(p){ if(p->val == x){ break; } fa = p; if(p->val > x){ p = p->left; } else{ p = p->right; } } if(p == NULL){ printf("%d is not found!\n", x); return; } if(p->left == NULL && p->right == NULL){//若p为叶子结点 if(p == *root){//p为根结点 *root = NULL; } else if(fa->left == p){ fa->left = NULL; } else{ fa->right = NULL; } delete p; } else if(p->left == NULL || p->right == NULL){//若p为单支结点 if(p == *root){ if(p->left != NULL){ *root = p->left; } else{ *root = p->right; } } else{ if(fa->left == p){ if(p->left != NULL){ fa->left = p->left; } else{ fa->left = p->right; } } else{ if(p->left != NULL){ fa->right = p->left; } else{ fa->right = p->right; } } } delete p; } else{//若p为双支结点 Node *parent = p; Node *child = p->right; while(child->left){ parent = child; child = child->left; } p->val = child->val; if(parent == p){ p->right = child->right; } else{ parent->left = child->right; } delete child; } }

Node *BST::Find_Node(int x){
// return Recursion_Find_Node(this->root, x);
return Non_Recursion_Find_Node(this->root, x);
}

void BST::preOrder_Traverse(){
preOrder_Traverse(this->root);
}

void BST::inOrder_Traverse(){
inOrder_Traverse(this->root);
}

void BST::postOrder_Traversal(){
postOrder_Traversal(this->root);
}

Node *BST::Recursion_Find_Node(Node *node, int x){ if(node == NULL) return NULL; if(node->val == x) return node; if(node->val > x) return Recursion_Find_Node(node->left, x); else return Recursion_Find_Node(node->right, x); }

Node *BST::Non_Recursion_Find_Node(Node *node, int x){ if(node == NULL) return NULL; while(node){ if(node->val == x) return node; else if(node->val > x) node = node->left; else node = node->right; } return node; }

void BST::preOrder_Traverse(Node *root){
if(root != NULL){
printf("%d ", root->val);
preOrder_Traverse(root->left);
preOrder_Traverse(root->right);
}
}

void BST::inOrder_Traverse(Node *root){
if(root != NULL){
inOrder_Traverse(root->left);
printf("%d ", root->val);
inOrder_Traverse(root->right);
}
}

void BST::postOrder_Traversal(Node *root){
if(root != NULL){
postOrder_Traversal(root->left);
postOrder_Traversal(root->right);
printf("%d ", root->val);
}
}

void BST::Delete_BST(Node *node){
if(node == NULL)
return;
if(node->left != NULL)
Delete_BST(node->left);
if(node->right != NULL)
Delete_BST(node->right);
delete node;
}

BST::~BST(){
Delete_BST(this->root);
}

int main()
{
return 0;
}


代码什么的就不要吐槽了T T
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: