树 算法结构

6 篇文章 0 订阅
3 篇文章 0 订阅
文章介绍了树作为一种抽象数据类型,包括它的基本概念,如根节点、子树和层次。接着详细阐述了二叉树的定义,区分了满二叉树和完全二叉树,并解释了四种遍历方法:前序遍历、中序遍历、后序遍历和层次遍历。最后提供了一个关于二叉树遍历的例题和解题代码。
摘要由CSDN通过智能技术生成

树的基本概念


  • 树(tree),是一种抽象数据类型或是实现这种抽象数据类型的数据结构,用来模拟具有树状结构性质的数据集合。

  • 树是一种非线性的数据结构,用它能很好地描述有分支和层次特性的数据集合。

  • 树是由n(n>0)个元素组成的有限集合,其中:

  1. 每个元素称为结点(node);
  • 有一个特定的结点,称为根结点或树根 (root);

  • 除根结点外,其余结点能分成m(m>=0)个互不相交的有限集合T0,T1,T2,……Tm−1。其中的每个子集又都是一棵树,这些集合称为这棵树的子树。


如下图是一棵典型的树:


树的结点

结点的层次:

根结点为第一层,根的子结点为第二层,依次向下递推…

树的深度:

树种结点的最大层次。eg:该树的深度为4 森林:互不相交的树称为森林

树结构的存储

我们表示一棵树的方法有:双亲表示法,孩子表示法,孩子兄弟表示法



双亲表示法

以双亲作为索引的关键词的一种存储方式

每个结点只有一个双亲,所以选择顺序存储占主要

结点定义:

struct Node{
    char data;//存储值
    int parent;//存储结点的父亲结点编号
}a[maxn];//结点个数maxn

孩子表示法

由于每个结点可有多个子树,所以我们用树的度数来定义每个结点的孩子数

结点定义:

struct Node{
    char data;//存储值
    int child[max_d];//树的度数是max_d
}a[maxn];//结点个数maxn

孩子兄弟表示法

任意一棵树,他的结点的第一个孩子如果存在就是唯一结点,他的右兄弟如果存在,也是唯一的,因此,我们设置两个指针,分别指向该结点的第一个孩子和该结点的右兄弟

结点定义:

struct Node{
    char data;//存储值
    Node *Firstchild,*Rightbrother;
}a;




二叉树

二叉树的定义

二叉树是n(n>=0)个结点的有限集合,该集合或者为空集(称为空二叉树),或者由一个根结点和两棵互不相交的、分别称为根结点的左子树和右子树组成。

满二叉树

满二叉树:在一棵二叉树中。如果所有分支结点都存在左子树和右子树,并且所有叶子都在同一层上,这样的二叉树称为满二叉树。

满二叉树的特点有:

  1. 叶子只能出现在最下一层。出现在其它层就不可能达成平衡。

  2. 非叶子结点的度一定是2。

  3. 在同样深度的二叉树中,满二叉树的结点个数最多,叶子数最多。

  4. 以下是一颗满二叉树:


完全二叉树

对一颗具有n个结点的二叉树按层编号,如果编号为i(1<=i<=n)的结点与同样深度的满二叉树中编号为i的结点在二叉树中位置完全相同,则这棵二叉树称为完全二叉树。

完全二叉树的特点

  1. 叶子结点只能出现在最下层和次下层。

  2. 最下层的叶子结点集中在树的左部。

  3. 倒数第二层若存在叶子结点,一定在右部连续位置。

  4. 如果结点度为1,则该结点只有左孩子,即没有右孩子。

  5. 同样结点数目的二叉树,完全二叉树深度最小。

  6. 在完全二叉树中,具有n个结点的完全二叉树的深度为[log2n]+1,其中[log2n]是向下取整。

若对含 n 个结点的完全二叉树从上到下且从左至右进行 1 至 n 的编号,则对完全二叉树中任意一个编号为 i 的结点有如下特性:

  1. 若 i=1,则该结点是二叉树的根,无双亲, 否则,编号为 [i/2] 的结点为其双亲结点;
  2. 若 2i>n,则该结点无左孩子, 否则,编号为 2i 的结点为其左孩子结点;
  3. 若 2i+1>n,则该结点无右孩子结点, 否则,编号为2i+1 的结点为其右孩子结点。

    注:满二叉树一定是完全二叉树,但反过来不一定成立。


