Java 資料結構與演算法 - 樹



概述

樹由節點和邊連線而成。我們將專門討論二叉樹或二叉搜尋樹。

二叉樹是一種用於資料儲存的特殊資料結構。二叉樹有一個特殊的條件,即每個節點最多可以有兩個子節點。二叉樹兼具有序陣列和連結串列的優點,搜尋速度與有序陣列一樣快,插入或刪除操作速度與連結串列一樣快。

術語

以下是關於樹的一些重要術語。

  • 路徑 - 路徑指的是樹中沿邊的一系列節點。

  • - 樹頂部的節點稱為根。每棵樹只有一個根,並且從根節點到任何節點都只有一條路徑。

  • 父節點 - 除根節點外的任何節點都有一條向上連線到稱為父節點的節點的邊。

  • 子節點 - 在給定節點下方由其向下連線的邊連線的節點稱為其子節點。

  • 葉子節點 - 沒有子節點的節點稱為葉子節點。

  • 子樹 - 子樹表示節點的後代。

  • 訪問 - 訪問是指當控制權在節點上時檢查節點的值。

  • 遍歷 - 遍歷是指按特定順序透過節點。

  • 層級 - 節點的層級表示節點的代數。如果根節點在第 0 層,那麼其下一個子節點在第 1 層,其孫節點在第 2 層,依此類推。

  • - 鍵表示節點的值,根據該值執行節點的搜尋操作。

二叉搜尋樹表現出特殊的行為。節點的左子節點的值必須小於其父節點的值,節點的右子節點的值必須大於其父節點的值。

二叉搜尋樹表示

我們將使用節點物件來實現樹,並透過引用將它們連線起來。

基本操作

以下是樹的基本主要操作。

  • 搜尋 - 在樹中搜索一個元素。

  • 插入 - 在樹中插入一個元素。

  • 先序遍歷 - 以先序方式遍歷樹。

  • 中序遍歷 - 以中序方式遍歷樹。

  • 後序遍歷 - 以後序方式遍歷樹。

節點

定義一個節點,它包含一些資料以及對其左右子節點的引用。

public class Node {
   public int data;
   public Node leftChild;
   public Node rightChild;

   public Node(){}

   public void display(){
      System.out.print("("+data+ ")");
   }
}

搜尋操作

當要搜尋一個元素時。從根節點開始搜尋,如果資料小於鍵值,則在左子樹中搜索元素,否則在右子樹中搜索元素。對每個節點遵循相同的演算法。

public Node search(int data){
   Node current = root;
   System.out.print("Visiting elements: ");
   while(current.data != data){
      if(current != null)
         System.out.print(current.data + " "); 
         //go to left tree
         if(current.data > data){
            current = current.leftChild;
         }//else go to right tree
         else{                
            current = current.rightChild;
         }
         //not found
         if(current == null){
            return null;
         }
      }
   return current;
}

插入操作

當要插入一個元素時。首先找到其合適的位置。從根節點開始搜尋,如果資料小於鍵值,則在左子樹中搜索空位置並插入資料。否則,在右子樹中搜索空位置並插入資料。

public void insert(int data){
   Node tempNode = new Node();
   tempNode.data = data;

   //if tree is empty
   if(root == null){
      root = tempNode;
   }else{
      Node current = root;
      Node parent = null;

      while(true){                
         parent = current;
         //go to left of the tree
         if(data < parent.data){
            current = current.leftChild;                
            //insert to the left
            if(current == null){
               parent.leftChild = tempNode;
               return;
            }
         }//go to right of the tree
         else{
            current = current.rightChild;
            //insert to the right
            if(current == null){
               parent.rightChild = tempNode;
               return;
            }
         }
      }            
   }
}    

先序遍歷

這是一個簡單的三步過程。

  • 訪問根節點

  • 遍歷左子樹

  • 遍歷右子樹

private void preOrder(Node root){
   if(root!=null){
      System.out.print(root.data + " ");
      preOrder(root.leftChild);
      preOrder(root.rightChild);
   }
}

中序遍歷

這是一個簡單的三步過程。

  • 遍歷左子樹

  • 訪問根節點

  • 遍歷右子樹

private void inOrder(Node root){
   if(root!=null){
      inOrder(root.leftChild);
      System.out.print(root.data + " ");            
      inOrder(root.rightChild);
   }
}

後序遍歷

這是一個簡單的三步過程。

  • 遍歷左子樹

  • 遍歷右子樹

  • 訪問根節點

private void postOrder(Node root){
   if(root!=null){            
      postOrder(root.leftChild);
      postOrder(root.rightChild);
      System.out.print(root.data + " ");
   }
}

樹的實現

Node.java

package com.tutorialspoint.datastructure;

public class Node {
   public int data;
   public Node leftChild;
   public Node rightChild;

   public Node(){}

   public void display(){
      System.out.print("("+data+ ")");
   }
}

Tree.java

package com.tutorialspoint.datastructure;

public class Tree {
   private Node root;

   public Tree(){
      root = null;
   }
   
