跟小刀學習 數據結構二叉樹的實現

  • 最近學習的有點累。導致二叉樹學習的有點模糊
  • 我們之前學過數組 和鏈表 數組插入比較慢 鏈表查詢比較慢。這時候我們就需要使用樹這種結構。都比較快
  • 樹的基本概念
  • :樹最上面的節點稱爲根節點,一棵樹只有一個根節點
  • 父節點:每一個節點都有一條邊向上連接到另一個節點,這個節點就是稱爲下面這個節點的父節點
  • 子節點:每一個節點都有條向下連接的節點,下面的這個節點就是該節點的子節點
  • 葉子節點:沒有子節點的節點也叫葉子節點.
  • 子樹:每一個節點都可以作爲一個子樹的根。他和他的所有子節點組合在一起就是個子樹
  • 查找節點:從根節點開始查找,如果查找的節點值比當前節點的值小,則繼續查找左子樹,否則查找右子樹
  • 遍歷樹:遍歷樹是根據一個特定的順序訪問樹的每一個節點,根據順序的不同分爲前序,中序,後序遍歷三種。
  • 前序遍歷。

    • (1)訪問根節點
    • (2)前序遍歷左子樹
    • (3)前序遍歷右子樹
  • 中序遍歷。

    • (1)中序遍歷左子樹
    • (2)訪問根節點
    • (3)中序遍歷右子樹
  • 後序遍歷。

    • (1)後序遍歷左子樹
    • (2)後序遍歷右子樹
    • (3)訪問根節點

上代碼:

/**
 * 二叉樹的節點類
 * @author Administrator
 *
 */
public class Node {

    public int iData;

    public String sData;

    public Node leftChild;
    public Node rightChild;


    public Node(int iData,String sData) {
        this.iData = iData;
        this.sData =sData;
    }


    public Node() {
        // TODO Auto-generated constructor stub
    }


    public void dispalyNode(){
        System.out.print("{"+ iData +"}");
    }

}

二叉樹的具體實現

package com.chapter5_1;

public class Tree {

    //根節點
    public Node root;

    /**
     * 二叉樹的插入 s
     */
    public void insert(int d,String s){
        //新節點
        Node newNode = new Node(d,s);
        //引用當前的節點
        Node current = root;
        //引用父節點
        Node parent;

        if(current == null){
            root = newNode;
            return ;//如果root節點爲空的話,直接點添加都結束了
        }  


        while(true){
            //先將當前的節點付給一個parent. 這個節點一直在變動
            parent = current;

            if(d < current.iData){
                //當前的節點變成剛纔的左節點
                current = current.leftChild;
                if(current == null){
                    parent.leftChild =newNode;
                    return;
                }
            }else{//d > 

//              變成剛纔的又節點
                current = current.rightChild;

                if(current == null){
                    parent.rightChild= newNode;
                    return;
                }

            }
        }
    }

    /**
     * 查找二叉樹
     * @param value
     * @return
     */
    public Node find(int value){
        Node current = root;

        while(current.iData !=value){
            //如果這個值比當前的節點值小,那麼找左子節點
            if(current.iData > value){
                current = current.leftChild;
            }else{
                current = current.rightChild;
            }

            if(current == null){
                return null;
            }
        }

        return  current;

    }
    public void traverse(int traverseType){
        switch (traverseType) {
        case 1://
            //前序遍歷
            System.out.println("前序遍歷");
            frontOrder(root);
            break;
        case 2:
            System.out.println("中序遍歷");
            inOrder(root);
            break;
        case 3:
            System.out.println("後序遍歷");
            postOrder(root);
            break;

        default:
            break;
        }
        System.out.println("--------------------------------");
    }

    /**
     * 前序遍歷
     * @param localNode
     */
    public void frontOrder(Node localNode){

        if(localNode != null){
            //訪問根節點
            System.out.println(localNode.iData +","+localNode.sData);
            //前序遍歷左子樹
            frontOrder(localNode.leftChild);
            //前序遍歷右子樹
            frontOrder(localNode.rightChild);
        }
    }
    /**
     *  中序遍歷 -
     * 1.中序遍歷左子樹
     * 2.訪問根節點
     * 3.中序遍歷右子樹(從小到大)
     * @param localNode
     */
    public void inOrder(Node localNode){

        if(localNode != null){

            //中序遍歷左子樹
            inOrder(localNode.leftChild);
            //訪問根節點
            System.out.println(localNode.iData +","+localNode.sData);
            //中序遍歷右子樹
            inOrder(localNode.rightChild);
        }
    }
    /**
     * 後序遍歷。。先遍歷左子樹-右子樹-訪問根節點
     * @param localNode
     */
    public void postOrder(Node localNode){

        if(localNode != null){

            //後序遍歷左子樹
            postOrder(localNode.leftChild);
            //後序遍歷右子樹
            postOrder(localNode.rightChild);
            //訪問根節點
            System.out.println(localNode.iData +","+localNode.sData);

        }
    }