二叉树遍历

二叉树的遍历是指从二叉树的根结点出发,按照某种次序依次访问二叉树中的所有结点,使得每个结点被访问一次,且仅被访问一次。

二叉树的访问次序可以分为四种:前序遍历、中序遍历、后序遍历、层序遍历

前序遍历

先访问根结点,再从左到右按照前序遍历思想递归遍历各棵子树。 上图前序遍历的结果为:ABDHIEJCFG 从根结点出发,则第一次到达结点A,故输出A; 继续向左访问,第一次访问结点B,故输出B; 按照同样规则,输出D,输出H; 当到达叶子结点H,返回到D,此时D的左子树已访问结束,进而访问D的右子树I; 按照同样的访问规则,继续输出E,J,C,F,G;

中序遍历

先遍历左子树,再访问根结点,再遍历右子树。 上图中序遍历的结果为:HDIBJEAFCG 从根结点出发,访问结点A,A存在左子树B,则递归访问左子树B,依次递归直到H; 到达H,H左子树为空,则输出结点H,访问H右子树,为空,返回H子树根结点D; 返回至D,此时D的左子树访问完毕,输出D,访问D的右子树I; 结点I左子树为空,则输出I,右子树为空则返回父结点D; 按照同样规则继续访问,输出B,J,E,A,F,C,G;

后序遍历

先从左到右遍历各棵子树,再访问根结点。 上图后序遍历的结果为:HIDJEBFGCA 从根结点A出发,A左右子树非空,先递归访问左子树B 以此类推到达H,H左、右子树为空,则输出H; 由H返回至D,D左子树访问结束,递归访问其右子树I; I左右子树均为空,输出I; 返回至D,此时D左、右子树均访问结束,故输出D; 按照同样规则继续访问,输出J,E,B,F,G,C,A; 层次遍历: 按层次从小到大逐个访问,同一层次按照从左到右的次序。 上图层次遍历的结果为:ABCDEFGHIJ

例题

10.4.8.1 树的遍历

【问题描述】

给出一个n个结点的二叉树,请求出二叉树的前序遍历,中序遍历和后序遍历。

【输入格式】

第一位一个整数n(0<n<=26),表示二叉树有n个结点,结点序号:1∼n。

以下n行,第i行表示序号为i的结点信息,第一个大写字母表示结点的值,后面为两整数,第一个表示左儿子序号,第二个表示右儿子序号,如果该序号为0表示没有,结点1为根结点。

【输出格式】

共三行,第一行为二叉树的前序遍历,第二行为中序遍历,第三行为后序遍历


【输入样例】

7
F 2 3
C 4 5
E 0 6
A 0 0
D 7 0
G 0 0
B 0 0

【输出样例】

FCADBEG
ACBDFEG
ABDCGEF

【代码实现】

#include <bits/stdc++.h>
const int maxn=26+5;
struct Node{//结点
    char data;//值
    int lch,rch;//记录结点左右儿子序号
}a[maxn];
int n;
void Head_s(int x){//前序遍历
    if(x==0)return;
    printf("%c",a[x].data);//先输出根结点
    Head_s(a[x].lch);//再递归访问左子树
    Head_s(a[x].rch);//再递归访问右子树
}
void Mid_s(int x){//中序遍历
    if(x==0)return;
    Mid_s(a[x].lch);//先遍历左子树
    printf("%c",a[x].data);//左子树访问结束,输出根结点
    Mid_s(a[x].rch);//再递归访问右子树
}
void Tail_s(int x){//后序遍历
    if(x==0)return;
    Tail_s(a[x].lch);//先遍历左子树
    Tail_s(a[x].rch);//再遍历右子树
    printf("%c",a[x].data);//左右子树访问结束,输出根结点
}
void Solve(){
    scanf("%d",&n);
    for(int i=1;i<=n;++i)
        scanf(" %c%d%d",&a[i].data,&a[i].lch,&a[i].rch);
    Head_s(1);printf("\n");
    Mid_s(1);printf("\n");
    Tail_s(1);printf("\n");
}
int main(){
    Solve();
    return 0;
}

评论

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值