普通树与二叉树

树作为一种常用的数据结构,不可不知。树采用的是链式存储,在详细介绍树之前要先了解几个基本概念:

根、节点、孩子、双亲、兄弟、分支 就不多BB了,叶子指的是没有子节点的节点,树的高度指从根到树所有叶子节点的最大长度,节点的度为其子节点的数量,节点的深度为节点到根的路径长度。

二叉树

二叉表示至多两向选择,在许多场景下都有应用。二叉树的种类实在太多,今天先宽泛地说一下几种二叉树。

严格二叉树

严格二叉树是这样的二叉树,它的每个节点或者没有孩子或者有两个孩子,即没有一个孩子的节点。

满二叉树

满二叉树要求每一层的节点数量都达到最大。

完全二叉树

在一棵完全二叉树中,除最后一层之外,每一层都有在这一层上可能的最大节点数量。最后一层的节点数量可以小于最大可能数量,但是它们必须是从左到右一个一个挨着排列的。

(实在太简单,就不上图了)

二叉树的遍历与署名

二叉树的遍历

可以大致分为前序遍历、中序遍历、后序遍历与层级遍历,前三种的区别只在于访问根节点相对左右子节点的访问顺序,层级遍历则是按照层级,一层一层逐级遍历节点。很明显,前中后序三中遍历用递归实现非常简单,有兴趣用循环实现的同学可以参考我另一篇博客递归转循环的通法。不好意思,盗个图先,嘻嘻。

二叉树的署名

数据结构的署名是这一结构及其内容的纯文本形式的编码,这一署名可以离线存储,并在需要时在内存中重构该数据结构。(说白了,持久化存储)

既然要持久化二叉树,那么其存储结构必须要唯一标识二叉树,不能产生歧义,否则存储的结构无意义。层级遍历结果首先否定,因为其完全无法提供节点层级与节点的父子关系。再来看三序遍历,单单一种遍历同样无法区分,那么两种遍历结合到一起呢?

假设所有节点存储的数据内容不同,在此前提下,前后序遍历无法唯一标识,因为无法提供节点之间的父子关系。而前中与中后则可以,有兴趣的同学可以思考一下,不深入讨论了。

这里给出鄙人实现的二叉树JAVA代码,请轻拍。

package com.structures.tree;

/**
 * Created by wx on 2017/11/2.
 * BinaryTree Node class.
 */
public class BinaryTree<T> {
    private T data;
    public BinaryTree<T> left;
    public BinaryTree<T> right;
    public BinaryTree<T> parent;

    // 子类无法继承父类的构造方法,需要的话,就显示调用;T申明过了,除了static不用再申明
    public BinaryTree(){
        T data = null;
        BinaryTree<T> left = null;
        BinaryTree<T> right = null;
        BinaryTree<T> parent = null;
    }

    // 初始节点值
    public void makeRoot(T data){
        if(this.data!=null)
            throw new TreeViolationException("The tree is not null!");
        else
            this.data = data;
    }

    //设定节点值
    public void setData(T data){
        this.data = data;
    }

    public T getData(){
        return data;
    }

    // 返回整棵树的根
    public BinaryTree<T> root(){
        BinaryTree<T> myRoot = this;
        while(myRoot.parent!=null){
            myRoot = myRoot.parent;
        }
        return myRoot;
    }

    //设定左子树
    public void attachLeft(BinaryTree<T> tree){
        if(left!=null)
            throw new TreeViolationException("Left sub tree already exists!");
        left = tree;
        tree.parent = this;
    }

    //设定右子树
    public void attachRight(BinaryTree<T> tree){
        if(right!=null)
            throw new TreeViolationException("Right sub tree already exists!");
        right = tree;
        tree.parent = this;
    }

    //删除左子树并返回之
    public BinaryTree<T> detachLeft(){
        BinaryTree<T> subTree = left;
        subTree.parent = null;
        left = null;

        return subTree;
    }

    //删除右子树并返回之
    public BinaryTree<T> detachRight(){
        BinaryTree<T> subTree = right;
        subTree.parent = null;
        right = null;

        return subTree;
    }

    //返回是否为空树
    public boolean isEmpty(){
        return (data==null && left==null && right==null);
    }

    //清空二叉树,并使之与双亲节点断开
    public void clear(){
        if(parent!=null){
            if(parent.left==this)
                parent.left = null;
            else
                parent.right = null;
        }
        parent = left = right = null;
        data = null;
    }
}

