二叉树的顺序表示和实现

二叉树的顺序存储结构

#define MAX_TREE_SIZE 100//二叉树的最大结点数
typedef char TElemType;
typedef TElemType SqBiTree[MAX_TREE_SIZE];//0号单元存储根结点

struct position//新增
{
    int level, order;//结点所在的层,在该层的序号(按满二叉树计算)
};

// function
    typedef int TElemType;
    TElemType Nil = 0;

二叉树的顺序存储的基本操作

void visit(TElemType e){
    printf("%d ", e);
}

#define ClearBiTree InitBiTree
#define DestroyBiTree InitBiTree

void InitBiTree(SqBiTree T){//构造空二叉树T。因为T是数组名,不需要&
    int i;
    for (i = 0; i < MAX_TREE_SIZE; i++)
        T[i] = Nil;//初值为空
}

void CreateBiTree(SqBiTree T){//按层序次序输入二叉树中结点的值,构造顺序存储的二叉树T
    int i = 0;
    InitBiTree(T);//构造空二叉树

    printf("请按层序输入结点的值(整型),0表示空结点,输999结束。结点数<=%d:\n", MAX_TREE_SIZE);
    while (1)//永真循环
    {
        scanf("%d", &T[i]);//按层序依次输入
        if (T[i] == 999)//输入结束
        {
            T[i] = Nil;//恢复为空结点
            break;//跳出循环
        }
        i++;//计数+1
    }

    for (i = 1; i < MAX_TREE_SIZE; i++)//从第2个(非根)结点开始检查
    if (T[i] != Nil && T[(i + 1) / 2 - 1] == Nil){//此结点不空但无双亲
        printf("出现无双亲的非根结点%d\n", T[i]);
        exit(OVERFLOW);
    }
}

Status BiTreeEmpty(SqBiTree T){
    if (T[0] == Nil)//根结点为空,则树空
        return TRUE;
    else
        return FALSE;
}

int BiTreeDepth(SqBiTree T){
    int i;
    if (T[0] == Nil)//根结点为空,则树空
        return 0;//空数的深度为0
    for (i = MAX_TREE_SIZE - 1; i >= 0; i--)//从数组的后面开始找起
        if (T[i] != Nil)//找到最后一个结点,其序号为i
            break;
    return (int)(log(i + 1.0) / log(2.0) + 1.1);//序号为i的结点的深度就是树的深度
}

Status Root(SqBiTree T, TElemType &e){
    if (BiTreeEmpty(T))//T空
        return ERROR;
    else
    {
        e = T[0];
        return OK;
    }
}

TElemType Value(SqBiTree T, position e){
    return T[int(pow(2.0, e.level - 1) + e.order - 2)];//返回处于位置e(层,本层序号)的结点的值
}

Status Assign(SqBiTree T, position e, TElemType value){//给处于位置e(层,本层序号)的结点赋新值value
    int i = int(pow(2.0, e.level - 1) + e.order - 2);//将层、本层序号转为数组的序号
    if (i != 0 && value != Nil && T[(i + 1) / 2 - 1] == Nil)//不是根结点,值非空,但双亲为空
        return ERROR;
    else if (value == Nil && T[i * 2 + 1] != Nil || T[i * 2 + 2] != Nil)//给双亲赋空值但有孩子结点
        return ERROR;
    T[i] = value;//以上两种情况之外,给结点赋新值
    return OK;
}

TElemType Parent(SqBiTree T, TElemType e){//若e是T的非根结点,则返回它的双亲,否则返回“空”
    int i;
    if (T[0] == Nil)//空树
        return Nil;//返回“空”
    for (i = 1; i <=MAX_TREE_SIZE - 1; i++)//从二叉树的第2个结点开始查找
        if (T[i] == e)//找到e
            return T[(i + 1) / 2 - 1];//返回其双亲结点的值
    return Nil;//未找到e
}

TElemType LeftChild(SqBiTree T, TElemType e){
    int i;
    for (i = 0; i < (MAX_TREE_SIZE - 2)/2; i++)//从T的第1个结点到最后一个可能有左孩子的结点
        if (T[i] == e)//找到e
            return T[i * 2 + 2];//返回e的左孩子的值
        return Nil;//未找到e
}

TElemType RightChild(SqBiTree T, TElemType e){
    int i;
    for (i = 0; i < (MAX_TREE_SIZE - 3)/2; i++)//从T的第1个结点到最后一个可能有右孩子的结点
        if (T[i] == e)//找到e
            return T[i * 2 + 2];//返回e的右孩子的值
    return Nil;//未找到e
}

