基于java的数据结构学习手记14-二叉树的实现

来源:互联网 发布:淘宝耐克女鞋 编辑:程序博客网 时间:2024/05/16 15:27

1.为什么使用树?     

 二叉树结合了两种数据结构的优点:一种是有序数组,另一种是链表。在树中查找数据项的速度和在有序数组中一样快O(logN),在树中删除和添加数据项和在链表中一样快O(1)。

2.实现树类

    首先需要一个节点对象类,这个对象包含要保存的数据,以及指向左子树,右子树的引用。代码如下:

  

Code:
  1. //////////////////////////////////////////////////////////////////  
  2. public class Node {  
  3.     public int iData;         //data item(key)  
  4.     public double dData;      //data item  
  5.     public Node leftChild;    //this is Node's left child  
  6.     public Node rightChild;   //this is Node's right child  
  7.       
  8.     public void displayNode()  
  9.     {  
  10.         System.out.print("{");  
  11.         System.out.print(iData);  
  12.         System.out.print(",");  
  13.         System.out.print(dData);  
  14.         System.out.print("}");  
  15.     }  
  16.   
  17. }// end class Node  

树类的实现:这个类的骨架如下

  

Code:
  1. class Tree  
  2. {  
  3.     private Node root;  
  4.     public void find(int key)  
  5.          {  
  6.           }  
  7.      public void insert(int id,double dd)  
  8.          {  
  9.           }  
  10.       public void delete(int id)  
  11.          {  
  12.           }   
  13. //other methods  
  14. }//end class Tree  

查找 方法find()

Code:
  1. //------------------------------------------------------------         
  2.       public Node find(int key)    //find node with given key  
  3.       {  
  4.          Node current=root;        //current指针指向root开始  
  5.          while(current.iData!=key) //while not match  
  6.          {  
  7.              if(current.iData>key)current=current.leftChild;//比key小,current指针走左子树  
  8.              else                                           //反之向右  
  9.                  current=current.rightChild;  
  10.              if(current==null)  
  11.              return null;  
  12.          }  
  13.          return current;  
  14.       }//end find();  
  15. //------------------------------------------------------------     
  16.  

   使用一个引用current,初始化为root节点,从root开始跟要查找的key比较,key比当前节点的iData对象小的时候,current引用变为当前current的左子树,否则就指向右子树。如果 current指向为null说明整个数没有匹配的数据项,返回null。找到匹配的数据项的时候,退出循环,返回 current指向的节点。

   插入方法insert()

Code:
  1. //------------------------------------------------------------     
  2.     public void insert(int id,double dd)  
  3.     {  
  4.         Node newNode=new Node();  
  5.         newNode.iData=id;  
  6.         newNode.dData=dd;  
  7.         if(root==null)                //如果根节点为空,把新节点设为根节点  
  8.             root=newNode;  
  9.         else                          //否则找到节点插入的位置,插入节点  
  10.         {  
  11.             Node current=root;  
  12.             Node parent;  
  13.             while(true)  
  14.             {  
  15.                 parent=current;  
  16.                 if(id<current.iData)  
  17.                 {  
  18.                     current=current.leftChild;  
  19.                     if(current==null)  
  20.                     {  
  21.                         parent.leftChild=newNode;  
  22.                         return;  
  23.                     }     
  24.                 }//end if go left  
  25.                 else  
  26.                 {  
  27.                     current=current.rightChild;  
  28.                     if(current==null)  
  29.                     {  
  30.                         parent.rightChild=newNode;  
  31.                         return;  
  32.                     }         
  33.                 }// end else go right  
  34.             }//end while()  
  35.         }//end else root  
  36.     }//end insert()  
  37. //------------------------------------------------------------------------------------------  

   首先判断树是否为空,如果是空,把根节点赋值为要插入的节点。否则,寻找要插入节点的位置,方法和find()类似,只是需要保存parent引用指向current的父节点,当current==null的时候即找到要插入的位置时,把要插入的节点赋给current的左子树或者右子树。

删除节点方法delete()

 

