数据结构--树和二叉树

数据结构

–树和二叉树

一.一些概念
  1. 树的定义
    树是有n(n≥0)个结点的有限集合。
    如果n=0,称为空树;
    如果n>0,称为非空树,对于非空树,有且仅有一个特定的称为根(Root)的节点(无直接前驱);
    如果n>1,则除根以外的其它结点划分为 m (m>0)个互不相交的有限集 T1, T2 ,…, Tm,其中每个集合本身又是一棵树,并且称为根的子树(SubTree)。
    每个结点都有唯一的直接前驱,但可能有多个后继.(一对多)
  2. 结点:包含一个数据元素及若干指向其子树的分支.(A结点)
  3. 结点的度:结点拥有的子树数.(A结点的度为3)
  4. 叶结点:度为0的结点[没有子树的结点].(K结点)
  5. 分支结点:度不为0的结点[包括根结点],也称为非终端结点。除根外称为内部结点.
  6. 孩子:结点的子树的根[直接后继,可能有多个].(A的孩子为BCD)
  7. 双亲:孩子的直接前驱[最多只能有一个].(B的双亲为A)
  8. 兄弟:同一双亲的孩子.(B的兄弟为CD)
  9. 子孙:以某结点为根的树中的所有结点.(B的子孙为EFKL)
  10. 祖先:从根到该结点所经分支上的所有结点.(C的祖先为BA)
  11. 层次:根结点为第一层,其孩子为第二层,依此类推.(B的层次为2)
  12. 深度:树中结点的最大层次.(该树的深度为4)
  13. 有序树:子树之间存在确定的次序关系.
  14. 无序树:子树之间不存在确定的次序关系.
  15. 森林:互不相交的树的集合。对树中每个结点而言,其子树的集合即为森林。
    任何一棵非空树是一个二元组
    Tree = (root,F)
    其中:root 被称为根结点, F被称为子树森林
二.二叉树(Binary Tree)

二叉树是一种特殊的树,每个结点最多有2棵子树,其子树有左右之分。

  1. 在二叉树的第i层上至多有2i-1个结点.
  2. 深度为k的二叉树至多有2k-1个结点.
  3. 如果二叉树终端结点数为n0,度为2的结点数为n2,则n0=n2+1.
三.满二叉树

一个深度为k且有2k-1个结点的二叉树,每层上的结点数都是最大数,可以自上而下、自左至右连续编号。

四.完全二叉树

当且仅当每一个结点都与深度相同的满二叉树中编号从1到n的结点一一对应的二叉树,其叶子结点只在最大两层上出现,左子树深度与右子树深度相等或大1。(满二叉树可以看作是完全二叉树的特殊状态,完全二叉树是满二叉树“未满”的状态)

  1. 具有n个结点的完全二叉树,其深度为[log2n] +1.
  2. 在完全二叉树中,结点i的双亲为 i/2, 结点i的左孩子LCHILD(i)=2i, 结点i的右孩子RCHILD(i)=2i+1(结点从1开始,从0为(i-1)/2, 2i+1, 2i+2)
五.二叉树的存储结构
  1. 顺序存储结构
    用一组连续的存储单元依次自上而下, 自左至右存储结点空结点用0或#表示,缺点是浪费空间。

    顺序表示为1 2 3 4 0 5 6 7 8 0 0 9 10
#include<iostream>
#define MAX_TREE_SIZE 100
using namespace std;
class BiTree{
private:
    char *Tree;
    int len;
public:
    BiTree(){ Tree = new int[MAX_TREE_SIZE]; len=0; }    //用数组存储即可
    void CreateTree(int *t, int l){ Tree = t; len = l; }
};
  1. 链序存储结构
    采用数据域加上左、右孩子指针。
#include<iostream>
using namespace std;
class BiNode{
    char data;
    BiNode *lchild;
    BiNode *rchild;
public:
    BiNode():lchild(NULL),rchild(NULL){}
    BiNode(char e):data(e), lchild(NULL),rchild(NULL){}
    friend class BiTree;
};
class BiTree{
private:
    BiNode *Root;
    void Create(BiNode *&t){
        char c;
        cin >> c;
        if(c!='0'){
            t = new BiNode(c);
            Create(t->lchild);
            Create(t->rchild);
        }else
            t=NULL;
    }
public:
    BiTree():Root(NULL){}
    void Create(){ Create(Root); }
};
  1. 三叉链表
    采用数据域加上左、右孩子指针及双亲指针。
六.遍历二叉树

树的遍历就是按某种次序访问树中的结点,要求每个结点访问一次且仅访问一次(非线性结构线性化)。

  1. 层次遍历输出(先上后下):队列实现

    遍历结果:ABCDEFG
private:
void LevelOrder(BiNode *t){
    queue<BiNode*> tq;
	BiNode* p = t;
    tq.push(Root);
    while(!tq.empty()){
        p = tq.front();
        tq.pop();
        cout << p->data;
        if(p->lchild)
            tq.push(p->lchild);
        if(p->rchild)
            tq.push(p->rchild);
   }
}
public:
void LevelOrder(){ LevelOrder(Root); }
  1. 先左子树后右子树
    - 先序遍历(DLR)
    若二叉树为空,则返回;否则:1> 访问根结点(D) 2> 先序遍历左子树(L) 3> 先序遍历右子树(R)

    遍历结果:ABDEGCF
