Java_二叉樹概念及基本操作

樹、森林和二叉樹的轉(zhuǎn)換

  • 樹轉(zhuǎn)換為二叉樹
  • 森林轉(zhuǎn)換為樹
  • 二叉樹轉(zhuǎn)換為樹
  • 二叉樹轉(zhuǎn)換為森林
Paste_Image.png

代碼

package com.self.data;

import java.util.ArrayList;
import java.util.Stack;

public class BinaryTree {
    private TreeNode root = null;

    public BinaryTree() {
        root = new TreeNode("A");
    }

 
     /** 
      * 構(gòu)建二叉樹 
      *              A 
      *         B         C 
      *     D      E    #   F 
      *   #   #  #   #    #   #  
      *   
      *   ABD##E##C#F##      
      */  
    public void createBinaryTree() {
        TreeNode nodeB = new TreeNode("B");
        TreeNode nodeC = new TreeNode("C");
        TreeNode nodeD = new TreeNode("D");
        TreeNode nodeE = new TreeNode("E");
        TreeNode nodeF = new TreeNode("F");
        root.leftChild = nodeB;
        root.rightChild = nodeC;
        nodeB.leftChild = nodeD;
        nodeB.rightChild = nodeE;
        nodeC.rightChild = nodeF;
    }
    
    /**
     * #方法創(chuàng)建二叉樹
     * ABD##E##C#F##   
     *                                                               
     * @return
     */
    public void createTree(ArrayList<String> nodes){
        if (nodes==null || nodes.size()==0) {
            return;
        }
        createTree(nodes.size(), nodes);
    }
    public TreeNode createTree(int size,ArrayList<String> nodes){
        TreeNode treeNode = null;
        int index = size - nodes.size();
        String ch = nodes.get(0);
        if ("#".equals(ch)) {
            nodes.remove(0);
            return null;
        }
        treeNode = new TreeNode(index, ch);
        if (index==0) {
            //根結(jié)點(diǎn)
            root = treeNode;
        }
        nodes.remove(0);
        //創(chuàng)建左孩子
        treeNode.leftChild = createTree(size, nodes);
        //創(chuàng)建右孩子
        treeNode.rightChild = createTree(size, nodes);
        return treeNode;
    }
    

    /**
     * 求二叉樹的高度
     * 
     * @author Administrator
     * 
     */
    public int getHeight() {
        return getHeight(root);
    }

    private int getHeight(TreeNode node) {
        if (node == null) {
            return 0;
        }

        int i = getHeight(node.leftChild);
        int j = getHeight(node.rightChild);
        return (i < j) ? j + 1 : i + 1;
    }

    /**
     * 獲取二叉樹的結(jié)點(diǎn)數(shù)
     * 
     * @author Administrator
     */
    public int getSize() {
        return getSize(root);
    }

    private int getSize(TreeNode node) {
        if (node == null) {
            return 0;
        } else {
            return 1 + getSize(node.leftChild) + getSize(node.rightChild);
        }
    }

    /**
     * 求二叉樹的葉子節(jié)點(diǎn) 先計(jì)算左子樹葉子節(jié)點(diǎn)放接,再計(jì)算右子樹葉子節(jié)點(diǎn)
     * 
     * @return
     */
    public int getLeafSize() {
        return getLeafSize(root);
    }

    private int getLeafSize(TreeNode node) {
        int leafSize = 0;
        if (node == null) {
            return 0;
        }
        if (node.leftChild == null && node.rightChild == null) {
            leafSize++;
        }
        leafSize += getLeafSize(node.leftChild);
        leafSize += getLeafSize(node.rightChild);
        return leafSize;
    }

    /**
     * 找二叉樹最左邊的孩子節(jié)點(diǎn)
     * 
     * @return
     */

    private TreeNode getLeftMostNode(TreeNode node, Stack<TreeNode> stack) {
        if (node == null) {
            return null;
        }
        while (node.leftChild != null) {
            stack.push(node);
            node = node.leftChild;
        }
        return node;
    }
    
    /**
     * 后續(xù)遍歷 - 非遞歸 
     * 步驟1  如果結(jié)點(diǎn)有左子樹,該結(jié)點(diǎn)入棧婚惫; 如果結(jié)點(diǎn)沒有左子樹,訪問該結(jié)點(diǎn)蒜撮; 
     * 步驟2  如果結(jié)點(diǎn)有右子樹襟士,重復(fù)
     * 步驟3  如果結(jié)點(diǎn)沒有右子樹(結(jié)點(diǎn)訪問完畢),根據(jù)棧頂指示回退烈拒,訪問棧頂元素圆裕,
     *     并訪問右子樹,重復(fù)步驟 如果棧為空荆几,表示遍歷結(jié)束吓妆。
     */
    public void nonPostOrder(TreeNode node) {
        if (node == null) {
            return;
        }
        Stack<TreeNode> stack = new Stack<TreeNode>();
        TreeNode treeNode = getLeftMostNode(node, stack);
        while (treeNode != null) {
            System.out.println("nonRecOrderdata" + treeNode.getData());
            if (treeNode.rightChild != null) {
                treeNode = getLeftMostNode(treeNode.rightChild, stack);
            } else if (!stack.isEmpty()) {
                treeNode = stack.pop();
            } else {
                treeNode = null;
            }
        }
    }
    /**
     * 中續(xù)遍歷 - 非遞歸 
     * 1、讓做孩子循環(huán)進(jìn)棧吨铸,當(dāng)沒有左孩子退出行拢,執(zhí)行出棧。
     * 2诞吱、獲取剛出棧的結(jié)點(diǎn)舟奠,為空時(shí)出棧并處理右子樹,不為空循環(huán)1,2房维。
     */
    
