树与二叉树1.0

来源:互联网 发布:北京小学教师工资 知乎 编辑:程序博客网 时间:2024/06/06 10:19

  • 树是一种重要的非线性数据结构,直观地看,它是数据元素(在树中称为结点)按分支关系组织起来的结构,很象自然界中的树那样。树结构在客观世界中广泛存在,如人类社会的族谱和各种社会组织机构都可用树形象表示。树在计算机领域中也得到广泛应用,如在编译源程序如下时,可用树表示源源程序如下的语法结构。又如在数据库系统中,树型结构也是信息的重要组织形式之一。一切具有层次关系的问题都可用树来描述。满二叉树,完全二叉树,排序二叉树。
  • 树由一个或多个结点组成,非空数一般都有一个特定的结点做为根(root)以根做为基础向下延伸,进而引出双亲、子女、兄弟、祖先。

树所具有的属性

  1. 树的度——也即是宽度,简单地说,就是结点的分支数。以组成该树各结点中最大的度作为该树的度,树中度为零的结点称为叶结点或终端结点。树中度不为零的结点称为分枝结点或非终端结点。除根结点外的分枝结点统称为内部结点
  2. 树的深度——组成该树各结点的最大层次。
  3. 森林——指若干棵互不相交的树的集合.
  4. 有序树——指树中同层结点从左到右有次序排列,它们之间的次序不能互换,这样的树称为有序树,否则称为无序树。