class TreeViolationException extends RuntimeException{
    TreeViolationException(String info){
        super(info);
    }
}

普通树

普通树主要是以层次的形式组织起来的,最常见的就是Unix操作系统的文件组成层次,生活中又如企业的管理层级。话不多说,上图。

树的理解和构建都很简单,但是相对二叉树又有很多一些问题。

问题一:存储空间问题

普通树的节点的孩子数量是不确定的,那么直接构建足够引用孩子节点空间的节点是行不通的。在不知道一个节点有多少个孩子的情况下,我们对节点要进行过高评估并分配一个最大空间,这会带来严重的空间浪费。假设节点的孩子最多k个,这棵树有n个节点,这个时候浪费的空间比例为:w = (nk-(n-1)) / (nk) ≈ 1- 1/k 。k=5时,几乎有80%的浪费!

问题二:普通树的署名

二叉树可以通过前中或者中后序遍历署名,那么普通树呢? 首先普通树就不存在所谓的中序遍历,而前后序结合又不能唯一标识一棵普通树。然后,尴尬了!

怎么解决?

普通树实际上是以二叉树的形式存储,这样的话,上面两个问题就迎刃而解了。其与之对应的二叉树之间的转化关系为:

  1. 对于普通树的节点A,A的第一个孩子变为二叉树中A的左孩子
  2. A的右兄弟变为二叉树中A的右孩子,以此类推

以图中树为实例,不妨写一下其遍历结果。

原来树的遍历:

  • 前序遍历:ABCEFDXG
  • 后序遍历:BEFCDGXA

转换后二叉树的遍历:

  • 前序遍历:ABCEFDXG
  • 中序遍历:FEGXDCBA
  • 后序遍历:BEFCDGXA

呦,怎么普通树的前序遍历和后序遍历分别与等价二叉树的前序遍历和中序遍历结果相同啊?!

仔细分析一下,等价二叉树节点left 对应 原来子节点, 等价二叉树节点right 对应原来的 右兄弟, 等价二叉树的中序遍历的遍历顺序与原来的前序相同!

同理 等价二叉树的中序遍历 与 原来的后续遍历的遍历顺序相同。追根究底,就是这样对应转换,没有改变遍历节点的顺序规则。

普通树与等价二叉树一一对应,同时使用二叉树的署名也唯一标识了普通树,问题二解决!

时间: 2024-08-04 17:46:11

普通树与二叉树的相关文章

树、二叉树、森林的转换

树转换为二叉树 (1)加线.在所有兄弟结点之间加一条连线. (2)去线.树中的每个结点,只保留它与第一个孩子结点的连线,删除它与其它孩子结点之间的连线. (3)层次调整.以树的根节点为轴心,将整棵树顺时针旋转一定角度,使之结构层次分明.(注意第一个孩子是结点的左孩子,兄弟转换过来的孩子是结点的右孩子) 森林转换为二叉树 (1)把每棵树转换为二叉树. (2)第一棵二叉树不动,从第二棵二叉树开始,依次把后一棵二叉树的根结点作为前一棵二叉树的根结点的右孩子,用线连接起来. 二叉树转换为树 是树转换为二

树、二叉树、遍历二叉树的总结

首先介绍树: 如上图所示就是一棵树,先介绍树的几个关键名词: 节点:A.B.C.D等都叫节点 节点的度:节点有几个分支,就叫节点的度,比如节点B有2个分支,那B的度为2 终端节点(叶子):没有分支的节点,如E.F.G.H 非终端节点:有分支的节点,如A.B.D.C 节点的层次:自上而下排列层次,A为1层,B为2层,D为3层 树的度:哪个节点的度最大,这个最大的度就是树的度,如图树的度为2 树的深度:简而言之,就是树有几层,如图的树的深度为4 我们接触最多的树是二叉树 二叉树:在计算机科学中,二叉

树和二叉树