    public void nonMidOrder(TreeNode node) {
        if (node == null) {
            return;
        }
        Stack<TreeNode> stack = new Stack<TreeNode>();
        TreeNode root = node;
        while (root != null || !stack.isEmpty()) {
            while (root != null) {
                stack.push(root);// 先訪問再入棧
                root = root.leftChild;
            }
            root = stack.pop();
            System.out.println("nonRecOrderdata " + root.getData());
            root = root.rightChild;// 如果是null沼瘫,出棧并處理右子樹
        }
    }

    /**
     * 前序遍歷——迭代
     * 
     * @author Administrator
     * 
     */
    public void preOrder(TreeNode node) {
        if (node == null) {
            return;
        } else {
            System.out.println("preOrder data:" + node.getData());
            preOrder(node.leftChild);
            preOrder(node.rightChild);
        }
    }

    /**
     * 前序遍歷——非迭代 需要借助棧模式進(jìn)行操作
     */
    public void nonRecOrder(TreeNode node) {
        if (node == null) {
            return;
        }
        Stack<TreeNode> stack = new Stack<TreeNode>();
        stack.push(node);
        while (!stack.isEmpty()) {
            // 出棧和進(jìn)棧
            TreeNode n = stack.pop();// 彈出根結(jié)點(diǎn)
            // 壓入子結(jié)點(diǎn)
            System.out.println("nonRecOrder data" + n.getData());
            if (n.rightChild != null) {
                stack.push(n.rightChild);

            }
            if (n.leftChild != null) {
                stack.push(n.leftChild);
            }
        }
    }

    /**
     * 中序遍歷——迭代
     * 
     * @author Administrator
     * 
     */
    public void midOrder(TreeNode node) {
        if (node == null) {
            return;
        } else {
            midOrder(node.leftChild);
            System.out.println("midOrder data:" + node.getData());
            midOrder(node.rightChild);
        }
    }

    /**
     * 后序遍歷——迭代
     * 
     * @author Administrator
     * 
     */
    public void postOrder(TreeNode node) {
        if (node == null) {
            return;
        } else {
            postOrder(node.leftChild);
            postOrder(node.rightChild);
            System.out.println("postOrder data:" + node.getData());
        }
    }

    public class TreeNode {
        private int index;
        private String data;
        private TreeNode leftChild;
        private TreeNode rightChild;

        public int getIndex() {
            return index;
        }

        public void setIndex(int index) {
            this.index = index;
        }

        public String getData() {
            return data;
        }

        public void setData(String data) {
            this.data = data;
        }

        public TreeNode(int index, String data) {
            this.index = index;
            this.data = data;
            this.leftChild = null;
            this.rightChild = null;
        }

        public TreeNode(String data) {
            this.data = data;
            this.leftChild = null;
            this.rightChild = null;
        }
    }

/**
 * 層次遍歷方法1
 * 首先把第0層保存在一個(gè)隊(duì)列中,然后按節(jié)點(diǎn)訪問咙俩,并把已經(jīng)訪問節(jié)點(diǎn)的左右孩子節(jié)點(diǎn)放在第二個(gè)隊(duì)列中耿戚,當(dāng)?shù)谝粋€(gè)隊(duì)
 * 列中的所有節(jié)點(diǎn)都訪問完成之后,交換兩個(gè)節(jié)點(diǎn)阿趁。這樣重復(fù)下去膜蛔,知道所有層的節(jié)點(diǎn)都被訪問,這樣做的代價(jià)就是空間復(fù)雜度有點(diǎn)高脖阵。
 */
private void broadLevelTree() {
    LinkedList<TreeNode> linkedList = new LinkedList<BinaryTree.TreeNode>();
    LinkedList<TreeNode> secondList = new LinkedList<BinaryTree.TreeNode>();
    linkedList.add(root);
    System.out.println("層次遍歷:");
    TreeNode tmpRoot = null;
    while (!linkedList.isEmpty()) {//層次
        while (!linkedList.isEmpty()) {//某一層的所有孩子結(jié)點(diǎn)
            tmpRoot = linkedList.removeFirst();
            System.out.print(" " + tmpRoot.data);
            if (tmpRoot.leftChild != null) {
                secondList.add(tmpRoot.leftChild);
            }
            if (tmpRoot.rightChild != null) {
                secondList.add(tmpRoot.rightChild);
            }
        }
        linkedList.addAll(secondList);
        secondList.clear();
    }

}

/**
 * 層次遍歷方法2
 * 遞歸遍歷飞几,遍歷某一層的數(shù)據(jù),想要遍歷整個(gè)樹独撇,對層次進(jìn)行for循環(huán)
 * 
 * @param node
 *            起始結(jié)點(diǎn)為根結(jié)點(diǎn)
 * @param level
 *            第幾層
 * @return
 */
private int broadLevelTree(TreeNode node, int level) {
    if (node == null) {
        return 0;
    }
    if (level == 0) {
        System.out.println("層次遍歷: " + node.data);
        return 1;
    }
    return broadLevelTree(node.leftChild, level - 1)
            + broadLevelTree(node.rightChild, level - 1);
}

