1. 程式人生 > >資料結構(七)——樹結構(Tree) 之二叉樹的常用操作

資料結構(七)——樹結構(Tree) 之二叉樹的常用操作

一.鏈式儲存的二叉樹的操作

1.遍歷二叉樹

  • 先序遍歷:根-->左-->右
  • 中序遍歷:左-->根-->右
  • 後序遍歷:左-->右-->根

2.二叉樹結點的查詢 

結點的查詢也可以分為先序查詢,中序查詢和後序查詢。方式和遍歷方式相似。

3.刪除二叉樹結點

  • 二叉樹抽象類程式碼
package cn.kimtian.tree;

/**
 * 鏈式儲存的二叉樹
 *
 * @author kimtian
 */
public class BinaryTree {
    /**
     * 根結點
     */
    TreeNode root;

    /**
     * 設定根結點
     *
     * @param root 根結點
     */
    public void setRoot(TreeNode root) {
        this.root = root;
    }

    /**
     * 獲取根結點
     *
     * @return TreeNode 根結點
     */
    public TreeNode getRoot() {
        return root;
    }

    /**
     * 先序遍歷
     */
    public void frontShow() {
        if (root != null) {
            root.frontShow();
        }
    }

    /**
     * 中序遍歷
     */
    public void middleShow() {
        if (root != null) {
            root.middleShow();
        }
    }

    /**
     * 後序遍歷
     */
    public void behindShow() {
        if (root != null) {
            root.behindShow();
        }
    }

    /**
     * 查詢二叉樹的結點--先序查詢
     *
     * @param i 查詢的結點的值
     */
    public TreeNode frontSearch(int i) {
        return root.frontSearch(i);
    }

    /**
     * 查詢二叉樹的結點--中序查詢
     *
     * @param i 查詢的結點的值
     */
    public TreeNode middleSearch(int i) {
        return root.middleSearch(i);
    }

    /**
     * 查詢二叉樹的結點--後序查詢
     *
     * @param i 查詢的結點的值
     */
    public TreeNode behindSearch(int i) {
        return root.behindSearch(i);
    }

    /**
     * 刪除二叉樹的結點/子樹
     *
     * @param i 查詢的結點的值
     */
    public void deleteTreeNode(int i) {
        if (root.value == i) {
            root = null;
        } else {
            root.deleteTreeNode(i);
        }
    }
}
  • 二叉樹的結點
package cn.kimtian.tree;

/**
 * 樹裡面的結點
 *
 * @author kimtian
 */
public class TreeNode {
    /**
     * 樹裡面的值,結點的權
     */
    int value;
    /**
     * 左兒子
     */
    TreeNode leftNode;
    /**
     * 右兒子
     */
    TreeNode rightNode;

    public TreeNode(int value) {
        this.value = value;
    }

    public void setLeftNode(TreeNode leftNode) {
        this.leftNode = leftNode;
    }

    public void setRightNode(TreeNode rightNode) {
        this.rightNode = rightNode;
    }

    /**
     * 先序遍歷--遞迴思想
     */
    public void frontShow() {
        //先遍歷當前結點的內容
        System.out.print(value + " ");
        //左結點
        if (leftNode != null) {
            leftNode.frontShow();
        }
        //右結點
        if (rightNode != null) {
            rightNode.frontShow();
        }
    }

    /**
     * 中序遍歷
     */
    public void middleShow() {
        //左結點
        if (leftNode != null) {
            leftNode.middleShow();
        }
        System.out.print(value + " ");
        //右結點
        if (rightNode != null) {
            rightNode.middleShow();
        }
    }

    /**
     * 後序遍歷
     */
    public void behindShow() {
        //左結點
        if (leftNode != null) {
            leftNode.behindShow();
        }
        //右結點
        if (rightNode != null) {
            rightNode.behindShow();
        }
        System.out.print(value + " ");
    }

    /**
     * 先序查詢
     *
     * @param i 查詢的結點的值
     */
    public TreeNode frontSearch(int i) {
        TreeNode target = null;
        //對比當前結點的值
        if (value == i) {
            return this;
        }
        //當前結點的值不是要查詢的結點
        else {
            //查詢左兒子
            if (leftNode != null) {
                target = leftNode.frontSearch(i);
            }
            if (target != null) {
                return target;
            }
            //查詢右兒子
            if (rightNode != null) {
                target = rightNode.frontSearch(i);
            }
            if (target != null) {
                return target;
            }
        }
        return target;
    }

    /**
     * 中序查詢
     *
     * @param i 查詢的結點的值
     */
    public TreeNode middleSearch(int i) {
        TreeNode target = null;
        //對比左兒子的值
        if (leftNode != null) {
            target = leftNode.middleSearch(i);
        }
        if (target != null) {
            return target;
        }
        //對比當前結點的值
        if (value == i) {
            return this;
        }
        //查詢右兒子
        if (rightNode != null) {
            target = rightNode.middleSearch(i);
        }
        if (target != null) {
            return target;
        }

        return target;
    }

    /**
     * 後序查詢
     *
     * @param i 查詢的結點的值
     */
    public TreeNode behindSearch(int i) {
        TreeNode target = null;
        //對比左兒子的值
        if (leftNode != null) {
            target = leftNode.behindSearch(i);
        }
        if (target != null) {
            return target;
        }
        //查詢右兒子
        if (rightNode != null) {
            target = rightNode.behindSearch(i);
        }
        if (target != null) {
            return target;
        }

        //對比當前結點的值
        if (value == i) {
            return this;
        }
        return target;
    }