TElemType  LeftSibling(SqBiTree T, TElemType e){//返回e的左兄弟,若e是T的左孩子或无左兄弟,返回“空”
    int i;
    if (T[0] == Nil)//空树
        return Nil;//返回“空”
    for (i = 1; i <= MAX_TREE_SIZE - 1; i++)//从二叉树T的第2个结点开始查找
        if (T[i] == e && i % 2 == 0)//找到e且其序号为偶数(是右孩子)
            return T[i - 1];//返回e的左兄弟的值
        return Nil;//未找到e
}

TElemType  RightSibling(SqBiTree T, TElemType e){//返回e的右兄弟,若e是T的右孩子或无右兄弟,返回“空”
    int i;
    if (T[0] == Nil)//空树
        return Nil;//返回“空”
    for (i = 1; i <= MAX_TREE_SIZE - 2; i++)//从二叉树T的第2个结点开始查找
    if (T[i] == e && i % 2)//找到e且其序号为偶数(是右孩子)
        return T[i + 1];//返回e的左兄弟的值
    return Nil;//未找到e
}

void Move(SqBiTree q, int j, SqBiTree T, int i){//把从q的j结点开始的子树移为从T的i结点开始的子树
    if (i >= MAX_TREE_SIZE)//i结点超出了存储范围
        exit(OVERFLOW);
    if (q[2 * j + 1] != Nil)//q的左子树不空
        Move(q, (2 * j + 1), T, (2 * i + 1));//把q的j结点的左子树移为T的i结点的左子树
    if (q[2 * j + 2] != Nil)//q的右子树不空
        Move(q, (2 * j + 2), T, (2 * i + 2));//把q的j结点的右子树移为T的i结点的右子树
    T[i] = q[j];//把q的j结点移为T的i结点
    q[j] = Nil;//把q的j结点置空
}

void InsertChild(SqBiTree T, TElemType p, int LR, SqBiTree c){
    //初始条件:二叉树T存在,p是T中某个结点的值,LR为0或1,非空二叉树c与T不相交且右子树为空
    //操作结果:根据LR为0或1,插入c为T中p结点的左或右子树。p结点的原有左或右子树则成为c的右子树
    int j, k;
    for (j = 0; j < int(pow(2.0, BiTreeDepth(T)) - 1); j++)//查找p的序号
        if (T[j] == p)//j为p的序号
            break;
    k = 2 * j + 1 + LR;//k为p的左或右孩子的序号
    if (T[k] != Nil)//p原来的左或右孩子不空
        Move(T, k, c, 2);//把从T的k结点开始的子树移为c的右子树
    Move(c, 0, T, k);//把树c移为从T的k结点开始的子树
}

Status DeleteChild(SqBiTree T, position p, int LR){
    int i;
    Status k = OK;//队列不空的标志
    LinkQueue q;
    InitQueue(q);//初始化队列,用以存放待删除的结点
    i = (int)pow(2.0, p.level - 1) + p.order - 2;//将层、本层序号转为数组的序号
    if (T[i] == Nil)//此结点空
        return ERROR;
    i = i * 2 + 1 + LR;//将待删除子树的根结点在数组中的序号
    while (k)
    {
        if (T[2 * i + 1] != Nil)//左结点不空
            EnQueue(q, 2 * i + 1);//入队左结点序号
        if (T[2 * i + 2] != Nil)//右结点不空
            EnQueue(q, 2 * i + 2);//入队右结点序号
        T[i] = Nil;//删除此结点
        k = DeQueue(q, i);//出队结点的序号,其值赋给i,成功(队列不空)返回OK,否则返回ERROR
    }
    return OK;
}

void(*VisitFunc)(TElemType);//函数变量
void PreTraverse(SqBiTree T, int e){  //递归先序遍历二叉树中T序号为e的子树,PreOrderTraverse()调用
    VisitFunc(T[e]);//访问树T中序号为e的结点
    if (T[2 * e + 1] != Nil)//序号为e的结点的左子树不空
        PreTraverse(T, 2 * e + 1);//递归先序遍历树T中序号为e的结点的左子树
    if (T[2 * e + 2] != Nil)//序号为e的结点的右子树不空
        PreTraverse(T, 2 * e + 2);//递归先序遍历树T中序号为e的结点的右子树
}

