二叉搜索树(BST)递归与非递归的插入、删除、查找的实现
2016-03-03 18:06
986 查看
昨天碰到了二叉搜索树(BST)这种数据结构,索性详细的学习了一遍。
BST的定义:
如果一棵树的左子树不为空,那么其所有节点的值均小于其根结点的值,如果右子树不为空,那么其所有节点的值均大于其根结点的值,它的左右子树也满足如上性质。空树也是BST。
我的BST的实现是以没有重复元素为前提,其实有重复元素也无大碍,只是把实现过程中相关的<改成<=即可,
节点结构定义:
BST结构定义及实现方法:
让我们首先来看看插入结点是如何实现的:
对于第一个要存入的值,我们将它设置为根结点,然后对于小于根结点的值,我们将其移动到左子树上再进行比较,直到移动到成为叶子节点即可,大于根结点的值同理。
具体实现:
递归:
非递归:
注意对于非递归的情况,Node的类型为指向指针的指针,不能单单传指针,这是因为如果只传指针,形参为指针值的拷贝,当root指向NULL的时候,在函数内部new的节点并不会被实际的指针指到。还有用指针的引用也不行,因为这样会使得指向根结点的指针指向其子节点。
对于查找结点的实现:
思想和插入的一样,只是可以使用指针,而不用指向指针的指针,因为我们只需要找到所查找元素的地址,并不需要对其操作,使用指针可以很轻松的完成工作。
递归:
非递归:
最后就是删除操作了:
删除操作实在是想不出递归写法。。。
对于BST的删除操作,有三种情况:
1:删除节点恰好为叶子节点
这种情况最好处理,只需要将其父节点指向空,然后delete该节点即可。
2:删除节点恰好有一个分支
我们只需要将其父亲节点指向其儿子节点即可,然后delete掉它,也比较简单。
3:删除节点恰好有两个分支
这种情况比较麻烦,有两种处理方法,在说这两种方法之前我们首先要知道两个概念:
节点的前驱:小于该节点的最大节点,前驱没有右子树
节点的后继:大于该节点的最小节点,后继没有左子树
了解后我们就可以阐述方法了:
第一种方法就是找到该节点的前驱,然后将它的值赋值给要删除的节点,最后删除这个前驱即可。第二种方法和第一种类似,就是找到该节点的后继,然后将它的值赋值给要删除的节点,最后删除这个后继即可。这里会用到前驱没有右子树,后继没有左子树的特性,具体实现看代码吧。
程序总览:
代码什么的就不要吐槽了T T
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
相关文章推荐
- 51nod--Dijkstra算法
- HDU 1181 变形课
- php依赖管理工具Composer的安装和使用
- new alloc/init 区别
- [转]数据库分区
- 如何删除win10多余的输入法
- CPU
- 操作系统做什么?
- 写出发帖数最多的十个人的名字
- OpenGL中显示列表的创建
- iOS开发-CGAffineTransformMakeRotation改变了中心解决的方法
- mysql联查
- 计算机科学领域的任何问题都可以通过增加一个间接的中间层来解决
- javaweb开发-j2ee无法加载tomcat7服务器
- maven--私服的搭建(Nexus的使用)
- QTP无法录制web脚本的解决方法
- linux 上 crontab 使用教程
- 另一种可左右滑动的横向GridView的实现
- 对Android回调的理解
- css3 pointer-events 让对象如透明般直接响应下层对象的鼠标事件