Java_二叉树概念及基本操作

树、森林和二叉树的转换

  • 树转换为二叉树
  • 森林转换为树
  • 二叉树转换为树
  • 二叉树转换为森林
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");
    }

 
     /** 
      * 构建二叉树 
      *              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;
    }
    
    /**
     * #方法创建二叉树
     * 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) {
            //根结点
            root = treeNode;
        }
        nodes.remove(0);
        //创建左孩子
        treeNode.leftChild = createTree(size, nodes);
        //创建右孩子
        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;
    }

    /**
     * 获取二叉树的结点数
     * 
     * @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);
        }
    }

    /**
     * 求二叉树的叶子节点 先计算左子树叶子节点,再计算右子树叶子节点
     * 
     * @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;
    }

    /**
     * 找二叉树最左边的孩子节点
     * 
     * @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;
    }
    
    /**
     * 后续遍历 - 非递归 
     * 步骤1  如果结点有左子树,该结点入栈; 如果结点没有左子树,访问该结点; 
     * 步骤2  如果结点有右子树,重复
     * 步骤3  如果结点没有右子树(结点访问完毕),根据栈顶指示回退,访问栈顶元素,
     *     并访问右子树,重复步骤 如果栈为空,表示遍历结束。
     */
    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;
            }
        }
    }
    /**
     * 中续遍历 - 非递归 
     * 1、让做孩子循环进栈,当没有左孩子退出,执行出栈。
     * 2、获取刚出栈的结点,为空时出栈并处理右子树,不为空循环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);
        }
    }

    /**
     * 前序遍历——非迭代 需要借助栈模式进行操作
     */
    public void nonRecOrder(TreeNode node) {
        if (node == null) {
            return;
        }
        Stack<TreeNode> stack = new Stack<TreeNode>();
        stack.push(node);
        while (!stack.isEmpty()) {
            // 出栈和进栈
            TreeNode n = stack.pop();// 弹出根结点
            // 压入子结点
            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层保存在一个队列中,然后按节点访问,并把已经访问节点的左右孩子节点放在第二个队列中,当第一个队
 * 列中的所有节点都访问完成之后,交换两个节点。这样重复下去,知道所有层的节点都被访问,这样做的代价就是空间复杂度有点高。
 */
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()) {//某一层的所有孩子结点
            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
 * 递归遍历,遍历某一层的数据,想要遍历整个树,对层次进行for循环
 * 
 * @param node
 *            起始结点为根结点
 * @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("非递归后续遍历:");
        binaryTree.nonPostOrder(binaryTree.root);

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

}

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,340评论 5 467
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,762评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,329评论 0 329
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,678评论 1 270
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,583评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 47,995评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,493评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,145评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,293评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,250评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,267评论 1 328
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,973评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,556评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,648评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,873评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,257评论 2 345
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,809评论 2 339

推荐阅读更多精彩内容

  • 树的概述 树是一种非常常用的数据结构,树与前面介绍的线性表,栈,队列等线性结构不同,树是一种非线性结构 1.树的定...
    Jack921阅读 4,414评论 1 31
  • 1.树(Tree): 树是 n(n>=0) 个结点的有限集。当 n=0 时称为空树。在任意一颗非空树中:有且仅有一...
    ql2012jz阅读 970评论 0 3
  • 基于树实现的数据结构,具有两个核心特征: 逻辑结构:数据元素之间具有层次关系; 数据运算:操作方法具有Log级的平...
    yhthu阅读 4,223评论 1 5
  • 四、树与二叉树 1. 二叉树的顺序存储结构 二叉树的顺序存储就是用数组存储二叉树。二叉树的每个结点在顺序存储中都有...
    MinoyJet阅读 1,490评论 0 7
  • 概念 树是什么 树(Tree)是n(n>=0)个结点的有限集。 n = 0的树是空树。 在任意一棵非空树中: 有且...
    刚刚悟道阅读 5,018评论 1 16