• 数据结构实现(三)二叉树


    转载:http://www.cnblogs.com/CherishFX/p/4617105.html

    二叉树( Binary Tree) 是 n(n>=0)个结点的有限集合,该集合或者为空集(称为空二叉树),或者由一个根结点和两棵互不相交的、分别称为根结点的左子树和右子树的二叉树组成 。

    二叉树的遍历方式主要有:先序遍历(NLR),中序遍历(LNR),后序遍历(LRN),和层次遍历。

    • 由二叉树的先序序列和中序序列可以唯一地确定一颗二叉树;
    • 由二叉树的后序序列和中序序列可以唯一地确定一颗二叉树;
    • 由二叉树的层序序列和中序序列可以唯一地确定一棵二叉树;
    • 但,由二叉树的先序序列和后序序列无法唯一地确定一棵二叉树。

    Java实现链式存储的二叉树以及其各种遍历算法:

    package dataStructures;
    
    import java.util.LinkedList;
    import java.util.List;
    import java.util.Queue;
    import java.util.Stack;
    
    class TreeNode<E> {
        public E data; // 数据域
        public TreeNode<E> lchild; // 左孩子
        public TreeNode<E> rchild; // 右孩子
    
        TreeNode() {
        }
    
        TreeNode(E e) {
            this.data = e;
        }
    
        TreeNode(E data, TreeNode<E> lchild, TreeNode<E> rchild) {
            this.data = data;
            this.lchild = lchild;
            this.rchild = rchild;
        }
    }
    
    /**
     * 二叉树的链式存储结构
     */
    public class BinaryTree<E> {
        private TreeNode<E> root; // 根节点
        private List<TreeNode> nodeList = null; // 二叉树结点的链式结构
    
        public BinaryTree() {
        }
    
        public BinaryTree(TreeNode<E> root) {
            this.root = root;
        }
    
        // 把一个数组转化为一颗完全二叉树
        public TreeNode<E> buildTree(E[] array) {
            nodeList = new LinkedList<TreeNode>();
            // 将数组中的元素依次转换为TreeNode节点,存放于链表中
            for (int i = 0; i < array.length; i++) {
                nodeList.add(new TreeNode(array[i]));
            }
            // 对前(array.length / 2 - 1)个父节点(除了最后一个父节点),按照父节点与孩子节点的数字关系建立完全二叉树
            // 对完全二叉树,按从上到下,从左到右的顺序依次编号0,1,2,3....N,则i>0的节点,其左孩子为(2*i+1),其右孩子为(2*i+2)
            for (int j = 0; j < (array.length / 2 - 1); j++) {
                // 左孩子
                nodeList.get(j).lchild = nodeList.get(j * 2 + 1);
                // 右孩子
                nodeList.get(j).rchild = nodeList.get(j * 2 + 2);
            }
            // 最后一个父节点:因为最后一个父节点可能没有右孩子,所以单独处理
            int index = array.length / 2 - 1;
            // 左孩子
            nodeList.get(index).lchild = nodeList.get(index * 2 + 1);
            // 右孩子:如果数组的长度为奇数才有右孩子
            if (array.length % 2 == 1) {
                nodeList.get(index).rchild = nodeList.get(index * 2 + 2);
            }
            root = nodeList.get(0); // 设置根节点
            return root;
        }
    
        // 得到树的高度
        public int height(TreeNode<E> node) {
            if (node == null) {
                return 0;
            } else {
                int i = height(node.lchild);
                int j = height(node.rchild);
                return (i < j) ? (j + 1) : (i + 1);
            }
        }
    
        // 得到节点的个数
        public int size(TreeNode<E> node) {
            if (node == null) {
                return 0;
            } else {
                return 1 + size(node.lchild) + size(node.rchild);
            }
        }
    
        // 递归实现先序遍历 NLR
        public void preOrder(TreeNode<E> node) {
            if (node != null) {
                System.out.print(node.data + " ");
                preOrder(node.lchild);
                preOrder(node.rchild);
            }
        }
    
        // 非递归实现先序遍历 NLR
        public void nonRecPreOrder(TreeNode<E> node) {
            Stack<TreeNode<E>> nodeStack = new Stack<TreeNode<E>>();
            TreeNode<E> nodeTemp = node; // nodeTemp作为遍历指针
            while (nodeTemp != null || !nodeStack.isEmpty()) { // 当nodeTemp非空或栈非空时循环
                if (nodeTemp != null) { // 根指针非空,遍历左子树
                    nodeStack.push(nodeTemp); // 根指针进栈
                    System.out.print(nodeStack.peek().data + " "); // 根指针退栈,访问根节点
                    nodeTemp = nodeTemp.lchild; // 每遇到非空二叉树先向左走
                } else { // 再向右子树走
                    nodeTemp = nodeStack.pop();
                    nodeTemp = nodeTemp.rchild;
                }
            }
        }
    
        // 递归实现中序遍历 LNR
        public void inOrder(TreeNode<E> node) {
            if (node != null) {
                inOrder(node.lchild);
                System.out.print(node.data + " ");
                inOrder(node.rchild);
            }
        }
    
        // 非递归实现中序遍历 LNR
        public void nonRecInOrder(TreeNode<E> node) {
            Stack<TreeNode<E>> nodeStack = new Stack<TreeNode<E>>();
            TreeNode<E> nodeTemp = node; // nodeTemp作为遍历指针
            while (nodeTemp != null || !nodeStack.isEmpty()) { // 当nodeTemp非空或栈非空时循环
                if (nodeTemp != null) { // 根指针非空,遍历左子树
                    nodeStack.push(nodeTemp); // 根指针进栈
                    nodeTemp = nodeTemp.lchild; // 每遇到非空二叉树先向左走
                } else {
                    nodeTemp = nodeStack.pop(); // 根指针退栈,访问根节点
                    System.out.print(nodeTemp.data + " ");
                    nodeTemp = nodeTemp.rchild; // 再向右子树走
                }
            }
        }
    
        // 递归实现后序遍历 LNR
        public void postOrder(TreeNode<E> node) {
            if (node != null) {
                postOrder(node.lchild);
                postOrder(node.rchild);
                System.out.print(node.data + " ");
            }
        }
    
        // 非递归实现后序遍历 LNR
        public void nonRecPostOrder(TreeNode<E> node) {
            Stack<TreeNode<E>> nodeStack = new Stack<TreeNode<E>>();
            TreeNode<E> nodeTemp = node; // nodeTemp作为遍历指针
            TreeNode<E> preNode = null; // 表示最近一次访问的节点
            while (nodeTemp != null || !nodeStack.isEmpty()) { // 当nodeTemp非空或栈非空时循环
                while (nodeTemp != null) { // 一直向左走,遍历左子树
                    nodeStack.push(nodeTemp);
                    nodeTemp = nodeTemp.lchild;
                }
                nodeTemp = nodeStack.peek();
                if (nodeTemp.rchild == null || nodeTemp.rchild == preNode) { // 右子树为空或右子树已被访问时,该节点出栈
                    nodeTemp = nodeStack.pop();
                    System.out.print(nodeTemp.data + " ");
                    preNode = nodeTemp; // 将该节点赋值给最近一个访问节点
                    nodeTemp = null; // 此处很重要,将刚出栈节点设置为空,对应于while循环的条件之一,否则陷入死循环
                } else {
                    nodeTemp = nodeTemp.rchild; // 遍历右子树
                }
            }
        }
    
        // 层次遍历
        public void levelOrder(TreeNode<E> root) {
            Queue<TreeNode<E>> nodeQueue = new LinkedList<TreeNode<E>>();
            TreeNode<E> node = null;
            nodeQueue.add(root); // 将根节点入队
            while (!nodeQueue.isEmpty()) { // 队列不空循环
                node = nodeQueue.peek();
                System.out.print(node.data + " ");
                nodeQueue.poll(); // 队头元素出队
                if (node.lchild != null) { // 左子树不空,则左子树入队列
                    nodeQueue.add(node.lchild);
                }
                if (node.rchild != null) { // 右子树不空,则右子树入队列
                    nodeQueue.add(node.rchild);
                }
            }
        }
    
        public static void main(String args[]) {
            // 将一个数组转化为一颗完全二叉树
            Object[] array = { 1, 2, 3, 4, 5, 6, 7, 8 };
            BinaryTree bt = new BinaryTree();
            TreeNode root = bt.buildTree(array);
            System.out.print("树的高度:");
            System.out.println(bt.height(root));
            System.out.print("节点的个数:");
            System.out.println(bt.size(root));
            System.out.println("先序遍历:");
            bt.preOrder(root);
            System.out.println("
    " + "非递归先序遍历:");
            bt.nonRecPreOrder(root);
            System.out.println();
    
            System.out.println("中序遍历:");
            bt.inOrder(root);
            System.out.println("
    " + "非递归中序遍历:");
            bt.nonRecInOrder(root);
            System.out.println();
    
            System.out.println("后序遍历:");
            bt.postOrder(root);
            System.out.println("
    " + "非递归后序遍历:");
            bt.nonRecPostOrder(root);
            System.out.println();
    
            System.out.println("层次遍历:");
            bt.levelOrder(root);
    
            // 手工构建一颗二叉树
            TreeNode nodeA = new TreeNode("A");
            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");
            TreeNode nodeG = new TreeNode("G");
            TreeNode nodeH = new TreeNode("H");
            TreeNode nodeI = new TreeNode("I");
            nodeA.lchild = nodeB;
            nodeA.rchild = nodeD;
            nodeB.rchild = nodeC;
            nodeD.lchild = nodeE;
            nodeD.rchild = nodeF;
            nodeF.lchild = nodeG;
            nodeF.rchild = nodeI;
            nodeG.rchild = nodeH;
    
            System.out.println("
    
    " + "*****************");
            System.out.print("树的高度:");
            System.out.println(bt.height(nodeA));
            System.out.print("节点的个数:");
            System.out.println(bt.size(nodeA));
            System.out.println("先序遍历:");
            bt.preOrder(nodeA);
            System.out.println();
    
            System.out.println("中序遍历:");
            bt.inOrder(nodeA);
            System.out.println();
    
            System.out.println("后序遍历:");
            bt.postOrder(nodeA);
            System.out.println();
    
            System.out.println("层次遍历:");
            bt.levelOrder(nodeA);
        }
    
    }

    结果

  • 相关阅读:
    stm32自带的flash分布图
    leetcode21
    使用redis缓存数据需要注意的问题以及个人的一些思考和理解
    Chapter 2 Open Book——2
    spring管理事务需要注意的
    如何避免在简单业务逻辑上面的细节上面出错
    leetcode387
    黑天鹅-简记
    java方法中只有值传递,没有引用传递
    Chapter 2 Open Book——1
  • 原文地址:https://www.cnblogs.com/xdyixia/p/9192452.html
Copyright © 2020-2023  润新知