Code:
  1. //------------------------------------------------------------------------------------------  
  2.     public boolean delete(int key)//delete node with given key  
  3.     {  
  4.         Node current=root;  
  5.         Node parent=root;  
  6.         boolean isLeftChild=true;  
  7.         while(current.iData!=key)  
  8.         {  
  9.             parent=current;  
  10.             if(key<current.iData)  
  11.             {  
  12.                 isLeftChild=true;  
  13.                 current=current.leftChild;  
  14.             }  
  15.             else  
  16.             {  
  17.                 isLeftChild=false;  
  18.                 current=current.rightChild;  
  19.             }  
  20.             if(current==null)return false;//没有找到要删除的节点,结束删除  
  21.                   
  22.         }//end while()查找要删除节点  
  23.         if(current.leftChild==null&&current.rightChild==null)//三种情况之一:要删除的节点没有左右子树  
  24.         {  
  25.             if(current==root) //首先判断这个要删除的节点是否为根  
  26.                 root=null;    //如果是根,把树清空  
  27.             else if(isLeftChild)//不是根节点后,判断要删除的节点是否是它的父节点的左子树  
  28.                 parent.leftChild=null;//如果是,把其父节点的左子树清空  
  29.             else   
  30.                 parent.rightChild=null;//如果不是,把其父节点的右子树清空  
  31.         }  
  32.                                                              //三种情况之二:要删除的节点只有一边子树的情况  
  33.         else if(current.rightChild==null)//如果要删除的节点只有左子树,那么把其左子树直接接到其父节点即可  
  34.         {  
  35.             if(current==root)root=current.leftChild;//如果要删除的节点是根节点,则把其左子树设为根  
  36.             else if(isLeftChild)parent.leftChild=current.leftChild;//非根节点的情况下,isLeftChild,就把要删除的节点的左子树接到要删除的父节点的左子树上  
  37.             else parent.rightChild=current.leftChild;//当要删除的节点是其父节点的右子树的情况  
  38.         }  
  39.         else if(current.leftChild==null)//如果要删除的节点只有右子树,那么把其右子树直接接到其父节点即可  
  40.         {  
  41.             if(current==root)root=current.rightChild;//如果要删除的节点是根节点,则把其左右子树设为根  
  42.             else if(isLeftChild)parent.leftChild=current.rightChild;//非根节点的情况下,isLeftChild,就把要删除的节点的右子树接到要删除的父节点的左子树上  
  43.             else parent.rightChild=current.rightChild;//当要删除的节点是其父节点的右子树的情况  
  44.         }  
  45.         else                                      //第三种情况  
  46.         {  
  47.             Node successor=getSuccessor(current);  
  48.             if(current==root)  
  49.                 root=successor;  
  50.             else if(isLeftChild)  
  51.                 parent.leftChild=successor;  
  52.             else   
  53.                 parent.rightChild=successor;  
  54.             successor.leftChild=current.leftChild;  
  55.         }  
  56.         return true;  
  57.     }//end delete();  
  58. //------------------------------------------------------------------------  
  59.       private Node getSuccessor(Node delNode)//返回比当前要删除的节点大的最小的节点,并执行必须的操作  
  60.       {  
  61.           Node successorParent=delNode;  
  62.           Node successor=delNode;  
  63.           Node current=delNode.rightChild;  
  64.           while(current!=null)  
  65.           {  
  66.               successorParent=successor;  
  67.               successor=current;  
  68.               current=current.leftChild;  
  69.           }  
  70.           if(successor!=delNode.rightChild)  
  71.           {  
  72.               successorParent.leftChild=successor.rightChild;  
  73.               successor.rightChild=delNode.rightChild;  
  74.           }  
  75.           return successor;  
  76.       }  
  77. //------------------------------------------------------------------------  

    删除节点的操作比较复杂,大的方面需要分三种情况考虑:1.要删除的节点没有子节点;2.要删除的节点只有一个子节点;3.要删除的节点有两个子节点。这里有另一个方法getsuccessor()其作用是找到整棵树中比要删除节点大的最小的节点(次小节点)并对要删除节点的右子树做一些操作(使其可以直接充当代替删除节点的后继节点的右子树)。这里有个技巧,树中任何节点的后继节点只有两种可能:1.为其右节点(当其右节点不含有左子树时);2.为其右节点的最左子节点。

    需要注意的是:需要一个标记boolean isLeftChild来标识要删除的节点是其父节点的左子树还是右子树。当找到了要删除节点current的后继节点successor时,只需根据isLeftChild把successor接入到parent的左或者右子树,然后把current的右子树充当successor的右子树, current的左子树充当successor的左子树,即完成了删除操作。

    遍历traverse()前序、中序、后序遍历使用了递归(recursive)的方法。

