昨天碰到了二叉搜索树(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