class BiTree{
private:
    int *Tree;
    int len;
    void PreOrderTraverse(BiNode *t){
         if (t) {
            cout << t->GetNode() << " ";
            PreOrderTraverse(t->GetLChild());
            PreOrderTraverse(t->GetRChild());
        }
    }
public:
    BiTree();
    void PreOrderTraverse(){ PreOrderTraverse(Root); }
};

          - 中序遍历(LDR)
          若二叉树为空,则返回;否则:1> 中序遍历左子树(L) 2> 访问根结点(D) 3> 中序遍历右子树(R)


遍历结果:DBGEAFC

class BiTree{
private:
    int *Tree;
    int len;
    void MidOrderTraverse(BiNode *t){
        if(t){
            MidOrderTraverse(t->GetLChild());
            cout << t->GetNode();
            MidOrderTraverse(t->GetRChild());
        }
    }
public:
    BiTree();
    void MidOrderTraverse(){ MidOrderTraverse(Root); }
};

          - 后序遍历(LRD)
          若二叉树为空,则返回;否则:1> 后序遍历左子树(L) 2> 后序遍历右子树(R) 3> 访问根结点(D)


遍历结果:DGEBFCA

class BiTree{
private:
    int *Tree;
    int len;
    void PostOrderTraverse(BiNode *t){
        if(t){
            PostOrderTraverse(t->GetLChild());
            PostOrderTraverse(t->GetRChild());
            cout << t->GetNode();
        }
    }
public:
    BiTree();
    void PostOrderTraverse(){ PostOrderTraverse(Root); }
};
  1. 先右子树后左子树
七.先序遍历创建二叉树

遍历结果:AB#C##D##

class BiTree{
private:
    BiNode *Root;
    void Create(BiNode *&t){
        char c;
        cin >> c;
        if(c!='#'){
            t = new BiNode(c);
            Create(t->lchild);
            Create(t->rchild);
        }else
            t=NULL;
    }
public:
    BiTree():Root(NULL){}
    void Create(){ Create(Root); }
};
八.应用
  1. 表达式
    (1)先序遍历得到前缀表达式:波兰式:- x + a b c / d e
    (2)中序遍历得到中缀表达式:(a+b)xc-d/e
    (3)后序遍历得到后缀表达式:逆波兰式:a b + c x d e / -
  2. 根据给出的两个遍历顺序创建二叉树
    例如:给出先序遍历和中序遍历,有:
    先序序列:根 左子树 右子树; 中序序列:左子树 根 右子树
    先序序列:a b c d e f g; 中序序列:c b d a e g f
九.线索二叉树

储存结点先后关系的信息(某个结点在序列中的前驱和后继等信息)。

  1. 方式
    (1)增加新指针:在每个结点中,增加前驱(fwd)和后继指针(bkwd)

    (2)利用空指针:在每个结点中增加两个标记位(LTag和RTag)

LTag=0, lChild域指示结点的左孩子;
LTag=1, lChild域指示结点的前驱结点;
RTag=0, lChild域指示结点的右孩子;
RTag=1, lChild域指示结点的后继结点。

  • 在有n个结点的二叉树中,必定存在n+1个空链域。
  • 因为每个结点有两个链域(左、右孩子指针),因此共有2n个链域。
  • 除根结点外,每个结点都有且仅有一个分支相连,即n-1个链域被使用。
  1. 线索链表:以这种结点结构构成的二叉链表作为二叉树的存储结构。
  2. 线索:指向结点前驱和后继的指针。
  3. 线索二叉树(Threaded Binary Tree):加上线索的二叉树。
  4. 线索化:对二叉树以某种次序遍历使其变为线索二叉树的过程。
  5. 建立线索二叉树:
十.树和森林
  1. 树的存储结构
    (1)双亲表示法
    采用一组连续的存储空间;由于每个结点只有一个双亲,只需要一个指针。

    (2)孩子表示法
    可以采用多重链表,即每个结点有多个指针;最大的缺点是空链域太多(d-1)n+1个。

    (3)孩子兄弟表示法
    采用二叉链表;左指针指向第一个孩子,右指针指向兄弟。
  2. 树与二叉树的对应关系
    树与二叉树都可以采用二叉链表作存储结构。任意给定一棵树,可以找到一个唯一的二叉树(没有右子树)。
  3. 森林与二叉树的对应关系
    如果把森林中的第二棵树的根结点看作是第一棵树的根结点的兄弟,则可找到一个唯一的二叉树与之对应。
  4. 树的遍历
    (1)先根(次序)遍历–二叉树的先序遍历
    当树非空时,访问根结点,再依次先根遍历各棵子树。

    遍历结果:ABEFCDG

    (2)后根(次序)遍历–二叉树的中序遍历
    当树非空时,依次后根遍历各棵子树,再访问根结点。

    遍历结果:EFBCGDA
  5. 森林的遍历
    (1)先序遍历–二叉树的先序遍历
    若森林不空,则
    1> 访问森林中第一棵树的根结点;
    2> 先序遍历森林中第一棵树的子树森林;
    3> 先序遍历森林中(除第一棵树之外)其余树构成的森林。
    即:依次从左至右对森林中的每一棵树进行先根遍历.

    遍历结果:ABCDEFGHIJK

    (2)中序遍历–二叉树的中序遍历
    若森林不空,则
    1> 中序遍历森林中第一棵树的子树森林;
    2> 访问森林中第一棵树的根结点;
    3> 中序遍历森林中(除第一棵树之外)其余树构成的森林。
    即:依次从左至右对森林中的每一棵树进行后根遍历。

    遍历结果:BCEDAGFKIJH
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

X to Y

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值