    /**
     * 刪除一個節點
     * 有3種情況
     * 1.該節點是葉子節點
     * 2.該節點只有 一個節點
     * 3.該節點有倆個節點。需要找到右邊節點的最小節點。(中序遍歷後繼。。找到)
     * @param value
     * @return
     */
    public  boolean delete(int value){

        //引用當前節點
        Node current = root;
        //引用父節點
        Node parent = root;

        //判斷是否爲左子節點
        boolean isLeftChild  =true;
        while(current.iData != value){
            //先賦值
            parent = current;
            //如果這個值比當前的節點值小,那麼找左子節點
            if(current.iData > value){
                current = current.leftChild;
                isLeftChild  =true;
            }else{
                current = current.rightChild;
                isLeftChild  =false;
            }

            if(current == null){
                return false;
            }
        }


        //刪除葉子節點,也就是該節點沒有子節點
        if(current.leftChild == null && current.rightChild == null){
            if(current == root){//刪除的是根。並且根麼有子子節點
                root = null;
            }else if(isLeftChild){//刪除的葉子節點是父節點的左子節點
                parent.leftChild = null;

            }else{
                parent.rightChild = null;
            }

    }else if(current.rightChild == null){//只有一個節點  意思就是左子節點有數據

        if(current == root){//如果是根的話。就是根節點=當前的左子節點 
            root = current.leftChild;
        }else if(isLeftChild){
            parent.leftChild = current.leftChild;
        }else{
            parent.rightChild = current.leftChild;
        }

    }else if(current.leftChild == null){//只有一個節點  意思就是右子節點有數據
        if(current == root) root = current.rightChild;
        //這裏看起來比較繞。。所以刪除的時候可以自己畫一個圖。自己想
        else if(isLeftChild){
            parent.leftChild = current.rightChild;
        }else{
            parent.rightChild = current.rightChild;
        }
    }else{//有倆個節點。。。。
        Node successor = getSuccessor(current);

        if(current ==root){
            root = successor;

        }else if(isLeftChild){
            parent.leftChild = successor;
        }else{
            parent.rightChild = successor;
        }

        successor.leftChild =current.leftChild; 
    }
        return true;
    }


    public Node getSuccessor(Node delNode){
        Node successor = delNode;
        Node successorParent = delNode;

        Node current =delNode.rightChild;

        while(current != null){
            successorParent =successor;
            successor =current;//先右邊然後然後一直找左子節點
            current = current.leftChild;//一直往左子節點找
        }
        if(successor != delNode.rightChild){//這裏沒有看懂。
            successorParent.leftChild = successor.rightChild;
            successor.rightChild = delNode.rightChild;

        }
        return successor;

    }
}

測試代碼:

package com.chapter5_1;

public class Test {

    public static void main(String[] args) {
        Tree t = new Tree();

        t.insert(10,"thinkpad");
        t.insert(20,"mac");
        t.insert(15,"del");
        t.insert(3,"leishen");
        t.insert(40,"zhangsan");
        t.insert(16,"liao");
        t.insert(4,"luyao");

//      System.out.println(t.root.rightChild.iData);
//      System.out.println(t.root.rightChild.leftChild.iData);
//      System.out.println(t.root.leftChild.iData);


//      Node node = t.find(15);
////        System.out.println(node.iData +", " +  node.sData);
//      node = t.find(3);
////        System.out.println(node.iData +", " +  node.sData);
        t.delete(3);
//      t.traverse(1);
        t.traverse(2);
//      t.traverse(3);

        t.delete(16);
//      t.traverse(1);
        t.traverse(2);
    }
}

至於測試結果我就不貼了。很多。在刪除二叉樹有倆個節點的時。我沒有弄明白。我先貼代碼。最近比較累。

發佈了35 篇原創文章 · 獲贊 13 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章