美文网首页
树及二叉树

树及二叉树

作者: VictorBXv | 来源:发表于2018-02-07 00:26 被阅读0次

    一、基本概念

    1. 节点的度 :节点拥有的子树数成为节点的度。

      • 叶子节点:度为0的节点称为叶子节点;
      • 分支节点:度不为0的节点称为分支节点;
      • 树的度:树内各节点的度的最大值;


        度的图解
    2. 树的层次与深度:树中节点的最大层次称为树的深度(高度)


      树的层次与深度

      注意:根节点为第一层;

    二、树的存储

    存储方式(存储思想):利用顺序存储链式存储共同来实现树的存储;

    (一)双亲表示法

    1. 定义:在每个节点中,附设一个指示器指示其双亲节点在链表中的位置(即孩子节点指向父节点);(开发中常用做法)
      • 优点:从孩子找父节点容易;
      • 缺点:从父节点找孩子难;
    2. 节点的数据模型
    模型图解
    • 举例:

      存储方式图解

    (二)孩子表示法

    1. 特点:用父节点表示自己
      • 优点:找每个节点的孩子容易;
      • 缺点:
        1. 找到每个节点的父节点难;
        2. 存在数据冗余,内存浪费;
        3. 数组扩容难;
    2. 举例
      方案一:创建固定长度的数组,使得每个节点都有若干个指针指向自己的每一个孩子
      [图片上传失败...(image-21a424-1517935019947)]
      方案二:先用一个标记记录每个节点有几个孩子,然后根据这个标记创建数组,减少数据冗余;
      [图片上传失败...(image-2dec98-1517935019947)]

    (三)孩子双亲表示法

    1. 做法:把每个节点的孩子节点排列起来,以单链表作为存储结构,则n个节点有n个孩子链表,如果是叶子节点则此单链表为空,然后n个头指针又组成一个线性表,采用顺序存储结构,存放在一个一维数组中;


      孩子兄弟表示法


    二叉树

    一、概念

    1. 完全二叉树:对一棵有n个节点的二叉树按层序编号,如果编号为i(1<=i<=n)的节点与同样深度的满二叉树中编号为i的节点在二叉树中位置完全相同,则这棵二叉树称为完全二叉树;
    完全二叉树举例

    二、二叉树的链式存储方式

    二叉树的链式存储方式

    三、二叉树的遍历

    一、前序遍历

    1. 步骤

      1. 如果二叉树为空,则空操作返回
      2. 否则先访问跟节点
      3. 然后前序遍历左子树
      4. 再前序遍历右子树
    2. 代码实现

       public void preOrderTraverse(Tree tree){
           if(tree == null){
               return;
           }
           System.out.println(tree.data);
           preOrderTraverse(tree.leftChild);
           preOrderTraverse(tree.rightChild);
       }
      

    二、中序遍历

    1. 步骤

      1. 如果二叉树为空,则返回空操作;
      2. 否则前序遍历左子树
      3. 然后访问跟节点
      4. 再中序遍历右子树
    2. 代码实现

       public void midOrderTraverse(Tree tree){
             if(tree==null){
                  return;
             }
             midOrderTraverse(tree.leftChild);
             System.out.println(tree.data);
             midOrderTraverse(tree.rightChild);
       }
      

    三、后序遍历

    1. 步骤

      1. 如果二叉树为空,则返回空操作;
      2. 否则后序遍历左子树
      3. 然后后序遍历右子树
      4. 再遍历根节点
    2. 代码实现

       public void proOrderTraverse(Tree tree){
           if(tree==null){
               return;
           }
           proOderTraverse(tree.leftChild);
           proOderTraverse(tree.rightChild);
           System.out.println(tree.data);
       }
      

    四、二叉树的创建以及遍历

    public class BinaryTree<T> {
    
        private TreeNode root;//根节点,这个节点是一定存在的,而且对二叉树的操作就是从这里开始的
    
        public TreeNode getRoot() {
            return root;
        }
    
        /**
         * @param t 根节点的初始值
         */
        public BinaryTree(T t) {
            root = new TreeNode(1, t);
        }
    
        /**
         * 通过二叉树的前序序列集合创建二叉树
         * @param list 集合必须是二叉树对应的完全二叉树序列,没有节点的地方用<code>#</code>代替
         *             算法思想:每次从list中取出一个元素来构建二叉树,同时从集合中移除这个元素,如果list的长度为0,表示构建完成
         *             如果遇到<code>#</code>,就不输出,然后递归调用这个方法,得到二叉树序列
         * @return
         */
        public TreeNode createBinaryTree(int size, List<T> list) {
            if (list == null) {
                return null;
            } else if (list.size() == 0) {
                return null;
            } else {
                //构建节点的准备工作,数据域和角标index
                T t = list.get(0);
                TreeNode node = null;
                int index = size - list.size();
                if (t.equals("#")) {
                    //如果是#,说明这里就没有节点,就不用构建,但是要把这个元素从list中移除
                    node = null;
                    list.remove(t);
                    return node;
                }
                //如果代码走到这里,就表示有数据,需要构造节点
                node = new TreeNode(index, t);
                //此外一定要把二叉树的根节点赋值,否则整棵二叉树就没有和root关联起来,会报npe
                if (index == 0) {
                    root = node;
                }
                list.remove(t);
                //以上构造完一个节点,接下来构造该节点的左右子树,
                //因为输入的是前序遍历的二叉树集合,所以要先构建左子树,然后是右子树
                //由递归的特点可知,这里一定是先构造完左子树,然后再构造右子树
                node.leftChild = createBinaryTree(size, list);
    
                node.rightChild = createBinaryTree(size, list);
                return node;
            }
        }
    
        /**
         * 这里有两种实现思路:
         * <li>
         * 有个成员变量<code>size</code>,每次添加一个节点size++,这样就得到了节点的个数
         * </li>
         * 思路二:通过遍历二叉树来计算节点个数
         * @return 二叉树中节点的个数
         */
        public int size() {
            return getSize(root);
        }
    
        /**
         * 获取任意节点的子节点个数
         * note:在二叉树中,递归(迭代)是很重要的思想
         * @param node 指定的节点
         * @return
         */
        public int getSize(TreeNode node) {
            return 1 + getSize(node.leftChild) + getSize(node.rightChild);
        }
    
        /**
         * 对指定的节点前序遍历
         * @param node
         */
        public void preOrderTraverse(TreeNode node) {
            if (node == null) {
                return;
            } else {
                System.out.print(node.getData() + "  ");
                preOrderTraverse(node.leftChild);
                preOrderTraverse(node.rightChild);
            }
        }
    
        /**
         * 中序遍历指定二叉树节点
         * @param node
         */
        public void midOrderTraverse(TreeNode node) {
            if (node == null) {
                return;
            } else {
                midOrderTraverse(node.getLeftChild());
                System.out.print(node.getData() + "  ");
                midOrderTraverse(node.getRightChild());
            }
        }
    
        /**
         * 对指定二叉树结点后序遍历
         * @param node
         */
        public void proOrderTraverse(TreeNode node) {
            if (node == null) {
                return;
            } else {
                proOrderTraverse(node.getLeftChild());
                proOrderTraverse(node.getRightChild());
                System.out.print(node.getData() + "  ");
            }
        }
    
        private static final class TreeNode<T> {
            private int index;//每个节点的标记,根节点默认是1
            private T data;
            private TreeNode leftChild;
            private TreeNode rightChild;
            private TreeNode parent;//父节点,这样我们就可以找到每个节点的孩子节点和父节点了
    
            /**
             * 构造方法,因为在创建节点时候并不知道左右孩子以及父节点信息,
             * 所以在构造方法里面无法通过构造方法对这些节点信息赋值,只能在创建对象后进行赋值
             * @param index 节点在整个二叉树中的标记,
             * @param data
             */
            public TreeNode(int index, T data) {
                this.index = index;
                this.data = data;
                this.leftChild = null;
                this.rightChild = null;
                this.parent = null;
            }
    
            public int getIndex() {
                return index;
            }
    
            public void setIndex(int index) {
                this.index = index;
            }
    
            public T getData() {
                return data;
            }
    
            public void setData(T data) {
                this.data = data;
            }
    
            public TreeNode getLeftChild() {
                return leftChild;
            }
    
            public void setLeftChild(TreeNode leftChild) {
                this.leftChild = leftChild;
            }
    
            public TreeNode getRightChild() {
                return rightChild;
            }
    
            public void setRightChild(TreeNode rightChild) {
                this.rightChild = rightChild;
            }
    
            public TreeNode getParent() {
                return parent;
            }
    
            public void setParent(TreeNode parent) {
                this.parent = parent;
            }
        }
    }

    相关文章

      网友评论

          本文标题:树及二叉树

          本文链接:https://www.haomeiwen.com/subject/lbonzxtx.html