以下的内容做为学习笔记,复制别人的,感觉总结的比较好: 第5章 树和二叉树 本章中主要介绍下列内容:  1.树的定义和存储结构  2.二叉树的定义.性质.存储结构  3.二叉树的遍历.线索算法  4.树和二叉树的转换  5.哈夫曼树及其应用课时分配:     1.2两个学时,3四个学时,4两个学时, 5两个学时,上机两个学时重点.难点:     二叉树的遍历.线索算法.哈夫曼树及其应用 第一节 树 1.树的定义和基本运算1.1 定义    树是一种常用的非线性结构.我们可以这样定义:树是n(n≥

数据结构学习笔记(树、二叉树)

树(一对多的数据结构) 树(Tree)是n(n>=0)个结点的有限集.n=0时称为空树.在任意一颗非空树种: (1)有且仅有一个特定的称为根(Root)的结点: (2)当n>1时,其余结点可分为m(m>0)个互不相交的有限集T1.T2........Tn,其中每一个集合本身又是一棵树,并且称为根的子树. 对于树的定义还需要强调两点:1.n>0时根结点是唯一的,不可能存在多个根结点,数据结构中的树只能有一个根结点.2.m>0时,子树的个数没有限制,但它们一定是互不相交的. 结点

6-5-树的双亲表示法-树和二叉树-第6章-《数据结构》课本源码-严蔚敏吴伟民版

课本源码部分 第6章  树和二叉树 - 树的双亲表示法 ——<数据结构>-严蔚敏.吴伟民版        源码使用说明  链接??? <数据结构-C语言版>(严蔚敏,吴伟民版)课本源码+习题集解析使用说明        课本源码合辑  链接??? <数据结构>课本源码合辑        习题集全解析  链接??? <数据结构题集>习题解析合辑        本源码引入的文件  链接? Status.h.Scanf.c.SequenceStack.c    

树和二叉树-第6章-《数据结构题集》习题解析-严蔚敏吴伟民版

习题集解析部分 第6章 树和二叉树 ——<数据结构题集>-严蔚敏.吴伟民版        源码使用说明  链接??? <数据结构-C语言版>(严蔚敏,吴伟民版)课本源码+习题集解析使用说明        课本源码合辑  链接??? <数据结构>课本源码合辑        习题集全解析  链接??? <数据结构题集>习题解析合辑       相关测试数据下载  链接? 数据包       本习题文档的存放目录:数据结构\▼配套习题解析\▼06 树和二叉树  

基本数据结构学习笔记——树与二叉树

1.树的形式化定义: 树(Tree)是由一个或多个结点组成的有限集合T,其中有一个特定的称为根的结点:其余结点可分为m(m≥0)个互不相交的有限集T1,T2,T3 ,…,Tm,每一个集合本身又是一棵树,且称为根的子树. 2.有关树的基本术语: 1.结点(Node):树中的元素,包含数据项及若干指向其子树的分支. 2.结点的度(Degree):结点拥有的子树数. 3.结点的层次:从根结点开始算起,根为第一层. 4.叶子(Leaf):度为零的结点,也称端结点. 5.孩子(Child):结点子树的根称

树、二叉树基础

刚看到堆排序,顺便记录一下关于树的一些基本概念: 前言 前面介绍的栈.队列都是线性结构(linear structure).而树是非线性结构(non-linear structure).因此,树中的元素之间一般不存在类似于线性结构的一对一的关系,更多地表现为多对多的关系.直观地看,它是数据元素(在树中称为节点)按分支关系组织起来的结构.显然,树形结构是比线性结构更复杂的一种数据结构类型. 一.树 树的定义:树是含有n个节点的有穷集合,其中有一个节点比较特殊称为根节点.在图示树时,用一条边连接两个

数据结构与算法系列研究五——树、二叉树、三叉树、平衡排序二叉树AVL

树.二叉树.三叉树.平衡排序二叉树AVL 一.树的定义 树是计算机算法最重要的非线性结构.树中每个数据元素至多有一个直接前驱,但可以有多个直接后继.树是一种以分支关系定义的层次结构.    a.树是n(≥0)结点组成的有限集合.{N.沃恩}     (树是n(n≥1)个结点组成的有限集合.{D.E.Knuth})      在任意一棵非空树中:        ⑴有且仅有一个没有前驱的结点----根(root).        ⑵当n>1时,其余结点有且仅有一个直接前驱.         ⑶所有结

第五章 树和二叉树

上章回顾 单链表的基本操作,包括插入.删除以及查找 双向链表和循环链表的区别 [email protected]:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git 第五章 第五章 树和二叉树 树和二叉树 [email protected]:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git 预习检查 什么是二叉树 树的遍历有哪几种方式 树有哪些应用 [email pr