树的存储结构

  • 无论采用哪种存储方法,都要求存储结构不但能存储各结点的数据信息,还要能唯一的反映个结点的逻辑关系—–父子关系。
  • 此处空缺若之后应用到之类的存储结构会进行补全,本文主要对二叉树的线性存储进行浅析,希望可以给给初学者一些帮助。

  • 二叉树

  • 二叉树是一种特殊的树,即结点的分支数最大为二。
  • 二叉树具有所有树的属性。
  • 二叉树的遍历方法大致有四种,前序遍历、中序遍历、后序遍历、层序遍历。(具体方法将在代码中讲到)
    1. 前序遍历:先访问根;按照从左到右的顺序前序遍历根结点的每一颗子树。
    2. 中序遍历:按照左中右的顺序,先访问左子树,再访问根,最后访问右子树。
    3. 后序遍历:按照左右中的顺序,先访问左子树,再访问右子树,最后访问根结点。
    4. 层序遍历:按照层级从左到右访问,下图为:abcdfeg。

    这里写图片描述

  • 满二叉树与完全二叉树
    233
    满二叉树:除最后一层无任何子节点外,每一层上的所有结点都有两个子结点的二叉树。
    完全二叉树:若设二叉树的深度为h,除第 h 层外,其它各层 (1~h-1) 的结点数都达到最大个数,第 h 层所有的结点都连续集中在最左边,这就是完全二叉树。

  • 这里对树与二叉树的基本概念不再多说,想必书中要全面的多,所以在这里不再赘述,直接上代码解析:

    **二叉树代码解析**

  • Three.h文件
  • #pragma oncetemplate<class Type>/*模板类*/struct BiNode/*用结构体定义结点*/{    Type data;/*存储数据*/    BiNode<Type> *lchild, *rchild;/*定义BiNode<Type>类型来存数双亲结点的左孩子、右孩子*/};template<class Type>class BiTree/*二叉树*/{public:    BiTree() {        root = Creat(root);/*在构造函数中直接调用Creat来构造二叉树*/    }    ~BiTree() { Clear(root);  mynode = 0; };/*析构函数中清空二叉树,释放内存*/    //以下函数的声明均为避免在主程序中访问到私有变量root    void PreOrder() { PreOrder(root); }//前序遍历    void InOrder() { InOrder(root); }//中序遍历    void PostOrder() { PostOrder(root); }//后序遍历    void LeverOrder();//层序遍历    void Mynode() { cout << mynode << endl; }/*输出结点个数*/    void FindDeep() { cout << FindDeep(root) << endl; }/*二叉树查询深度函数*/    BiNode<Type> *GetRoot() { return root; }/*得到根节点函数*/private:    BiNode<Type> *root;/*定义根节点*/    int mynode;/*二叉树结点个数*/    BiNode<Type> *Creat(BiNode<Type> *bt);    void Clear(BiNode<Type> *bt);    void PostOrder(BiNode<Type> *bt);    void PreOrder(BiNode<Type> *bt);    void InOrder(BiNode<Type> *bt);    int FindDeep(BiNode<Type> *bt);};/*--------------以下算法均为递归算法----------*/template<class Type>void BiTree<Type>::PreOrder(BiNode<Type> *bt)/*bt传参实际等于root*/{    if (bt == NULL)return;/*递归出口~若结点为空则跳出*/    else    {    /*    先访问根;按照从左到右的顺序前序遍历根结点的每一颗子树。    对于递归算法,我们只需考虑其中一步即可。(可以参考最简单的二叉树a##)    */        cout << bt->data;/*打印根节点*/        PreOrder(bt->lchild);/*递归遍历左孩子*/        PreOrder(bt->rchild);/*递归遍历右孩子*/    }}template<class Type>inline void BiTree<Type>::InOrder(BiNode<Type>* bt){    if (bt == NULL)return;    else    {        InOrder(bt->lchild);/*递归遍历左孩子*/        cout << bt->data;/*打印根结点*/        InOrder(bt->rchild);/*递归遍历右孩子*/    }//这里注意打印的顺序,其他去前序遍历没有区别。}/*------寻找深度的递归算法----*/template<class Type>inline int BiTree<Type>::FindDeep(BiNode<Type>* bt){    int deep = 0;    if (bt) {        int lchilddeep = FindDeep(bt->lchild);        int rchilddeep = FindDeep(bt->rchild);        deep = lchilddeep >= rchilddeep ? lchilddeep + 1 : rchilddeep + 1;/*这里是deep计算的关键(具体运行原理会在后续的递归章节中给出)*/    }    return deep;}template<class Type>/*后序*/inline void BiTree<Type>::PostOrder(BiNode<Type>* bt){    if (bt == NULL)return;    else    {        PostOrder(bt->lchild);        PostOrder(bt->rchild);        cout << bt->data;/*注意打印顺序*/    }}/*层序遍历:层序遍历算法较为特殊,我们无法用递归方式直接打印,此处借助队列对树的结点进行暂时的存储并在合适的位置进行出队打印操作*/template<class Type>inline void BiTree<Type>::LeverOrder(){    Queue<Type> s;/*存储数结点的队列*/    BiNode<Type> *bt;    s.Push(root);/*将根结点入队*/    while (!s.IsEmpty()/*队列非空*/)    {        bt = s.Pop();/*出队并将对头值付给bt*/        cout << bt->data << " ";        if (bt->lchild != NULL)            s.Push(bt->lchild);        if (bt->rchild != NULL)            s.Push(bt->rchild);    }}template<class Type>inline BiNode<Type>* BiTree<Type>::Creat(BiNode<Type>* bt){    Type ch;    cin >> ch;    if (ch == '#')bt = NULL;    else    {        bt = new BiNode<Type>;        bt->data = ch; mynode++;        bt->lchild = Creat(bt->lchild);        bt->rchild = Creat(bt->rchild);    }    /*此处创建队列方式与前序遍历方式类似所以在输入的时候要以前序遍历规则输入;上蓝图的前序遍历为abdefgc;则输入为:abd#e##fg###c## 非空结点的空左右孩子要用#代替*/    return bt;/*出口*/}template<class Type>inline void BiTree<Type>::Clear(BiNode<Type>* bt){    if (bt != NULL)    {        Clear(bt->lchild);        Clear(bt->rchild);        delete bt;    }    /*递归清理*/}/*-----------------------------------------树节点队列存储----------------------------------------------*//*队列在队列章节会详细说明,在这里特别的是对列结点存储的是树节点的指针需要注意返回值和删除的情况*/template<class Type>struct QNode{    BiNode<Type> *Element;/*树节点*/    QNode<Type> *next;};template<class Type>class Queue{public:    Queue();    ~Queue();    BiNode<Type>* Pop();    void Push(BiNode<Type> *x);    void Clear();    bool IsEmpty();private:    QNode<Type> *head, *end;};template<class Type>inline Queue<Type>::Queue(){    head = new QNode<Type>;    //head->Element = new BiNode<Type>;    head->next = NULL;    end = head;}template<class Type>inline Queue<Type>::~Queue(){}template<class Type>inline BiNode<Type>* Queue<Type>::Pop(){    QNode<Type> *p;    if (IsEmpty())    {        exit(0);    }    p = head->next;    head->next = p->next;    if (head->next==NULL)    {        end = head;    }    return p->Element;    /*出队时无需delete p */}template<class Type>inline void Queue<Type>::Push(BiNode<Type>* x){    QNode<Type> *p;    p = new QNode<Type>;    p->Element = x;    p->next = end->next;    end->next = p;    end = p;}template<class Type>inline void Queue<Type>::Clear(){}template<class Type>inline bool Queue<Type>::IsEmpty(){    if (head->next == NULL)        return true;    else        return false;}

  • main.cpp文件
  • #include <iostream>#include "Tree.h"using namespace std;int main(){    BiTree<char> s;    //s.Mynode();    s.FindDeep();    return 0;}//注意双等号判断

    上文若有不太正确的地方希望大家指出我会及时改正,大家互相学习~~

    ——–墨子须眉参上。

    2 0
    原创粉丝点击