数据结构基础—树与二叉树(1)

数据结构基础—树和二叉树

一、树、二叉树类型定义

1.树的定义

a.定义

树是一种非线性结构,是具有相同特征的数据元素的集合(同质/类)

数据对象D:D是具有相同特征的数据元素的集合(同质/类)
数据关系R:
若D为空树,则就角空树
否则
1. n = 1(一个元素),有且仅有一个根节点
2. n > 1,其余节点可分为m颗不相交的有限子集(小树)(递归定义),每一个子 集也叫一颗子树符合...
基本操作:查找类,插入类(初始化,节点插入子树...),删除类(销毁.删除结点...)

根是树的第一层,子树依次类推++

深度:最大的层数 = max(子树深度)+1(递归啦)

b.分类

  • 有向树:有确定的根,自顶向下(一般)
  • 有序树:子树之间存在有次序关系
  • 无序树:子树之间不存在次序关系

c.对比树型结构和线性

  • 线性:第一元素无前驱,最后一个元素无后继;其他元素一个前驱,一个后继
  • 树型:根结点无前驱,多个叶子结点无后继;其他元素,一个前驱,个后继

d.属性

结点:数据元素+若干指向子树的分支(结点关系)

结点的度:分支个数(子树棵树..)

树的度:树中所有结点的度的最大值

叶子结点:度为零的结点

分支结点:度>0的结点

路径:从根到某个结点的路线

同一层的都是堂兄弟,若父结点相同:兄弟结点

祖先结点:> 父结点的结点的统称

e.森林

m > 0棵不相交的树的集合(可以看成去了头结点...)

2.二叉树类型定义:

a.定义

空树 / 一个根结点+两颗子树(还是二叉树)

是有序树,分左右子树

b.二叉树的5中形态

image

b.特殊的二叉树

  • 满二叉树,深度为k的树有2的k-1次方个结点

  • 完全二叉树,满二叉树去掉右边的叶子不能跳的去。树中所含n个结点和满二叉树中编号1-n的结点一一一对应

image

c.完全二叉树性质

1.二叉树第i层最多2的n-1次方的结点(i >= 1)

2.若深度为i,则最多有多少个结点(等比求和),2的i次方 - 1

3.若深度为i,则,第i层最少1个结点。整个树最少有i个结点

4.结点和边(分支)的关系。n个结点,n-1个分支(n = e + 1)

5.叶子结点和度为2的关系:n0 = n2 +1(n=n0 + n1 + n2 = e(n1+n2) + 1)

6.完全二叉树有n个结点,则,深度为log2n取整数(向下取)+1

7.结点编号:结点为i,若i = 1是根结点,i/2是双亲。i >1且 2i <= n,左子2i;i >1且 2i+1 <= n,右2i+1

二、二叉树的存储结构

1.顺序

#define MaxSize 100
typefef TElemType SqbItREE[maxSzie];//零号单元存储根节点
SqBiTree bt;

只适用于完全二叉树好

2.链式

a.二叉链表

image

typedef struct BiTNode{
    TElemType data;//数据
    struct BiTNode *lchild,*rchild;//左右指针
}BiTNode,*BiTree;

n个结点的二叉链表中,有 n+1个空指针域(2n个指针域,除了根结点,每个结点对应一个,n-1个,2n- (n-1))

b.三叉链表

浪费一些空间
image

typedef struct TrTNode{
    TElemType data;//数据
    struct TrTNode *lchild,*rchild;//左右指针
     struct TrTNode *parent;//双亲指针
}TrTNode,*TrTree;

image

typedef struct BPTNode{//结点结构
    TElemType data;//数据
    int *parent;//指向双亲的指针
    char *LRTag;//左右孩子的标志
}BPTNode;
typedef structBPTree{
    BPTNode nodes[MaxSize];
    int mum;结点数目
    int root;跟结点的位置
}BPTree;

d.静态链表

image

三、二叉树的遍历

1.算法递归的描述

满足条件:

  • 每一次调用更接近解
  • 必须有一个终止处理或计算

递归一定可以改成栈

分治法,后置递归法,回溯法(与分治本本质相同)

尾递归(提倡简单,设计,效率高)

2.二叉树的遍历

a.遍历路径

对于二叉树,有三种遍历路径

先上后下的层次遍历,先左后右(正序),先右后左(逆序)

b.先左后右的遍历(正序)

分为三种:根左右(先),左根右(中),左右根(后)

先序描述

//递归
void Preorder(BiTree T,void(*visit)(TElemType& e)){//先序遍历
                             //对该结点的操作
    if(T){
        visit(T->data);//访问
        Preorder(T->lchild,vist);//遍历左子树
        // visit(T->data);中序
        Preorder(T->lchild,vist);//遍历右子树
        // visit(T->data);后序
    }
}

其实,三种访问算法的实质是一样的,是指访问时机不同(沿着树画出线画出空结点)

  • 先:第一次经过就访问
  • 中:第二次经过就访问
  • 后:第三次经过就访问

c.第一个结点和最后一个结点

第一个结点:

  • 先序:根结点
  • 中序:从根结点出发,沿左链走,第一个没有左孩子的结点
  • 后序:在左链,沿着左链一直走,找到没有左孩子的结点;若该结点没有右孩子该结点就是最后一个结点;如果有右孩子则重复上述操作

最后一个结点:

  • 先序:在右链,沿着右链一直走,找到没有右孩子的结点;若该结点没有左孩子该结点就是最后一个结点;如果有左孩子则重复上述操作
  • 中序:从根结点出发,沿右链走,第一个没有右孩子的结点
  • 后序:根结点

d.非递归遍历

代码放在下一篇啦(要不有点多)

总是先将树的左子入栈

用栈或者模拟栈均可

第一种

先获取第一个左链结点,并将其所有的根结点入栈(左结点全部入栈,除了获取的结点)

访问该结点,查询是否有右结点,如果有,重复上述;

如果没有,则判断栈(该结点的根结点是栈顶)是否空,不空:则退栈,获取该栈顶为新的"第一个结点",重复上述;空(遍历结束)

第二种

若栈或树不空时

  • 树不空:树进栈,沿左链下移
  • 栈不空:退一个栈到T,并获取T。T沿右链下移

四、二叉树的一些基本操作

和遍历一样放在下一篇了

posted @ 2022-11-17 09:14  T,a,o  阅读(141)  评论(0编辑  收藏  举报