void PreOrderTraverse(SqBiTree T, void(*visit)(TElemType)){//先序遍历T,对每个结点调用函数visit一次且仅一次
    VisitFunc = visit;
    if (!BiTreeEmpty(T))//树不空
        PreTraverse(T, 0);//递归先序遍历树T中序号为0的树(树T自身)
    printf("\n");
}

void InTraverse(SqBiTree T, int e){//递归中序遍历二叉树T中序号为e的子树,InOrderTraverse()调用
    if (T[2 * e + 1] != Nil)//序号为e的结点的左子树不空
        InTraverse(T, 2 * e + 1);//递归中序遍历树T中序号为e的结点的左子树
    VisitFunc(T[e]);//访问树T中序号为e的结点
    if (T[2 * e + 2] != Nil)//序号为e的结点的右子树不空
        InTraverse(T, 2 * e + 2);//递归中序遍历树T中序号为e的结点的右子树
}

void InOrderTraverse(SqBiTree T, void(*visit)(TElemType)){//中序遍历T,对每个结点调用函数visit一次且仅一次
    VisitFunc = visit;
    if (!BiTreeEmpty(T))//树不空
        InTraverse(T, 0);//递归中序遍历树T中序号为0的树(树T自身)
    printf("\n");
}

void PostTraverse(SqBiTree T, int e){//递归后序遍历二叉树T中序号为e的子树,PostOrderTraverse()调用
    if (T[2 * e + 1] != Nil)//序号为e的结点的左子树不空
        PostTraverse(T, 2 * e + 1);//递归后序遍历树T中序号为e的结点的左子树
    if (T[2 * e + 2] != Nil)//序号为e的结点的右子树不空
        PostTraverse(T, 2 * e + 2);//递归后序遍历树T中序号为e的结点的右子树
    VisitFunc(T[e]);//访问树T中序号为e的结点
}

void PostOrderTraverse(SqBiTree T, void(*visit)(TElemType)){//后序遍历T,对每个结点调用函数visit一次且仅一次
    VisitFunc = visit;
    if (!BiTreeEmpty(T))//树不空
        PostTraverse(T, 0);//递归后序遍历树T中序号为0的树(树T本身)
    printf("\n");
}

void LevelOrderTraverse(SqBiTree T, void(*visit)(TElemType)){//层序遍历二叉树T
    int i = MAX_TREE_SIZE - 1, j;
    while (T[i] == Nil)
        i--;//找到最后一个非空结点的序号
    for (j = 0; j <= i; j++)//从根结点起,按层序遍历二叉树
        if (T[j] != Nil)
            visit(T[j]);//只遍历非空的结点
        printf("\n");
}