    /**
     * 刪除二叉樹的結點/子樹
     *
     * @param i 要刪除的結點的值
     */
    public void deleteTreeNode(int i) {
        TreeNode parent = this;
        //判斷左兒子
        if (parent.leftNode != null && parent.leftNode.value == i) {
            parent.leftNode = null;
            return;
        }
        //判斷右邊兒子
        if (parent.rightNode != null && parent.rightNode.value == i) {
            parent.rightNode = null;
            return;
        }
        //遞迴檢查並刪除左兒子
        parent = leftNode;
        if (parent != null) {
            parent.deleteTreeNode(i);
        }
        //遞迴檢查並刪除右兒子
        parent = rightNode;
        if (parent != null) {
            parent.deleteTreeNode(i);
        }

    }
}

(3)測試類。

package cn.kimtian.tree;

/**
 * 測試鏈式儲存的二叉樹
 *
 * @author kimtian
 */
public class TestBinaryTree {
    public static void main(String[] args) {
        //建立一棵樹
        BinaryTree binaryTree = new BinaryTree();
        //建立一個根結點
        TreeNode root = new TreeNode(1);
        //將根結點賦給樹
        binaryTree.setRoot(root);
        //建立一個子左結點
        TreeNode leftTwo = new TreeNode(2);
        //建立一個子右結點
        TreeNode rightTwo = new TreeNode(3);
        //給根的左結點賦值
        root.setLeftNode(leftTwo);
        //給根的右結點賦值
        root.setRightNode(rightTwo);
        //第三層結點
        TreeNode llThree = new TreeNode(4);
        TreeNode lrThree = new TreeNode(5);
        TreeNode rlThree = new TreeNode(6);
        TreeNode rrThree = new TreeNode(7);
        leftTwo.setLeftNode(llThree);
        leftTwo.setRightNode(lrThree);
        rightTwo.setLeftNode(rlThree);
        rightTwo.setRightNode(rrThree);
        //先序遍歷
        binaryTree.frontShow();
        System.out.println();
        //中序遍歷
        binaryTree.middleShow();
        System.out.println();
        //後序遍歷
        binaryTree.behindShow();
        System.out.println();
        System.out.println("====================");
        //先序查詢
        TreeNode result = binaryTree.frontSearch(5);
        System.out.println(result);
        System.out.println(result == lrThree);
        TreeNode result1 = binaryTree.frontSearch(10);
        System.out.println(result1);

        System.out.println();
        System.out.println("====================");
        //中序查詢
        TreeNode result2 = binaryTree.middleSearch(5);
        System.out.println(result2);
        System.out.println(result2 == lrThree);
        TreeNode result3 = binaryTree.middleSearch(10);
        System.out.println(result3);
        System.out.println();
        System.out.println("====================");

        //後序查詢
        TreeNode result4 = binaryTree.behindSearch(5);
        System.out.println(result4);
        System.out.println(result4 == lrThree);
        TreeNode result5 = binaryTree.behindSearch(10);
        System.out.println(result5);
        //先序遍歷
        binaryTree.frontShow();
        System.out.println();
        //刪除一個子樹
        binaryTree.deleteTreeNode(1);
        //先序遍歷
        binaryTree.frontShow();
        System.out.println();

    }
}

二.順序儲存的二叉樹的操作

順序儲存的二叉樹通常情況只考慮完全二叉樹。

  • 第n個元素的左子結點是2*n+1
  • 第n個元素的右子結點是2*n+2
  • 第n個元素的父結點是(n-1)/2

1.遍歷二叉樹

  • 先序遍歷:根-->左-->右
  • 中序遍歷:左-->根-->右
  • 後序遍歷:左-->右-->根
package cn.kimtian.tree.arraybinarytree;

/**
 * 順序儲存的二叉樹
 *
 * @author kimtian
 */
public class ArrayBinaryTree {
    /**
     * 一個儲存樹的陣列
     */
    int[] data;

    public ArrayBinaryTree(int[] data) {
        this.data = data;
    }

    /**
     * 前序遍歷
     *
     * @param index 從哪個結點開始遍歷
     */
    public void frontShow(int index) {
        if (data == null || data.length == 0) {
            return;
        }
        //先遍歷當前結點的內容
        System.out.print(data[index] + " ");
        //處理左子結點
        if (2 * index + 1 < data.length) {
            frontShow(2 * index + 1);
        }
        //處理右子結點
        if (2 * index + 2 < data.length) {
            frontShow(2 * index + 2);
        }
    }

    /**
     * 前序遍歷 過載方法
     */
    public void frontShow() {
        frontShow(0);
    }

    /**
     * 中序遍歷
     *
     * @param index 從哪個結點開始遍歷
     */
    public void middleShow(int index) {
        if (data == null || data.length == 0) {
            return;
        }
        //處理左子結點
        if (2 * index + 1 < data.length) {
            middleShow(2 * index + 1);
        }
        //先遍歷當前結點的內容
        System.out.print(data[index] + " ");
        //處理右子結點
        if (2 * index + 2 < data.length) {
            middleShow(2 * index + 2);
        }
    }

    /**
     * 中序遍歷
     */
    public void middleShow() {
        middleShow(0);
    }

    /**
     * 後序遍歷
     *
     * @param index 從哪個結點開始遍歷
     */
    public void behindShow(int index) {
        if (data == null || data.length == 0) {
            return;
        }
        //處理左子結點
        if (2 * index + 1 < data.length) {
            behindShow(2 * index + 1);
        }
        //處理右子結點
        if (2 * index + 2 < data.length) {
            behindShow(2 * index + 2);
        }
        //先遍歷當前結點的內容
        System.out.print(data[index] + " ");
    }

    /**
     * 後序遍歷
     */
    public void behindShow() {
        behindShow(0);
    }
}