Code:
  1. //------------------------------------------------------------------------  
  2. public void traverse(int traverseType)  
  3. {  
  4.   switch(traverseType)  
  5.   {  
  6.   case 1:System.out.print("/nPreorder traversal: ");  
  7.          preOrder(root);  
  8.          break;  
  9.   case 2:System.out.print("/nInorder traversal: ");  
  10.          inOrder(root);  
  11.          break;  
  12.   case 3:System.out.print("/nPostorder traversal: ");  
  13.          postOrder(root);  
  14.          break;  
  15.   }  
  16.   System.out.println();  
  17. }  
  18. //------------------------------------------------------------  
  19. private void preOrder(Node localRoot)//前序遍历  
  20. {  
  21.     if(localRoot!=null)  
  22.     {  
  23.         System.out.print(localRoot.iData+" ");  
  24.         preOrder(localRoot.leftChild);  
  25.         preOrder(localRoot.rightChild);  
  26.     }  
  27. }  
  28. //------------------------------------------------------------  
  29. private void inOrder(Node localRoot)//中序遍历  
  30. {  
  31.     if(localRoot!=null)  
  32.     {  
  33.         inOrder(localRoot.leftChild);  
  34.         System.out.print(localRoot.iData+" ");  
  35.         inOrder(localRoot.rightChild);  
  36.     }  
  37. }  
  38. //-----------------------------------------------------------------  
  39. private void postOrder(Node localRoot)//后续遍历  
  40. {  
  41.     if(localRoot!=null)  
  42.     {  
  43.         postOrder(localRoot.leftChild);  
  44.         postOrder(localRoot.rightChild);  
  45.         System.out.print(localRoot.iData+" ");  
  46.     }  
  47. }  
  48. //------------------------------------------------------------------  

 

  完整代码如下:

Node节点类:

Code:
  1. //////////////////////////////////////////////////////////////////  
  2. public class Node {  
  3.     public int iData;         //data item(key)  
  4.     public double dData;      //data item  
  5.     public Node leftChild;    //this is Node's left child  
  6.     public Node rightChild;   //this is Node's right child  
  7.       
  8.     public void displayNode()  
  9.     {  
  10.         System.out.print("{");  
  11.         System.out.print(iData);  
  12.         System.out.print(",");  
  13.         System.out.print(dData);  
  14.         System.out.print("}");  
  15.     }  
  16.   
  17. }// end class Node  

Tree类:

  

