二叉搜索树介绍

二叉搜索树(Binary Search Tree,简称BST),又叫二叉排序树,二叉查找树,是一种特殊的树型结构,它有如下特点。

任一节点的左(右)子树中,所有节点(若存在)均不大于(不小于)r。我们把这种特点叫做顺序性。

二叉搜索树的数据结构:

 

1 struct node
2 {
3     int data;
4     node*lchild,*rchild,*parent;
5 };

 

 

常用操作介绍

1. 查找

  查找是二叉搜索树最主要的功能,二叉搜索树的顺序性也利于查找的实现。和二分法类似,可以采用分治算法的思想进行,逐步缩小查找范围,直到发现目标或搜索范围为空。用一个流程图来表示就是下面这样:

 

查找代码实现:

 

 1 node*findNode(int data,node*Node)
 2 {
 3     if(!Node)
 4         return nullptr;
 5     else
 6     {
 7         if(Node->data==data)
 8             return Node;
 9         return Node->data>data?findNode(data,Node->lchild):findNode(data,Node->rchild);
10     }
11 }

 

2. 插入

二叉搜索树的顺序性便于查找,但是却给搜索树的维护和更新带来了一点困难,在插入和删除节点的时候,必须要保持二叉搜索树作为数据结构的完整性和一致性。相比删除操作,插入操作更容易理解一点。假设有一个序列为{23,3,24,54,12},我们拿这个这个序列建一个二叉查找树,模拟一下插入操作。

 

 

插入代码实现

 

 1 void insertNode(int data,node*&BSTree,node*parent)
 2 {
 3     if(!BSTree)
 4     {
 5         BSTree = new node;
 6         BSTree->data = data;
 7         BSTree->lchild = BSTree->rchild = nullptr;
 8         BSTree->parent = parent;
 9         return;
10     }
11     BSTree->data>data?insertNode(data,BSTree->lchild,BSTree):insertNode(data,BSTree->rchild,BSTree);
12     return;
13 }

 

 

 

 

3. 删除 

相比于插入算法,二叉搜索树的删除算法要更复杂一点,要分为三种情况处理:

1. 删除的节点是叶子节点,这种情况很好处理,只要把该节点删除就好了

 

2. 删除的节点有一颗左子树或者右子树,那么用这棵子树的根节点替换被删除的节点

 

3. 最麻烦的情况就是被删除的节点同时拥有左子树和右子树

这个时候我们需要寻找的被删除节点的直接后继节点,也就是在该节点右子树最小的那个节点。注意,这个时候该节点不可能有左子树,否则它不会是最小的节点,那么,就可以分为两种情况:

1. 直接后继节点的父亲节点是待删除节点,那用这个后继节点替换待删除节点,如果它有右子树,则右子树依然属于该节点。

 

                                                                             

2. 直接后继节点是的父亲节点是不待删除节点自身,则除了用这个后继节点替换待删除节点以外,如果它有右子树,那还要它的右子树交给它的父亲节点做左子树。

                                                                                                  

 删除代码实现:

 1 node*findNextNode(node*Node)
 2 {
 3     if(!Node->lchild)
 4         return Node;
 5     else
 6         return findNextNode(Node->lchild);
 7 }
 8 void removeNode(int data,node*BSTree)
 9 {
10     node*delNode = findNode(data,BSTree);
11     if(!delNode->lchild&&!delNode->rchild)  // 叶子节点
12     {
13         if(delNode->parent)            //假设双亲节点存在
14         {
15             node*tmp = delNode->parent;
16             if(tmp->lchild==delNode) tmp->lchild = nullptr;
17             if(tmp->rchild==delNode) tmp->rchild = nullptr;
18         }
19         delete delNode;
20     }
21     else if((!delNode->lchild&&delNode->rchild)||(!delNode->rchild&&delNode->lchild))  //有一棵左子树或者右子树
22     {
23         node*NextNode = delNode->lchild?delNode->lchild:delNode->rchild;
24         if(delNode->parent)
25         {
26             node*tmp = delNode->parent;
27             NextNode->parent = tmp;
28             tmp->lchild==delNode?tmp->lchild=NextNode:tmp->rchild=NextNode;
29         }
30         else
31             NextNode->parent = nullptr;
32         delete delNode;
33     }
34     else        //最复杂的情况
35     {
36         node*NextNode = findNextNode(delNode);   //找到后继节点
37         node*NextNodeParent = NextNode->parent;  // 找到后继节点的父亲节点
38         if(NextNodeParent==delNode)
39         {
40             if(delNode->parent)
41             {
42                 node*tmp = delNode->parent;
43                 NextNode->parent=tmp;
44                 tmp->lchild==delNode?tmp->lchild=NextNode:tmp->rchild = NextNode;
45                 delNode->lchild->parent = NextNode;
46                 NextNode->lchild = delNode->lchild;
47             }
48             else
49             {
50                 delNode->lchild->parent = NextNode;
51                 NextNode->lchild = delNode->lchild;
52             }
53         }
54         else
55         {
56             swap(NextNode->data,delNode->data);
57             if(NextNode->rchild)
58             {
59                 NextNodeParent->lchild = NextNode->rchild;
60                 NextNode->rchild->parent = NextNode;
61             }
62         }
63         delete delNode;
64     }
65     return;
66 }