void Print(SqBiTree T){//逐层、按本层序号输出二叉树T
    int j, k;
    position p;
    TElemType e;
    for (j = 1; j <= BiTreeDepth(T); j++)//j为当前层
    {
        printf("第%d层:", j);
        p.level = j;//当前结点所在层
        for (k = 1; k <= pow(2.0, j - 1); k ++)
        {
            p.order = k;//当前结点在本层的顺序
            e = Value(T, p);//该结点的值赋给e
            if (e != Nil)//e非空
                printf("%d:%d", k, e);//输出在本层的顺序及值
        }
        printf("\n");
    }
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-27 18:38:04

二叉树的顺序表示和实现的相关文章

二叉树的顺序结构

#include "stdio.h" #include "stdlib.h" #include "math.h" #include "time.h" #define OK 1 #define ERROR 0 #define TRUE 1 #define FALSE 0 #define MAXSIZE 100 /* 存储空间初始分配量 */ #define MAX_TREE_SIZE 100 /* 二叉树的最大结点数 */ ty

二叉树叶子顺序遍历 &#183; binary tree leaves order traversal

[抄题]: 给定一个二叉树,像这样收集树节点:收集并移除所有叶子,重复,直到树为空. 给出一个二叉树: 1 / 2 3 / \ 4 5 返回 [[4, 5, 3], [2], [1]]. [暴力解法]: 时间分析: 空间分析: [思维问题]: 觉得要用BFS [一句话思路]: [输入量]:空: 正常情况:特大:特小:程序里处理到的特殊情况:异常情况(不合法不合理的输入): [画图]: [一刷]: [二刷]: [三刷]: [四刷]: [五刷]: [五分钟肉眼debug的结果]: [总结]: [复杂

树和二叉树

以下的内容做为学习笔记,复制别人的,感觉总结的比较好: 第5章 树和二叉树 本章中主要介绍下列内容:  1.树的定义和存储结构  2.二叉树的定义.性质.存储结构  3.二叉树的遍历.线索算法  4.树和二叉树的转换  5.哈夫曼树及其应用课时分配:     1.2两个学时,3四个学时,4两个学时, 5两个学时,上机两个学时重点.难点:     二叉树的遍历.线索算法.哈夫曼树及其应用 第一节 树 1.树的定义和基本运算1.1 定义    树是一种常用的非线性结构.我们可以这样定义:树是n(n≥

对称二叉树

[问题描述] 如果二叉树的左右子树的结构是对称的,即两棵子树皆为空,或者皆不空,则称该二叉树是对称的.编程判断给定的二叉树是否对称. 例:如下图中的二叉树T1是对称的,T2是不对称的. 二叉树用顺序结构给出,若读到#则为空,二叉树T1=ABCDE,T2=ABCD#E,如果二叉树是对称的,输出“Yes”,反之输出“No”. [输入样例]tree_c.in ABCDE [输出样例]tree_c.out Yes 1 #include<iostream> 2 using namespace std;

数据结构(七)二叉树

定义 特点 特殊的二叉树 斜树 顾名思义,其中的结点都只有一个,又分为左斜树和右斜树,这时候又有疑惑了,这种数据结构不是有线性表一样吗,没错,线性表是一种特殊的树 满二叉树 完全二叉树 这个定义有点绕,简单来说就是所有的结点必须是有顺序的,不能跳跃存在 二叉树的性质 1.在二叉树的第i层至多有2的(i-1)次方个结点,参考满二叉树 2.深度游k的二叉树至多有2的k次方-1个结点,参考满二叉树 3.任意二叉树,终端结点为n0,度为2的结点为n2,度为1的结点为n1,则n0=n2+1 下面是推倒过程

二叉树基础及应用

二叉树基础: 刚看到堆排序,顺便记录一下关于树的一些基本概念: 前言 前面介绍的栈.队列都是线性结构(linear structure).而树是非线性结构(non-linear structure).因此,树中的元素之间一般不存在类似于线性结构的一对一的关系,更多地表现为多对多的关系.直观地看,它是数据元素(在树中称为节点)按分支关系组织起来的结构.显然,树形结构是比线性结构更复杂的一种数据结构类型. 一.树 树的定义:树是含有n个节点的有穷集合,其中有一个节点比较特殊称为根节点.在图示树时,用

对称的二叉树-剑指Offer

对称的二叉树 题目描述 请实现一个函数,用来判断一颗二叉树是不是对称的.注意,如果一个二叉树同此二叉树的镜像是同样的,定义其为对称的. 思路 先序遍历二叉树的顺序为“根->左->右”,我们定义个跟先序遍历对称的遍历顺序“跟->右->左”,如果这两个遍历的结点对应相等,则是对称二叉树 注意:因为叶子结点的左右子树在遍历结果中无法根据先后顺序区分,所以我们需要考虑到null指针,需要null指针对应也相等 如果二叉树为空,则也是对称的 代码 /* public class TreeNo

第4章第3节 二叉树的基本操作(非递归实现)

二叉树的非递归遍历 上一节二叉树的递归遍历中简单介绍了二叉树的递归遍历的实现方式,本节主要介绍二叉树的非递归遍历实现,继续引用上节的例子来说明下. 一.先序遍历 二叉树先序遍历的访问顺序为:根结点->左孩子->右孩子.简单的说,对于任意一个结点,均可以看作是根结点,直接对其访问,如果访问完成后,左孩子不为空,则可以将该左孩子再次看成一个新的根结点,那么就又回到开始,访问根结点,访问左孩子,如果左孩子为空时,访问它的右孩子.对于一般程序而言,递归程序转为非递归程序需要引入栈这个数据结构,可以参考

树和二叉树总结及算法实现

[注:相关概念来自经典教材.百度百科及维基百科] 树 树状图是一种数据结构,它是由n(n>=1)个有限节点组成一个具有层次关系的集合.它具有以下的特点: 每个节点(node)有零个或多个子节点: 没有父节点的节点称为根节点: 每一个非根节点有且只有一个父节点: 除了根节点外,每个子节点可以分为多个不相交的子树: 如图所示: 相关概念: 节点的度:一个节点含有的子树的个数称为该节点的度: 树的度:一棵树中,最大的节点的度称为树的度: 叶节点或终端节点:度为零的节点: 非终端节点或分支节点:度不为零