Code:
  1. package tree;  
  2. import java.util.*;  
  3. public class Tree {  
  4.       private Node root;           //first node of tree  
  5. //------------------------------------------------------------     
  6.       public Tree()  
  7.       {  
  8.           root=null;  
  9.       }  
  10. //------------------------------------------------------------         
  11.       public Node find(int key)    //find node with given key  
  12.       {  
  13.          Node current=root;        //current指针指向root开始  
  14.          while(current.iData!=key) //while not match  
  15.          {  
  16.              if(current.iData>key)current=current.leftChild;//比key小,current指针走左子树  
  17.              else                                           //反之向右  
  18.                  current=current.rightChild;  
  19.              if(current==null)  
  20.              return null;  
  21.          }  
  22.          return current;  
  23.       }//end find();  
  24. //------------------------------------------------------------     
  25.     public void insert(int id,double dd)  
  26.     {  
  27.         Node newNode=new Node();  
  28.         newNode.iData=id;  
  29.         newNode.dData=dd;  
  30.         if(root==null)                //如果根节点为空,把新节点设为根节点  
  31.             root=newNode;  
  32.         else                          //否则找到节点插入的位置,插入节点  
  33.         {  
  34.             Node current=root;  
  35.             Node parent;  
  36.             while(true)  
  37.             {  
  38.                 parent=current;  
  39.                 if(id<current.iData)  
  40.                 {  
  41.                     current=current.leftChild;  
  42.                     if(current==null)  
  43.                     {  
  44.                         parent.leftChild=newNode;  
  45.                         return;  
  46.                     }     
  47.                 }//end if go left  
  48.                 else  
  49.                 {  
  50.                     current=current.rightChild;  
  51.                     if(current==null)  
  52.                     {  
  53.                         parent.rightChild=newNode;  
  54.                         return;  
  55.                     }         
  56.                 }// end else go right  
  57.             }//end while()  
  58.         }//end else root  
  59.     }//end insert()  
  60. //------------------------------------------------------------------------------------------  
  61.     public boolean delete(int key)//delete node with given key  
  62.     {  
  63.         Node current=root;  
  64.         Node parent=root;  
  65.         boolean isLeftChild=true;  
  66.         while(current.iData!=key)  
  67.         {  
  68.             parent=current;  
  69.             if(key<current.iData)  
  70.             {  
  71.                 isLeftChild=true;  
  72.                 current=current.leftChild;  
  73.             }  
  74.             else  
  75.             {  
  76.                 isLeftChild=false;  
  77.                 current=current.rightChild;  
  78.             }  
  79.             if(current==null)return false;//没有找到要删除的节点,结束删除  
  80.                   
  81.         }//end while()查找要删除节点  
  82.         if(current.leftChild==null&&current.rightChild==null)//三种情况之一:要删除的节点没有左右子树  
  83.         {  
  84.             if(current==root) //首先判断这个要删除的节点是否为根  
  85.                 root=null;    //如果是根,把树清空  
  86.             else if(isLeftChild)//不是根节点后,判断要删除的节点是否是它的父节点的左子树  
  87.                 parent.leftChild=null;//如果是,把其父节点的左子树清空  
  88.             else   
  89.                 parent.rightChild=null;//如果不是,把其父节点的右子树清空  
  90.         }  
  91.                                                              //三种情况之二:要删除的节点只有一边子树的情况  
  92.         else if(current.rightChild==null)//如果要删除的节点只有左子树,那么把其左子树直接接到其父节点即可  
  93.         {  
  94.             if(current==root)root=current.leftChild;//如果要删除的节点是根节点,则把其左子树设为根  
  95.             else if(isLeftChild)parent.leftChild=current.leftChild;//非根节点的情况下,isLeftChild,就把要删除的节点的左子树接到要删除的父节点的左子树上  
  96.             else parent.rightChild=current.leftChild;//当要删除的节点是其父节点的右子树的情况  
  97.         }  
  98.         else if(current.leftChild==null)//如果要删除的节点只有右子树,那么把其右子树直接接到其父节点即可  
  99.         {  
  100.             if(current==root)root=current.rightChild;//如果要删除的节点是根节点,则把其左右子树设为根  
  101.             else if(isLeftChild)parent.leftChild=current.rightChild;//非根节点的情况下,isLeftChild,就把要删除的节点的右子树接到要删除的父节点的左子树上  
  102.             else parent.rightChild=current.rightChild;//当要删除的节点是其父节点的右子树的情况  
  103.         }  
  104.         else                                      //第三种情况  
  105.         {  
  106.             Node successor=getSuccessor(current);  
  107.             if(current==root)  
  108.                 root=successor;  
  109.             else if(isLeftChild)  
  110.                 parent.leftChild=successor;  
  111.             else   
  112.                 parent.rightChild=successor;  
  113.             successor.leftChild=current.leftChild;  
  114.         }  
  115.         return true;  
  116.     }//end delete();  
  117. //------------------------------------------------------------------------  
  118.       private Node getSuccessor(Node delNode)//返回比当前要删除的节点大的最小的节点,并执行必须的操作  
  119.       {  
  120.           Node successorParent=delNode;  
  121.           Node successor=delNode;  
  122.           Node current=delNode.rightChild;  
  123.           while(current!=null)  
  124.           {  
  125.               successorParent=successor;  
  126.               successor=current;  
  127.               current=current.leftChild;  
  128.           }  
  129.           if(successor!=delNode.rightChild)  
  130.           {  
  131.               successorParent.leftChild=successor.rightChild;  
  132.               successor.rightChild=delNode.rightChild;  
  133.           }  
  134.           return successor;  
  135.       }  
  136. //------------------------------------------------------------------------  
  137. public void traverse(int traverseType)  
  138. {  
  139.   switch(traverseType)  
  140.   {  
  141.   case 1:System.out.print("/nPreorder traversal: ");  
  142.          preOrder(root);  
  143.          break;  
  144.   case 2:System.out.print("/nInorder traversal: ");  
  145.          inOrder(root);  
  146.          break;  
  147.   case 3:System.out.print("/nPostorder traversal: ");  
  148.          postOrder(root);  
  149.          break;  
  150.   }  
  151.   System.out.println();  
  152. }  
  153. //------------------------------------------------------------  
  154. private void preOrder(Node localRoot)//前序遍历  
  155. {  
  156.     if(localRoot!=null)  
  157.     {  
  158.         System.out.print(localRoot.iData+" ");  
  159.         preOrder(localRoot.leftChild);  
  160.         preOrder(localRoot.rightChild);  
  161.     }  
  162. }  
  163. //------------------------------------------------------------  
  164. private void inOrder(Node localRoot)//中序遍历  
  165. {  
  166.     if(localRoot!=null)  
  167.     {  
  168.         inOrder(localRoot.leftChild);  
  169.         System.out.print(localRoot.iData+" ");  
  170.         inOrder(localRoot.rightChild);  
  171.     }  
  172. }  
  173. //-----------------------------------------------------------------  
  174. private void postOrder(Node localRoot)//后续遍历  
  175. {  
  176.     if(localRoot!=null)  
  177.     {  
  178.         postOrder(localRoot.leftChild);  
  179.         postOrder(localRoot.rightChild);  
  180.         System.out.print(localRoot.iData+" ");  
  181.     }  
  182. }  
  183. //------------------------------------------------------------------  
  184. public void displayTree()  
  185. {  
  186.     Stack globalStack=new Stack();  
  187.     globalStack.push(root);  
  188.     int nBlanks=32;  
  189.     boolean isRowEmpty=false;  
  190.     System.out.println(".............................................................................");  
  191.     while(isRowEmpty==false)  
  192.     {  
  193.         Stack<Node> localStack=new Stack();  
  194.         isRowEmpty=true;  
  195.         for(int j=0;j<nBlanks;j++)  
  196.             System.out.print(" ");  
  197.         while(globalStack.isEmpty()==false)  
  198.         {  
  199.             Node temp=(Node) globalStack.pop();  
  200.             if(temp!=null)  
  201.             {  
  202.                 System.out.print(temp.iData);  
  203.                 localStack.push(temp.leftChild);  
  204.                 localStack.push(temp.rightChild);  
  205.                 if(temp.leftChild!=null||temp.rightChild!=null)  
  206.                     isRowEmpty=false;  
  207.             }  
  208.             else  
  209.             {  
  210.                 System.out.print("..");  
  211.                 localStack.push(null);  
  212.                 localStack.push(null);  
  213.             }  
  214.             for(int j=0;j<nBlanks*2.2;j++)  
  215.                 System.out.print(" ");  
  216.         }  
  217.         System.out.println();  
  218.         nBlanks/=2;  
  219.         while(localStack.isEmpty()==false)  
  220.             globalStack.push(localStack.pop());  
  221.     }  
  222. System.out.println("................................................................................");  
  223.   
  224. }//end displayTree()  
  225.   
  226.   
  227. //------------------------------------------------------------------  
  228. }  

