zoukankan      html  css  js  c++  java
  • 二叉查找树的Java实现

    转自:http://blog.csdn.net/lovesqcc/article/details/6246615

    为了克服对树结构编程的恐惧感,决心自己实现一遍二叉查找树,以便掌握关于树结构编程的一些技巧和方法。以下是基本思路:

            [1] 关于容器与封装。封装,是一种非常重要的系统设计思想;无论是面向过程的函数,还是面向对象的对象,都是实现抽象和封装的技术手段。要使系统更加安全更具可维护性,就应当将封装思想谨记心中。容器是封装思想的绝好示例。用户对容器的印象应该简洁地表达为:A. 可以存入指定的东西; B. 可以取出所期望的东西。 而至于这容器中究竟有什么机关,藏的是毒蛇还是黄金,都是对用户不可见的。二叉查找树就是这样一个容器。面向对象编程中,为实现树结构,自然要对树结点对象进行建模。这里采用了内部类;外部类对二叉查找树进行建模,而树结点作为内部类实现。

           [2] 本程序尽量实现一个比较实用的二叉查找树,其中包括动态的插入、删除操作;查询给定关键字、最小关键字、最大关键字;获取二叉树的有序列表(用于排序)等。因为我希望以后还能用到这个容器的,而不仅仅是编程练习。二叉查找树操作的大部分算法参考了《算法导论2》第12章内容,删除操作略显笨拙。程序中有错误之处,欢迎指出。

          [3]  程序如下:

         

    [c-sharp] view plaincopyprint?
     
    1. /** 
    2.  * @author shuqin1984  2011-3-13 
    3.  *  
    4.  * 此程序实现一个二叉查找树的功能,可以进行动态插入、删除关键字; 
    5.  * 查询给定关键字、最小关键字、最大关键字;转换为有序列表(用于排序) 
    6.  *  
    7.  *  
    8.  */  
    9. package datastructure.tree;  
    10. import java.util.ArrayList;  
    11. import java.util.List;  
    12.   
    13. public class BinarySearchTree {  
    14.       
    15.     // 树的根结点  
    16.     private TreeNode root = null;  
    17.       
    18.     // 遍历结点列表  
    19.     private List<TreeNode> nodelist = new ArrayList<TreeNode>();  
    20.       
    21.     private class TreeNode {  
    22.           
    23.         private int key;  
    24.         private TreeNode leftChild;  
    25.         private TreeNode rightChild;  
    26.         private TreeNode parent;  
    27.           
    28.         public TreeNode(int key, TreeNode leftChild, TreeNode rightChild, TreeNode parent) {  
    29.             this.key = key;  
    30.             this.leftChild = leftChild;  
    31.             this.rightChild = rightChild;  
    32.             this.parent = parent;  
    33.         }     
    34.         public int getKey() {  
    35.             return key;  
    36.         }  
    37.         public String toString()  
    38.         {  
    39.             String leftkey = (leftChild == null ? "" : String.valueOf(leftChild.key));    
    40.             String rightkey = (rightChild == null ? "" : String.valueOf(rightChild.key));   
    41.             return "(" + leftkey + " , " + key + " , " + rightkey + ")";  
    42.         }  
    43.           
    44.     }  
    45.       
    46.     /** 
    47.      * isEmpty: 判断二叉查找树是否为空;若为空,返回 true ,否则返回 false .  
    48.      *  
    49.      */  
    50.     public boolean isEmpty()  
    51.     {  
    52.         if (root == null) {  
    53.             return true;  
    54.         } else {  
    55.             return false;  
    56.         }             
    57.     }  
    58.       
    59.     /** 
    60.      * TreeEmpty: 对于某些二叉查找树操作(比如删除关键字)来说,若树为空,则抛出异常。 
    61.      */  
    62.     public void TreeEmpty() throws Exception   
    63.     {  
    64.         if (isEmpty()) {  
    65.             throw new Exception("树为空!");  
    66.         }  
    67.     }  
    68.       
    69.     /** 
    70.      * search: 在二叉查找树中查询给定关键字  
    71.      * @param key 给定关键字 
    72.      * @return 匹配给定关键字的树结点 
    73.      */  
    74.     public TreeNode search(int key)   
    75.     {  
    76.         TreeNode pNode = root;  
    77.         while (pNode != null && pNode.key != key) {  
    78.             if (key < pNode.key) {  
    79.                 pNode = pNode.leftChild;  
    80.             }  
    81.             else {  
    82.                 pNode = pNode.rightChild;  
    83.             }  
    84.         }  
    85.         return pNode;  
    86.     }  
    87.       
    88.     /** 
    89.      * minElemNode: 获取二叉查找树中的最小关键字结点 
    90.      * @return 二叉查找树的最小关键字结点 
    91.      * @throws Exception 若树为空,则抛出异常 
    92.      */  
    93.     public TreeNode minElemNode(TreeNode node) throws Exception  
    94.     {  
    95.         if (node == null) {  
    96.             throw new Exception("树为空!");  
    97.         }  
    98.         TreeNode pNode = node;  
    99.         while (pNode.leftChild != null) {  
    100.             pNode = pNode.leftChild;  
    101.         }  
    102.         return pNode;  
    103.     }  
    104.       
    105.     /** 
    106.      * maxElemNode: 获取二叉查找树中的最大关键字结点 
    107.      * @return 二叉查找树的最大关键字结点 
    108.      * @throws Exception 若树为空,则抛出异常 
    109.      */  
    110.     public TreeNode maxElemNode(TreeNode node) throws Exception   
    111.     {  
    112.         if (node == null) {  
    113.             throw new Exception("树为空!");  
    114.         }  
    115.         TreeNode pNode = node;  
    116.         while (pNode.rightChild != null) {  
    117.             pNode = pNode.rightChild;  
    118.         }  
    119.         return pNode;  
    120.     }  
    121.       
    122.     /** 
    123.      * successor: 获取给定结点在中序遍历顺序下的后继结点 
    124.      * @param node 给定树中的结点 
    125.      * @return 若该结点存在中序遍历顺序下的后继结点,则返回其后继结点;否则返回 null 
    126.      * @throws Exception  
    127.      */  
    128.     public TreeNode successor(TreeNode node) throws Exception  
    129.     {  
    130.         if (node == null) {  
    131.             return null;  
    132.         }  
    133.           
    134.         // 若该结点的右子树不为空,则其后继结点就是右子树中的最小关键字结点  
    135.         if (node.rightChild != null) {   
    136.             return minElemNode(node.rightChild);  
    137.         }  
    138.         // 若该结点右子树为空  
    139.         TreeNode parentNode = node.parent;  
    140.         while (parentNode != null && node == parentNode.rightChild) {  
    141.             node = parentNode;  
    142.             parentNode = parentNode.parent;  
    143.         }  
    144.         return parentNode;  
    145.     }  
    146.       
    147.       
    148.     /** 
    149.      * precessor: 获取给定结点在中序遍历顺序下的前趋结点 
    150.      * @param node 给定树中的结点 
    151.      * @return 若该结点存在中序遍历顺序下的前趋结点,则返回其前趋结点;否则返回 null 
    152.      * @throws Exception  
    153.      */  
    154.     public TreeNode precessor(TreeNode node) throws Exception  
    155.     {  
    156.         if (node == null) {  
    157.             return null;  
    158.         }  
    159.           
    160.         // 若该结点的左子树不为空,则其前趋结点就是左子树中的最大关键字结点  
    161.         if (node.leftChild != null) {   
    162.             return maxElemNode(node.leftChild);  
    163.         }  
    164.         // 若该结点左子树为空  
    165.         TreeNode parentNode = node.parent;  
    166.         while (parentNode != null && node == parentNode.leftChild) {  
    167.             node = parentNode;  
    168.             parentNode = parentNode.parent;  
    169.         }  
    170.         return parentNode;  
    171.     }  
    172.       
    173.       
    174.     /** 
    175.      * insert: 将给定关键字插入到二叉查找树中 
    176.      * @param key 给定关键字 
    177.      */  
    178.     public void insert(int key)  
    179.     {  
    180.         TreeNode parentNode = null;  
    181.         TreeNode newNode = new TreeNode(key, nullnull,null);  
    182.         TreeNode pNode = root;  
    183.         if (root == null) {  
    184.             root = newNode;  
    185.             return ;  
    186.         }  
    187.         while (pNode != null) {  
    188.             parentNode = pNode;  
    189.             if (key < pNode.key) {     
    190.                 pNode = pNode.leftChild;  
    191.             }  
    192.             else if (key > pNode.key) {  
    193.                 pNode = pNode.rightChild;  
    194.             } else {  
    195.                 // 树中已存在匹配给定关键字的结点,则什么都不做直接返回                    
    196.                 return ;  
    197.             }  
    198.         }  
    199.         if (key < parentNode.key) {  
    200.             parentNode.leftChild = newNode;  
    201.             newNode.parent = parentNode;  
    202.         }  
    203.         else {  
    204.             parentNode.rightChild = newNode;  
    205.             newNode.parent = parentNode;  
    206.         }         
    207.           
    208.     }  
    209.       
    210.     /** 
    211.      * insert: 从二叉查找树中删除匹配给定关键字相应的树结点 
    212.      * @param key 给定关键字 
    213.      */  
    214.     public void delete(int key) throws Exception  
    215.     {  
    216.         TreeNode pNode = search(key);  
    217.         if (pNode == null) {  
    218.             throw new Exception("树中不存在要删除的关键字!");  
    219.         }  
    220.         delete(pNode);  
    221.     }  
    222.       
    223.     /** 
    224.      * delete: 从二叉查找树中删除给定的结点. 
    225.      * @param pNode 要删除的结点 
    226.      *  
    227.      * 前置条件: 给定结点在二叉查找树中已经存在 
    228.      * @throws Exception  
    229.      */  
    230.     private void delete(TreeNode pNode) throws Exception   
    231.     {  
    232.           if (pNode == null) {  
    233.               return ;  
    234.           }  
    235.           if (pNode.leftChild == null && pNode.rightChild == null) { // 该结点既无左孩子结点,也无右孩子结点  
    236.               TreeNode parentNode = pNode.parent;  
    237.               if (pNode == parentNode.leftChild) {  
    238.                   parentNode.leftChild = null;  
    239.               } else {  
    240.                   parentNode.rightChild = null;  
    241.               }  
    242.               return ;  
    243.           }  
    244.           if (pNode.leftChild == null && pNode.rightChild != null) { // 该结点左孩子结点为空,右孩子结点非空  
    245.               TreeNode parentNode = pNode.parent;  
    246.               if (pNode == parentNode.leftChild) {  
    247.                   parentNode.leftChild = pNode.rightChild;  
    248.                   pNode.rightChild.parent = parentNode;  
    249.               }  
    250.               else {  
    251.                   parentNode.rightChild = pNode.rightChild;  
    252.                   pNode.rightChild.parent = parentNode;  
    253.               }  
    254.               return ;  
    255.           }  
    256.           if (pNode.leftChild != null && pNode.rightChild == null) { // 该结点左孩子结点非空,右孩子结点为空  
    257.               TreeNode parentNode = pNode.parent;  
    258.               if (pNode == parentNode.leftChild) {  
    259.                   parentNode.leftChild = pNode.leftChild;  
    260.                   pNode.rightChild.parent = parentNode;  
    261.               }  
    262.               else {  
    263.                   parentNode.rightChild = pNode.leftChild;  
    264.                   pNode.rightChild.parent = parentNode;  
    265.               }  
    266.               return ;  
    267.           }  
    268.           // 该结点左右孩子结点均非空,则删除该结点的后继结点,并用该后继结点取代该结点  
    269.           TreeNode successorNode = successor(pNode);  
    270.           delete(successorNode);  
    271.           pNode.key = successorNode.key;  
    272.     }  
    273.       
    274.     /** 
    275.      * inOrderTraverseList: 获得二叉查找树的中序遍历结点列表 
    276.      * @return 二叉查找树的中序遍历结点列表 
    277.      */  
    278.     public List<TreeNode> inOrderTraverseList()  
    279.     {  
    280.         if (nodelist != null) {  
    281.            nodelist.clear();  
    282.         }  
    283.         inOrderTraverse(root);  
    284.         return nodelist;  
    285.     }  
    286.       
    287.     /** 
    288.      * inOrderTraverse: 对给定二叉查找树进行中序遍历 
    289.      * @param root 给定二叉查找树的根结点 
    290.      */  
    291.     private void inOrderTraverse(TreeNode root)  
    292.     {  
    293.         if (root != null) {  
    294.             inOrderTraverse(root.leftChild);  
    295.             nodelist.add(root);  
    296.             inOrderTraverse(root.rightChild);  
    297.         }  
    298.     }  
    299.       
    300.     /** 
    301.      * toStringOfOrderList: 获取二叉查找树中关键字的有序列表 
    302.      * @return 二叉查找树中关键字的有序列表 
    303.      */  
    304.     public String toStringOfOrderList()  
    305.     {  
    306.         StringBuilder sbBuilder = new StringBuilder(" [ ");  
    307.         for (TreeNode p: inOrderTraverseList()) {  
    308.             sbBuilder.append(p.key);  
    309.             sbBuilder.append(" ");  
    310.         }  
    311.         sbBuilder.append("]");  
    312.         return sbBuilder.toString();  
    313.     }  
    314.       
    315.     /** 
    316.      * 获取该二叉查找树的字符串表示 
    317.      */  
    318.     public String toString()  
    319.     {  
    320.         StringBuilder sbBuilder = new StringBuilder(" [ ");  
    321.         for (TreeNode p: inOrderTraverseList()) {  
    322.             sbBuilder.append(p);  
    323.             sbBuilder.append(" ");  
    324.         }  
    325.         sbBuilder.append("]");  
    326.         return sbBuilder.toString();  
    327.     }  
    328.     public TreeNode getRoot() {  
    329.         return root;  
    330.     }  
    331.       
    332.     public static void testNode(BinarySearchTree bst, TreeNode pNode) throws Exception {  
    333.         System.out.println("本结点: " + pNode);  
    334.         System.out.println("前趋结点: " + bst.precessor(pNode));  
    335.         System.out.println("后继结点: " + bst.successor(pNode));  
    336.     }  
    337.       
    338.     public static void testTraverse(BinarySearchTree bst) {  
    339.         System.out.println("二叉树遍历:" + bst);  
    340.         System.out.println("二叉查找树转换为有序列表: " + bst.toStringOfOrderList());  
    341.     }  
    342.       
    343.     public static void main(String[] args)   
    344.     {  
    345.         try {  
    346.             BinarySearchTree bst = new BinarySearchTree();  
    347.             System.out.println("查找树是否为空? " + (bst.isEmpty() ? "是" : "否"));  
    348.             int[] keys = new int[] {15, 6, 18, 3, 7, 13, 20, 2, 9, 4};  
    349.             for (int key: keys) {  
    350.                 bst.insert(key);  
    351.             }  
    352.             System.out.println("查找树是否为空? " + (bst.isEmpty() ? "是" : "否"));  
    353.               
    354.             TreeNode minkeyNode = bst.minElemNode(bst.getRoot());  
    355.             System.out.println("最小关键字: " + minkeyNode.getKey());  
    356.             testNode(bst, minkeyNode);  
    357.               
    358.             TreeNode maxKeyNode = bst.maxElemNode(bst.getRoot());  
    359.             System.out.println("最大关键字: " + maxKeyNode.getKey());  
    360.             testNode(bst, maxKeyNode);  
    361.               
    362.             System.out.println("根结点关键字: " + bst.getRoot().getKey());  
    363.             testNode(bst, bst.getRoot());  
    364.             testTraverse(bst);  
    365.               
    366.             System.out.println("****************************** ");  
    367.               
    368.             System.out.println("查找 7 : " + (bst.search(7) != null ? "查找成功!" : "查找失败,不存在该关键字!"));  
    369.             bst.delete(7);  
    370.             System.out.println("查找 7 : " + (bst.search(7) != null ? "查找成功!" : "查找失败,不存在该关键字!"));  
    371.             System.out.println("查找 12 : " + (bst.search(12) != null ? "查找成功!" : "查找失败,不存在该关键字!"));  
    372.             bst.insert(12);  
    373.             System.out.println("查找 12 : " + (bst.search(12) != null ? "查找成功!" : "查找失败,不存在该关键字!"));  
    374.               
    375.             testTraverse(bst);  
    376.               
    377.             System.out.println("****************************** ");  
    378.               
    379.             bst.insert(16);  
    380.             bst.delete(6);  
    381.             bst.delete(4);  
    382.               
    383.             testTraverse(bst);  
    384.               
    385.         } catch (Exception e) {  
    386.             System.out.println(e.getMessage());  
    387.             e.printStackTrace();  
    388.         }  
    389.     }  
    390.       
    391.       
    392. }   
  • 相关阅读:
    3.15SQL
    SQL注入
    黑盒渗透测试【转自HACK学习-FoxRoot】
    【学校作业】某项目网络安全技术解决方案
    小米手环4使用半年后的测评报告
    GKCTF赛后复盘
    RCTF赛后复盘
    【课堂笔记】常见漏洞总结
    原型链污染问题的研究
    CTF之Web常见题型总结
  • 原文地址:https://www.cnblogs.com/cugwx/p/3664306.html
Copyright © 2011-2022 走看看