    public static void main(String[] args) {
        BinaryTree binaryTree = new BinaryTree();
//      binaryTree.createBinaryTree();
        
        String[] nodes = new String[]{"A","B","D","#","#","E","#","#","C",
                "#","F","#","#"};
        ArrayList<String> listNodes = new ArrayList<String>();
        for (int i = 0; i < nodes.length; i++) {
            listNodes.add(nodes[i]);
        }
        binaryTree.createTree(listNodes);
        
        int height = binaryTree.getHeight();
        System.out.println("treeHeihgt:" + height);
        int size = binaryTree.getSize();
        System.out.println("treeSize:" + size);
        int leafSize = binaryTree.getLeafSize();
        System.out.println("leafSize:" + leafSize);

        System.out.println("前序遍歷:");
        binaryTree.preOrder(binaryTree.root);
        System.out.println("中序遍歷:");
        binaryTree.midOrder(binaryTree.root);
        System.out.println("后序遍歷:");
        binaryTree.postOrder(binaryTree.root);
        System.out.println("非遞歸遍歷:");
        binaryTree.nonRecOrder(binaryTree.root);
        System.out.println("非遞歸中序遍歷:");
        binaryTree.nonMidOrder(binaryTree.root);
        System.out.println("非遞歸后續(xù)遍歷:");
        binaryTree.nonPostOrder(binaryTree.root);

        for (int i = 0; i < 3; i++) {
            binaryTree.broadLevelTree(binaryTree.root, i);
        }
        binaryTree.broadLevelTree();
    }

}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末屑墨,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子纷铣,更是在濱河造成了極大的恐慌卵史,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,183評論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件搜立,死亡現(xiàn)場離奇詭異以躯,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,850評論 3 399
  • 文/潘曉璐 我一進(jìn)店門忧设,熙熙樓的掌柜王于貴愁眉苦臉地迎上來刁标,“玉大人,你說我怎么就攤上這事址晕“蛐福” “怎么了?”我有些...
    開封第一講書人閱讀 168,766評論 0 361
  • 文/不壞的土叔 我叫張陵谨垃,是天一觀的道長启搂。 經(jīng)常有香客問我,道長刘陶,這世上最難降的妖魔是什么胳赌? 我笑而不...
    開封第一講書人閱讀 59,854評論 1 299
  • 正文 為了忘掉前任,我火速辦了婚禮匙隔,結(jié)果婚禮上疑苫,老公的妹妹穿的比我還像新娘。我一直安慰自己纷责,他們只是感情好缀匕,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,871評論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著碰逸,像睡著了一般乡小。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上饵史,一...
    開封第一講書人閱讀 52,457評論 1 311
  • 那天满钟,我揣著相機(jī)與錄音,去河邊找鬼胳喷。 笑死湃番,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的吭露。 我是一名探鬼主播吠撮,決...
    沈念sama閱讀 40,999評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼讲竿!你這毒婦竟也來了泥兰?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,914評論 0 277
  • 序言:老撾萬榮一對情侶失蹤题禀,失蹤者是張志新(化名)和其女友劉穎鞋诗,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體迈嘹,經(jīng)...
    沈念sama閱讀 46,465評論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡削彬,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,543評論 3 342
  • 正文 我和宋清朗相戀三年全庸,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片融痛。...
    茶點(diǎn)故事閱讀 40,675評論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡壶笼,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出雁刷,到底是詐尸還是另有隱情覆劈,我是刑警寧澤,帶...
    沈念sama閱讀 36,354評論 5 351
  • 正文 年R本政府宣布安券,位于F島的核電站墩崩,受9級特大地震影響氓英,放射性物質(zhì)發(fā)生泄漏侯勉。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,029評論 3 335
  • 文/蒙蒙 一铝阐、第九天 我趴在偏房一處隱蔽的房頂上張望址貌。 院中可真熱鬧,春花似錦徘键、人聲如沸练对。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,514評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽螟凭。三九已至,卻和暖如春它呀,著一層夾襖步出監(jiān)牢的瞬間螺男,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,616評論 1 274
  • 我被黑心中介騙來泰國打工纵穿, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留下隧,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,091評論 3 378
  • 正文 我出身青樓谓媒,卻偏偏與公主長得像淆院,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子句惯,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,685評論 2 360

推薦閱讀更多精彩內(nèi)容