数据结构 学习笔记 树

一、树的定义

树的递归定义:

1.有且只有一个结点叫根。

2.除根结点外其余结点可划分为m个互不相交的子集T1,T2...Tm(m>=0),并且这m个子集每个子集本身又构成一棵树,称为T的子树。

 

树的表示方法有很多,如图形表示,广义表表示,嵌套集合表示,凹入表表示等等。

 

树的基本概念和术语

1.结点

又称作节点,表示数据元素,链式储存结构要加上相关指针。

2.结点的度Degree

结点的子树个数或者分枝数,称为结点的度。

3.树的度

树内各结点的度的最大值。

4.叶子结点

度为0的结点称为叶子结点,或者终端结点。

5.分支结点

指的是度不为0的结点,或者有子树的结点。

6.结点的层次

此处规定根结点的层次为1,其他结点的层次数等于父亲结点+1。结点的层次也叫结点的深度。

7.树的高度(Depth)

树中各结点的最大层次数,称为树的高度。

8.孩子结点

当前结点所有子树的根结点,称为孩子结点。

9.后裔结点

当前结点为跟结点,其子树上的所有结点,都是当前结点的后裔结点。

10.双亲结点

即父亲结点。

11.祖先结点

从根结点由路径到达当前结点,路径经过的所有结点,均为当前结点的祖先结点。

12.兄弟结点(Silbling)

双亲结点相同的所有结点互称为兄弟结点。

13.堂兄弟结点

双亲结点在同一层次(深度相同)的结点,互为堂兄弟。

14.有序树和无序树

同一结点的所有子树,从左至右规定次序叫有序树,若结点的子树不分先后次序即无序树。

15.森林

m棵不相交树的集合,叫做森林。

与线性表以及其他结构相比,树结构有明显的差异,每个结点至多有一个直接前驱,但却可以有多个后继。

 

二、二叉树

2.1递归定义

二叉树是n个结点的有限集合,其中n>=0,n=0 称为空树否则:

1.有且只有一个结点为根结点。

2.其余结点划分为两个互不相交的子集TL,TR,并且TL,TR分别构成一棵二叉树,称为T的左子树和右子树。

2.2特点

特点一、二叉树中的每个结点最多只有两棵子树。即二叉树中仅仅存在三种度数的结点:0度,1度,2度。

特点二、二叉树是一棵有序树,其子树区分左右。

例如:3个结点构成的树 只有2种形态,而3个结点构成的二叉树形态 有 5 种

 

2.3二叉树的性质

定义:

满二叉树:每层都有最大数目结点的二叉树

完全二叉树:在满二叉树最下层自右向左连续删除若干结点形成的树

性质一:二叉树上第i层上的结点树\leq 2^{i-1}(i> 0)

性质二:深度为k的二叉树的结点树\leq 2^k -1(k> 0)

性质三:对于任意非空二叉树,如果其叶子树为N0,度为2的结点树为N2,则有下列等式:n_{0} = n_{2} + 1

证明略。

性质四:有n个结点的完全二叉树的深度为log_{2}n + 1 (向下取整)

性质五:在编号的完全二叉树中,当前结点的编号为i,则有:

1.如果i的左孩子存在,其编号为2i

2.如果i的右孩子存在,其编号为2i+1

3.如果i的父亲结点存在,其编号为i/2 向下取整

 

例题:已知完全二叉树有100个结点,则该二叉树有多少个叶子结点?

(至少三种方法)

方法一:最大编号为100,其父结点为50,从51~100均为叶子结点。ANS = 100 - 51 + 1 = 50.

 

 

2.4二叉树的存储结构

2.4.1顺序存储结构

(1)完全二叉树的顺序存储

用数组存储元素(结点的值),用数组下标编号表示树中对应结点的编号值。

(2)一般二叉树的顺序存储

将其补全为完全二叉树后按照完全二叉树进行存储。

 

2.4.2链表存储结构

二叉链表

typedef struct BNode{
    char data;
    struct BNode *lChild, *rChild;
}BiNode;

二叉链表是最基本的链式存储结构,一棵n个结点的二叉树,采用二叉链表存储的时候,共有2n个指针域,其中有n-1个指针非空(除了根结点,其他结点都有指针指向,剩下2n-(n-1) = n+1个指针域为空。

 

三叉链表

每个结点有三个指针域(左右孩子,父结点),称这种结构的链表叫做三叉链表。

typedef struct TriNode{
    char data;
    struct Trinode *lChird, *rChild, *parent;
}TNode;

 

2.5 二叉树的遍历

遍历即对二叉树中的每个结点经过一次且仅一次的访问。

二叉树访问次序组合

                                  从左到右                   从右到左

先序                              DLR                          DRL

中序                              LDR                          RDL

后序                              LRD                          RLD

 

在此使用从左到右的遍历序。

1.先序遍历 DLR

if(T){
    首先访问根结点;
    先序遍历T的左子树;
    先序遍历T的右子树;
}

2.中序遍历 LDR

if(T) {
    中序遍历T的左子树;
    访问T的根结点;
    中序遍历T的右子树;
}

3.后序遍历 LRD

if(T) {
    后序遍历T的左子树;
    后序遍历T的右子树;
    访问T的根结点;
}

 

此处需要练习,请自行练习。

例:某序列遍历如下:

中序:CBEDAGHFJI

后序:CEDBHGJIFA

试构造其二叉树结构。

 

先序遍历的递归算法

void preOrder(BNode *T) {
    if(T) {
        cout << T->data << endl;
        preOrder(T->lChild);
        preOrder(T->rChild);
    }
}

先序遍历的非递归算法

void preOrderNR(BiNode *T) {
    BiNode *p;
    stack<BiNode*> s;
    p = T;
    while(p || s.empty()) {
        if(p) {
            cout << p->data << " ";
            s.push(p);
            p = p->lChild;
        }
        else {
            s.pop();
            p = p->rChild;
        }
    }
}

2.6二叉树的创建和销毁

void createSubTree(BiNode *q, int k) { // 子树创建
    //q为当前跟结点
    //k = 1为左子树,k = 2为右子树
    BiNode *u;
    int x;
    cin >> x;
    if(x != '/') {
        u = new BiNode;
        u->data = x;
        u->lChild = NULL;
        u->rChild = NULL;
        if(k == 1) 
            q ->lChild = u;
        else if(k == 2)
            q ->rChild = u;
        createSubTree(u,1);
        createSubTree(u,2);
    }
}

void createBiTree(BiNode *&T) {
    BiNode *p;
    char x;
    cout << "请按照先序序列输入二叉树,'/'表示无子树" << endl;
    cin >> x;
    if(x = '/')  
        return;
    T = new BiNode;
    T->data = x;
    T->lChild = NULL;
    T->rChild = NULL;
    p = T;
    createSubTree(p, 1);
    createSubTree(p, 2);
}

创建如图

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值