二叉排序树(二叉搜索树)



二叉排序树(二叉搜索树)

二叉排序树

二叉排序树又称为二叉查找树,它是一种特殊结构的二叉树,其定义为:二叉树排序树或者是一棵空树,或者是具有如下性质的二叉树:

(1)若它的左子树非空,则左子树上所有结点的值均小于根结点的值;

(2)若它的右子树非空,则右子树上所有结点的值均大于根结点的值;

(3)它的左右子树也分别为二叉排序树。

这是一个递归定义。由定义可以得出二叉排序树的一个重要性质:中序遍历一个二叉排序树时可以得到一个递增有序序列。图1所示的二叉树就是一棵二叉排序树,若中序遍历图8.3(a)的二叉排序树,则可得到一个递增有序序列为:1,2,3,4,5,6,7,8,9。

 

    

 

 

(a) 二叉排序树示例1                               (b) 二叉排序树示例2(根据字符ASCII码的大小)

图1二叉排序树

在下面讨论二叉排序树的操作中,使用二叉链表作为存储结构,其结点结构说明如下:

typedef struct node

{ KeyType key ; /*关键字的值*/

struct node *lchild,*rchild;/*左右指针*/

}bstnode,*BSTree;

 

1.二叉排序树的插入和生成

已知一个关键字值为key的结点s,若将其插入到二叉排序树中,只要保证插入后仍符合二叉排序树的定义即可。插入可以用下面的方法进行:1)若二叉树序树是空树,则key成为二叉树序树的根;2)若二叉树序树非空,则将key与二叉树序树的根进行比较,如果key的值等于根结点的值,则停止插入,如果key的值小于根结点的值,则将key插入左子树,如果key的值大于根结点的值,则将key插入右子树。

例如,设关键字的输入顺序为:45,24 ,53,12,28,90,按上述算法生成的二叉排序树的过程如图2所示。

 


 

 

 


 

 

 

 

 

图2 二叉排序树的建立过程

对同样一些元素值,如果输入顺序不同,所创建的二叉树形态也不同。如上面的例子如果输入顺序为 24,53,90,12,28,45,则生成的二叉排序树如图3所示:

 

 

图3输入顺序不同所建立的不同二叉排序树

 2.二叉排序树的查找过程

由其定义可见,二叉排序树的查找过程为:
(1)若查找树为空,查找失败。
(2)查找树非空,将给定值key与查找树的根结点关键码比较。
(3)若相等,查找成功,结束查找过程,否则:
① 当给值key小于根结点关键码,查找将在以左孩子为根的子树上继续进行,转(1)。
② 当给值key大于根结点关键码,查找将在以右孩子为根的子树上继续进行,转(1)。


3.二叉排序树删除操作

从二叉排序树中删除一个结点之后,要求其仍能保持二叉排序树的特性。
设待删结点为*p(p为指向待删结点的指针),其双亲结点为*f,删除可以分三种情况,如图6-4所示。

 

(1)*p结点为叶结点,由于删去叶结点后不影响整棵树的特性,所以,只需将被删结点的双亲结点相应指针域改为空指针,如图6-4(a)所示。
(2)*p结点只有右子树或只有左子树,此时,只需将替换*f结点的*p子树即可,如图6-4(b)、(c)所示。
(3)*p结点既有左子树又有右子树,可按中序遍历保持有序地进行调整,如图6-4(d)、(e)所示。

设删除*p结点前,中序遍历序列为:
① P为F的左子女时有:…,Pi子树,P,Pj,S子树,Pk,Sk子树,…,P2,S2子树,P1,S1子树,F,…。
② P为F的右子女时有:…,F,Pi子树,P,Pj,S子树,Pk,Sk子树,…,P2,S2子树,P1,S1子树,…。
则删除*p结点后,中序遍历序列应为:
① P为F的左子女时有:…,Pi子树,Pj,S子树,Pk,Sk子树,…,P2,S2子树,P1,S1子树,F,…。
② P为F的右子女时有:…,F,Pi子树,Pj,S子树,Pk,Sk子树,…,P2,S2子树,P1,S1子树,…。
有两种调整方法:
① 直接令Pi为*f相应的子树,以Pr为Pi中序遍历的最后一个结点Pk的右子树。
② 令*p结点的直接前驱Pr或直接后继(对Pi子树中序遍历的最后一个结点Pk)替换*p结点,再按(2)的方法删去Pr或Pk。
【算法分析】
对给定序列建立二叉排序树,若左右子树均匀分布,则其查找过程类似于有序表的折半查找。但若给定序列原本有序,则建立的二叉排序树就蜕化为单链表,其查找效率和顺序查找一样。因此,对均匀的二叉排序树进行插入或删除结点后,应进行调整,使其依然保持均匀。