App类:

Code:
  1. package tree;  
  2.   
  3. import java.io.BufferedReader;  
  4. import java.io.IOException;  
  5. import java.io.InputStreamReader;  
  6.   
  7. public class TreeApps {  
  8.   
  9.     /** 
  10.      * @param args 
  11.      * @throws IOException  
  12.      */  
  13.     public static void main(String[] args) throws IOException {  
  14.         // TODO Auto-generated method stub  
  15.         int value;  
  16.         Tree theTree=new Tree();  
  17.           
  18.         theTree.insert(501.5);  
  19.         theTree.insert(251.5);  
  20.         theTree.insert(751.5);  
  21.           
  22.         theTree.insert(121.5);  
  23.         theTree.insert(371.5);  
  24.         theTree.insert(431.5);  
  25.           
  26.         theTree.insert(301.5);  
  27.         theTree.insert(331.5);  
  28.         theTree.insert(871.5);  
  29.         theTree.insert(931.5);  
  30.         theTree.insert(971.5);  
  31.           
  32.         while(true)  
  33.         {  
  34.             System.out.print("Enter first letter of show, ");  
  35.             System.out.print("insert,find,delete,or traverse: ");  
  36.             int choice=getChar();  
  37.             switch(choice)  
  38.             {  
  39.             case 's':  
  40.                 theTree.displayTree();  
  41.                 break;  
  42.             case 'i':  
  43.                 System.out.print("Enter value to insert: ");  
  44.                 value=getInt();  
  45.                 theTree.insert(value, value+0.9);  
  46.                 break;  
  47.             case 'f':  
  48.                 System.out.print("Enter value to find: ");  
  49.                 value=getInt();  
  50.                 Node found=theTree.find(value);  
  51.                 if(found!=null)  
  52.                 {  
  53.                     System.out.print("Found: ");  
  54.                     found.displayNode();  
  55.                     System.out.print("/n");  
  56.                   
  57.                 }  
  58.                 else  
  59.                     System.out.print("Could not find");  
  60.                     System.out.print(value+"/n");  
  61.                     break;  
  62.             case 'd':  
  63.                 System.out.print("Enter value to delete: ");  
  64.                 value=getInt();  
  65.                 boolean didDelete=theTree.delete(value);  
  66.                 if(didDelete)  
  67.                     System.out.print("Deleted "+value+"/n");  
  68.                 else  
  69.                     System.out.print("Could not delete ");  
  70.                     System.out.print(value+"/n");  
  71.                 break;  
  72.             case 't':  
  73.                 System.out.print("Enter type 1,2 or 3");  
  74.                 value=getInt();  
  75.                 theTree.traverse(value);  
  76.                 break;  
  77.             default:  
  78.                 System.out.print("Invalid entry/n");  
  79.             }//end switch   
  80.         }//end while  
  81.   
  82.     }//end main()  
  83. //----------------------------------------------------------------  
  84.     public static String getString()throws IOException    
  85.     {  
  86.         InputStreamReader in=new InputStreamReader(System.in);  
  87.         BufferedReader br=new BufferedReader(in);  
  88.         String s=br.readLine();  
  89.         return s;  
  90.         }  
  91. //----------------------------------------------------------------  
  92.     public static char getChar()throws IOException  
  93.     {  
  94.      String s=getString();  
  95.      return s.charAt(0);  
  96.     }  
  97. //----------------------------------------------------------------  
  98.   public static int getInt()throws IOException  
  99.   {  
  100.       String s=getString();  
  101.       return Integer.parseInt(s);  
  102.   }  
  103. //----------------------------------------------------------------  
  104. }//end class TreeApp  
  105. //////////////////////////////////////////////////////////////////////  

显示结果:

Code:
  1. Enter first letter of show, insert,find,delete,or traverse: s  
  2. .............................................................................  
  3.                                 50                                                                         
  4.                 25                                    75                                      
  5.         12                  37                  ..                  87                    
  6.     ..         ..         30         43         ..         ..         ..         93           
  7.   ..     ..     ..     ..     ..     33     ..     ..     ..     ..     ..     ..     ..     ..     ..     97       
  8. ................................................................................  
  9. Enter first letter of show, insert,find,delete,or traverse: