zoukankan      html  css  js  c++  java
  • 二叉排序树

      当用线性表作为表的组织形式时,可以有三种查找法。其中以二分查找效率最高。但由于二分查找要求表中

    节点按关键字有序,且不能用链表作存储结构,因此,当表的插入或删除操作频繁时,为维护表的有序性,

    势必要移动表中很多节点。这时由移动节点引起的额外时间开销,就会抵消二分查找的优点。也就是说,

    二分查找只适用于静态查找表。

      若要对动态查找表进行高效率的查找,可采用下面介绍的几种特殊的二叉树或树作为表的组织形式。不妨将它们统称为树表。

    二叉排序树

    1、二叉排序树的定义
     
     
     二叉排序树(Binary Sort Tree)又称二叉查找(搜索)树(Binary Search Tree)。其定义为:二叉排序树或者是空树,或者是满足如下性质的二叉树:
    ①若它的左子树非空,则左子树上所有结点的值均小于根结点的值;
    ②若它的右子树非空,则右子树上所有结点的值均大于根结点的值;
    ③左、右子树本身又各是一棵二叉排序树。
      上述性质简称二叉排序树性质(BST性质),故二叉排序树实际上是满足BST性质的二叉树。

    2、二叉排序树的特点
      
    由BST性质可得:
      (1) 二叉排序树中任一结点x,其左(右)子树中任一结点y(若存在)的关键字必小(大)于x的关键字。
      (2) 二叉排序树中,各结点关键字是惟一的。
      注意:
      实际应用中,不能保证被查找的数据集中各元素的关键字互不相同,所以可将二叉排序树定义中BST性质(1)里的"小于"改为"大于等于",或将BST性质(2)里的"大于"改为"小于等于",甚至可同时修改这两个性质。
      (3) 按中序遍历该树所得到的中序序列是一个递增有序序列。


     java版源代码:

      1 package arrange;
      2 
      3 public class BinarySortTree {
      4     BSTreeNode rootNode;// 创建根节点
      5     // 创建二叉查找树
      6 
      7     public void createBSTree(int[] A) {
      8         rootNode = new BSTreeNode(A[0], null, null);// 初始化根节点
      9 
     10         for (int i = 1; i < A.length; i++) {// 逐个取出数组A中的元素用来构造二叉查找树
     11             BSTreeNode tmpNode = rootNode; // 为什么rootNode每次循环后都能增加新的值 ?
     12             // System.out.println(tmpNode.data);
     13             while (true) {
     14                 if (tmpNode.data >= A[i]) {// 小于等于根节点
     15                     if (tmpNode.left == null) {// 如果左孩子为空,这把当前数组元素插入到左孩子节点的位置
     16                         tmpNode.left = new BSTreeNode(A[i], null, null); // 给节点的左子树赋值
     17                         break;
     18                     }
     19 
     20                     tmpNode = tmpNode.left;
     21                     // 如果不为空的话,则把左孩子节点用来和当前数组元素作比较
     22                 } else {// 大于根节点
     23                     if (tmpNode.right == null) {// 如果右孩子为空,这把当前数组元素插入到左孩子节点的位置
     24                         tmpNode.right = new BSTreeNode(A[i], null, null);
     25                         break;
     26                     }
     27                     tmpNode = tmpNode.right;// 如果不为空的话,则把右孩子节点用来和当前数组元素作比较
     28                 }
     29             }
     30         }
     31 
     32     }
     33 
     34     // 中序遍历二叉查找树(中序遍历之后便可以排序成功)
     35     public void inOrderBSTree(BSTreeNode x) {
     36         if (x != null) {
     37             inOrderBSTree(x.left);// 先遍历左子树
     38             System.out.print(x.data + ",");// 打印中间节点
     39             inOrderBSTree(x.right);// 最后遍历右子树
     40         }
     41     }
     42 
     43     // 查询二叉排序树--递归算法
     44     public BSTreeNode searchBSTree1(BSTreeNode x, BSTreeNode k) {
     45         if (x == null || k.data == x.data) {
     46             return x;// 返回查询到的节点
     47         }
     48         if (k.data < x.data) {// 如果k小于当前节点的数据域
     49             return searchBSTree1(x.left, k);// 从左孩子节点继续遍历
     50         } else {// 如果k大于当前节点的数据域
     51             return searchBSTree1(x.right, k);// 从右孩子节点继续遍历
     52         }
     53     }
     54 
     55     // 查询二叉排序树--非递归算法
     56     public BSTreeNode searchBSTree2(BSTreeNode x, BSTreeNode k) {
     57         while (x != null && k.data != x.data) {
     58             if (x.data > k.data) {
     59                 x = x.left;// 从左孩子节点继续遍历
     60             } else {
     61                 x = x.right;// 从右孩子节点继续遍历
     62             }
     63         }
     64         return x;
     65     }
     66 
     67     // 查找二叉查找树的最小节点
     68     public BSTreeNode searchMinNode(BSTreeNode x) {
     69         while (x.left != null) {
     70             x = x.left;
     71         }
     72         return x;
     73     }
     74 
     75     // 查找二叉查找树的最大节点
     76     public BSTreeNode searchMaxNode(BSTreeNode x) {
     77         while (x.right != null) {
     78             x = x.right;
     79         }
     80         return x;
     81     }
     82 
     83     // 插入节点进入二叉查找树
     84     public void insert(BSTreeNode k) {
     85         BSTreeNode r = rootNode;
     86         BSTreeNode p, q = null;
     87         p = r;
     88         while (p != null) {// while语句可以找到k节点所要插入的位置的父亲节点q
     89             q = p;
     90             if (p.data > k.data) {
     91                 p = p.left;
     92             } else {
     93                 p = p.right;
     94             }
     95         }
     96         if (q == null) {// 二叉查找树为空树的情况下,直接插入到根节点,这里的q为已知的k的父亲节点
     97             r.data = k.data;
     98         } else if (q.data > k.data) {// 插入到父亲节点q的左边
     99             q.left = k;
    100         } else {// 插入到父亲节点q的右边
    101             q.right = k;
    102         }
    103     }
    104 
    105     // 删除二叉查找树中指定的节点
    106     public void delete(BSTreeNode k) {// 分三种情况删除
    107         if (k.left == null && k.right == null) {// 第一种情况--没有子节点的情况下
    108             BSTreeNode p = parent(k);
    109             if (p.left == k) {// 其为父亲节点的左孩子
    110                 p.left = null;
    111             } else if (p.right == k) {// 其为父亲节点的右孩子
    112                 p.right = null;
    113             }
    114         } else if (k.left != null && k.right != null) {// 第二种情况--有两个孩子节点的情况下
    115             BSTreeNode s = successor(k);// k的后继节点
    116             delete(s);
    117             k.data = s.data;
    118         } else {// 第三种情况--只有一个孩子节点的情况下
    119             BSTreeNode p = parent(k);
    120             if (p.left == k) {
    121                 if (k.left != null) {
    122                     p.left = k.left;
    123                 } else {
    124                     p.left = k.right;
    125                 }
    126             } else if (p.right == k) {
    127                 if (k.left != null) {
    128                     p.right = k.left;
    129                 } else {
    130                     p.right = k.right;
    131                 }
    132             }
    133 
    134         }
    135     }
    136 
    137     // 查找节点的前驱节点
    138     public BSTreeNode predecessor(BSTreeNode k) {
    139         if (k.left != null) {
    140             return searchMaxNode(k.left);// 左子树的最大值
    141         }
    142         BSTreeNode y = parent(k);
    143         while (y != null && k == y.left) {// 向上找到最近的一个节点,其父亲节点的右子树包涵了当前节点或者其父亲节点为空
    144             k = y;
    145             y = parent(y);
    146         }
    147         return y;
    148     }
    149 
    150     // 查找节点的后继节点
    151     public BSTreeNode successor(BSTreeNode k) {
    152         if (k.right != null) {
    153             return searchMinNode(k.right);// 右子树的最小值
    154         }
    155         BSTreeNode y = parent(k);
    156         while (y != null && k == y.right) {// 向上找到最近的一个节点,其父亲节点的左子树包涵了当前节点或者其父亲节点为空
    157             k = y;
    158             y = parent(y);
    159         }
    160         return y;
    161     }
    162 
    163     // 求出父亲节点,在定义节点类BSTreeNode的时候,没有申明父亲节点,所以这里专门用parent用来输出父亲节点(主要是不想修改代码了,就在这里加一个parent函数吧)
    164     public BSTreeNode parent(BSTreeNode k) {
    165         BSTreeNode p = rootNode;
    166         BSTreeNode tmp = null;
    167         while (p != null && p.data != k.data) {// 最后的p为p。data等于k.data的节点,tmp为p的父亲节点
    168             if (p.data > k.data) {
    169                 tmp = p;// 临时存放父亲节点
    170                 p = p.left;
    171             } else {
    172                 tmp = p;// 临时存放父亲节点
    173                 p = p.right;
    174             }
    175         }
    176         return tmp;
    177     }
    178 
    179     /**
    180      * @param args
    181      */
    182     public static void main(String[] args) {
    183         // TODO Auto-generated method stub
    184         int[] A = { 23, 12, 43, 2, 87, 54 };
    185         BSTreeNode searchNode1 = null;// 递归查找到的结果
    186         BSTreeNode searchNode2 = null;// 非递归查找到的结果
    187         BSTreeNode searchMinNode = null;// 最小节点
    188         BSTreeNode searchMaxNode = null;// 最大节点
    189         BSTreeNode k = null, l = null, p = null, q = null, m = null, n = null;// 申明6个节点k,l,p,q,m,n
    190 
    191         System.out.print("打印出数组A中的元素");
    192         for (int i = 0; i < A.length; i++)
    193             System.out.print(A[i] + ",");
    194 
    195         BinarySortTree bsTree = new BinarySortTree();
    196 
    197         bsTree.createBSTree(A);// 创建二叉查找树
    198 
    199         System.out.println();
    200         System.out.print("中序遍历构造的二叉查找树:");
    201         bsTree.inOrderBSTree(bsTree.rootNode);// 中序遍历二叉查找树
    202 
    203         k = new BSTreeNode(23, null, null);// 初始化一节点k,左右孩子为null
    204         l = new BSTreeNode(17, null, null);// 初始化一节点l,左右孩子为null
    205         q = new BSTreeNode(12, null, null);// 初始化一节点q,左右孩子为null
    206         // m=bsTree.searchBSTree2(bsTree.rootNode,
    207         // k);//从二叉查找树里面查找一个节点,其m.data为k.data(这个m节点在后面用来测试程序)
    208         searchNode1 = bsTree.searchBSTree1(bsTree.rootNode, k);// 查询二叉查找树----递归算法
    209         searchNode2 = bsTree.searchBSTree2(bsTree.rootNode, k);// 查询二叉查找树----非递归算法
    210         m = searchNode2;
    211 
    212         System.out.println("");
    213         System.out.println("递归算法--查找节点域:" + searchNode1.data + "左孩子:" + searchNode1.left.data + "右孩子:" + "查找节点域:"
    214                 + searchNode1.right.data);// 递归 实现
    215         System.out.println("非递归算法--查找节点域:" + searchNode2.data + "左孩子:" + searchNode2.left.data + "右孩子:" + "查找节点域:"
    216                 + searchNode2.right.data);// 循环实现
    217 
    218         searchMinNode = bsTree.searchMinNode(bsTree.rootNode);// 找到最小节点
    219         searchMaxNode = bsTree.searchMaxNode(bsTree.rootNode);// 找到最大节点
    220 
    221         System.out.println("最小节点:" + searchMinNode.data);
    222         System.out.println("最大节点:" + searchMaxNode.data);
    223 
    224         bsTree.insert(l);// 把l节点插入到二叉查找树中
    225 
    226         System.out.print("插入l节点(l的data为17)之后的二叉查找树的中序遍历结果:");
    227         bsTree.inOrderBSTree(bsTree.rootNode);// 中序遍历二叉查找树
    228 
    229         p = bsTree.parent(q);// 取q节点的父亲节点
    230 
    231         System.out.println("");
    232         System.out.println("q的父亲节点(q的data为12):" + p.data + "左孩子:" + p.left.data + "右孩子:" + "查找节点域:" + p.right.data);// 这里的左孩子或者右孩子节点可能打印为空,会出现null异常
    233 
    234         bsTree.delete(l);
    235         System.out.print("删除l节点(l的data为17)之后的二叉查找树的中序遍历结果:");
    236         bsTree.inOrderBSTree(bsTree.rootNode);// 中序遍历二叉查找树
    237 
    238         n = bsTree.successor(m);
    239         System.out.println("");
    240         System.out.println("K的后继节点(k的data为23):" + n.data);
    241 
    242         n = bsTree.predecessor(m);
    243         System.out.println("K的前驱节点(k的data为23):" + n.data);
    244     }
    245 
    246 }
    247 
    248 // 二叉查找树的节点类
    249 class BSTreeNode {
    250     int data;// 数据域
    251     BSTreeNode right;// 左孩子
    252     BSTreeNode left;// 右孩子
    253     // 构造二叉查找树的节点
    254 
    255     public BSTreeNode(int data, BSTreeNode right, BSTreeNode left) {
    256         this.data = data; // 给二叉树的数据域赋值
    257         this.right = right; // 给该节点的右孩子赋值
    258         this.left = left; // 给该节点的左孩子赋值
    259     }
    260 
    261 }

     输出结果为:

     1 打印出数组A中的元素23,12,43,2,87,54,
     2 中序遍历构造的二叉查找树:2,12,23,43,54,87,
     3 递归算法--查找节点域:23左孩子:12右孩子:查找节点域:43
     4 非递归算法--查找节点域:23左孩子:12右孩子:查找节点域:43
     5 最小节点:2
     6 最大节点:87
     7 插入l节点(l的data为17)之后的二叉查找树的中序遍历结果:2,12,17,23,43,54,87,
     8 q的父亲节点(q的data为12):23左孩子:12右孩子:查找节点域:43
     9 删除l节点(l的data为17)之后的二叉查找树的中序遍历结果:2,12,23,43,54,87,
    10 K的后继节点(k的data为23):43
    11 K的前驱节点(k的data为23):12
  • 相关阅读:
    电脑族,记忆力下降怎么办
    asp.net入門經典讀書筆記
    GridView
    如何学习开源库
    i++与++i区别使用
    计算二次方程根
    MySQL Dump/Restore
    利用SetConsoleCursorPosition控制命令行光标位置
    How to upgrade to Ubuntu 10.10 Maverick Meerkat from ubuntu 10.04 lucid, karmic| Desktop & Server
    通过一条命令获取最快的 apt 源镜像
  • 原文地址:https://www.cnblogs.com/xh0102/p/5403587.html
Copyright © 2011-2022 走看看