程序代码实现:

  1. package binarytree;
  2. import java.util.ArrayDeque;
  3. import java.util.ArrayList;
  4. import java.util.List;
  5. import java.util.Queue;
  6. public class BinarySortTree<T extends Comparable<T>> {
  7.     //二叉搜索树,二叉排序树
  8.     public class Node{
  9.         T data;
  10.         Node parent;
  11.         Node lchild;
  12.         Node rchild;
  13.         public Node(T data,Node parent,Node lchild,Node rchild){
  14.             this.data=data;
  15.             this.parent=parent;
  16.             this.lchild=lchild;
  17.             this.rchild=rchild;
  18.         }
  19.         public boolean equals(Object obj){
  20.             if (this==obj) {
  21.                 return true;
  22.             }
  23.             if (obj.getClass()==Node.class) {
  24.                 Node target=(Node)obj;
  25.                 return data.equals(target.data)&&
  26.                         lchild==target.lchild&&
  27.                         rchild==target.rchild&&
  28.                         parent==target.parent;
  29.             }
  30.             return false;
  31.         }
  32.         @Override
  33.         public String toString() {
  34.             return ”Node [data="+data+"]“;
  35.         }
  36.     }
  37.     private Node root;
  38.     public BinarySortTree() {
  39.         root=null;
  40.     }
  41.     public BinarySortTree(T t) {
  42.         this.root = new Node(t, null, null, null);
  43.     }
  44.     //添加节点
  45.     public void add(T element){
  46.         if (root==null) {
  47.             root=new Node(element, null, null, null);
  48.         } else {
  49.             Node current=root;
  50.             Node parent=null;
  51.             int cmp=0;
  52.             //搜索合适的叶子节点,以该叶子节点为父节点添加新节点
  53.             do {
  54.                 parent=current;
  55.                 cmp=element.compareTo(current.data);
  56.                 if (cmp>0) {
  57.                     current=current.rchild;
  58.                 } else {
  59.                     current=current.lchild;
  60.                 }
  61.             } while (current!=null);
  62.             //创建新节点
  63.             Node newNode=new Node(element, parent, null, null);
  64.             if (cmp>0) {
  65.                 parent.rchild=newNode;
  66.             } else {
  67.                 parent.lchild=newNode;
  68.             }
  69.         }
  70.     }
  71.     //删除节点
  72.     public void remove(T element){
  73.         //获取要删除的节点
  74.         Node target=getNode(element);
  75.         if (target==null) {
  76.             return;
  77.         }
  78.         //左、右子树是否为空
  79.         if (target.lchild==null&&target.rchild==null) {
  80.             if (target==root) {
  81.                 root=null;
  82.             } else {
  83.                 if (target==target.parent.lchild) {
  84.                     target.parent.lchild=null;
  85.                 } else {
  86.                     target.parent.rchild=null;
  87.                 }
  88.                 target.parent=null;
  89.             }
  90.         } else if(target.lchild==null&&target.rchild!=null){
  91.             if (target==root) {
  92.                 root=target.rchild;
  93.             } else {
  94.                 if (target==target.parent.lchild) {
  95.                     target.parent.lchild=target.rchild;
  96.                 } else {
  97.                     target.parent.rchild=target.rchild;
  98.                 }
  99.                 target.rchild.parent=target.parent;
  100.             }
  101.         }else if(target.lchild!=null&&target.rchild==null){
  102.             if (target==root) {
  103.                 root=target.lchild;
  104.             } else {
  105.                 if (target==target.parent.lchild) {
  106.                     target.parent.lchild=target.lchild;
  107.                 } else {
  108.                     target.parent.rchild=target.lchild;
  109.                 }
  110.                 target.lchild.parent=target.parent;
  111.             }
  112.         }else {
  113.             Node lchildMaxNode=target.lchild;//存放左孩子最大的节点
  114.             while (lchildMaxNode.rchild!=null) {
  115.                 lchildMaxNode=lchildMaxNode.rchild;
  116.             }
  117.             lchildMaxNode.parent.rchild=null;
  118.             lchildMaxNode.parent=target.parent;
  119.             if (target==target.parent.lchild) {
  120.                 target.parent.lchild=lchildMaxNode;
  121.             } else {
  122.                 target.parent.rchild=lchildMaxNode;
  123.             }
  124.             lchildMaxNode.lchild=target.lchild;
  125.             lchildMaxNode.rchild=target.rchild;
  126.             target.parent=target.lchild=target.rchild=null;
  127.         }
  128.     }
  129.     //获取要指定的节点
  130.     public Node getNode(T element) {
  131.         Node p=root;
  132.         while (p!=null) {
  133.             int cmp=element.compareTo(p.data);
  134.             if (cmp>0) {
  135.                 p=p.rchild;
  136.             } else if (cmp<0) {
  137.                 p=p.lchild;
  138.             }else {
  139.                 return p;
  140.             }
  141.         }
  142.         return null;
  143.     }
  144.     //广度优先遍历
  145.     public List<Node> breadthFrist(){
  146.         Queue<Node> queue=new ArrayDeque<Node>();
  147.         List<Node> list=new ArrayList<Node>();
  148.         if (root!=null) {
  149.             queue.offer(root);
  150.         }
  151.         while (!queue.isEmpty()) {
  152.             list.add(queue.peek());
  153.             Node pNode=queue.poll();
  154.             if (pNode.lchild!=null) {
  155.                 queue.offer(pNode.lchild);
  156.             }
  157.             if (pNode.rchild!=null) {
  158.                 queue.offer(pNode.rchild);
  159.             }
  160.         }
  161.         return list;
  162.     }
  163. }