   public Node search(int data){
      Node current = root;
      System.out.print("Visiting elements: ");
      while(current.data != data){
         if(current != null)
            System.out.print(current.data + " "); 
            //go to left tree
            if(current.data > data){
               current = current.leftChild;
            }//else go to right tree
            else{                
               current = current.rightChild;
            }
            //not found
            if(current == null){
               return null;
            }
         }
      return current;
   }

   public void insert(int data){
      Node tempNode = new Node();
      tempNode.data = data;

      //if tree is empty
      if(root == null){
         root = tempNode;
     }else{
         Node current = root;
         Node parent = null;

         while(true){                
            parent = current;
            //go to left of the tree
            if(data < parent.data){
               current = current.leftChild;                
               //insert to the left
               if(current == null){
                  parent.leftChild = tempNode;
                  return;
               }
            }//go to right of the tree
            else{
               current = current.rightChild;
               //insert to the right
               if(current == null){
                  parent.rightChild = tempNode;
                  return;
               }
            }
         }            
      }
   }    

   public void traverse(int traversalType){
      switch(traversalType){
         case 1:
            System.out.print("\nPreorder traversal: ");
            preOrder(root);
            break;
         case 2:
            System.out.print("\nInorder traversal: ");
            inOrder(root);
            break;
         case 3:
            System.out.print("\nPostorder traversal: ");
            postOrder(root);
            break;
         }            
   }   

   private void preOrder(Node root){
      if(root!=null){
         System.out.print(root.data + " ");
         preOrder(root.leftChild);
         preOrder(root.rightChild);
      }
   }

   private void inOrder(Node root){
      if(root!=null){
         inOrder(root.leftChild);
         System.out.print(root.data + " ");            
         inOrder(root.rightChild);
      }
   }

   private void postOrder(Node root){
      if(root!=null){            
         postOrder(root.leftChild);
         postOrder(root.rightChild);
         System.out.print(root.data + " ");
      }
   }
}

演示程式

TreeDemo.java

package com.tutorialspoint.datastructure;

public class TreeDemo {
   public static void main(String[] args){
      Tree tree = new Tree();

      /*                     11               //Level 0
      */
      tree.insert(11);
      /*                     11               //Level 0
      *                      |
      *                      |---20           //Level 1
      */
      tree.insert(20);
      /*                     11               //Level 0
      *                      |
      *                  3---|---20           //Level 1
      */
      tree.insert(3);        
      /*                     11               //Level 0
      *                      |
      *                  3---|---20           //Level 1
      *                           |
      *                           |--42       //Level 2
      */
      tree.insert(42);
      /*                     11               //Level 0
      *                      |
      *                  3---|---20           //Level 1
      *                           |
      *                           |--42       //Level 2
      *                               |
      *                               |--54   //Level 3
      */
      tree.insert(54);
      /*                     11               //Level 0
      *                      |
      *                  3---|---20           //Level 1
      *                           |
      *                       16--|--42       //Level 2
      *                               |
      *                               |--54   //Level 3
      */
      tree.insert(16);
      /*                     11               //Level 0
      *                      |
      *                  3---|---20           //Level 1
      *                           |
      *                       16--|--42       //Level 2
      *                               |
      *                           32--|--54   //Level 3
      */
      tree.insert(32);
      /*                     11               //Level 0
      *                      |
      *                  3---|---20           //Level 1
      *                  |        |
      *                  |--9 16--|--42       //Level 2
      *                               |
      *                           32--|--54   //Level 3
      */
      tree.insert(9);
      /*                     11               //Level 0
      *                      |
      *                  3---|---20           //Level 1
      *                  |        |
      *                  |--9 16--|--42       //Level 2
      *                     |         |
      *                  4--|     32--|--54   //Level 3
      */
      tree.insert(4);
      /*                     11               //Level 0
      *                      |
      *                  3---|---20           //Level 1
      *                  |        |
      *                  |--9 16--|--42       //Level 2
      *                     |         |
      *                  4--|--10 32--|--54   //Level 3
      */
      tree.insert(10);
      Node node = tree.search(32);
      if(node!=null){
         System.out.print("Element found.");
         node.display();
         System.out.println();
      }else{
         System.out.println("Element not found.");
      }

      Node node1 = tree.search(2);
      if(node1!=null){
         System.out.println("Element found.");
         node1.display();
         System.out.println();
      }else{
         System.out.println("Element not found.");
      }        

      //pre-order traversal
      //root, left ,right
      tree.traverse(1);
      //in-order traversal
      //left, root ,right
      tree.traverse(2);
      //post order traversal
      //left, right, root
      tree.traverse(3);       
   }
}

如果我們編譯並執行上述程式,則會產生以下結果:

Visiting elements: 11 20 42 Element found.(32)
Visiting elements: 11 3 Element not found.

Preorder traversal: 11 3 9 4 10 20 16 42 32 54 
Inorder traversal: 3 4 9 10 11 16 20 32 42 54 
Postorder traversal: 4 10 9 3 16 32 54 42 20 11
廣告