首页 > 其他分享 >二叉树的顺序实现

二叉树的顺序实现

时间:2023-08-02 23:14:16浏览次数:51  
标签:结点 顺序 return 实现 BiTree int depth 二叉树

二叉树的顺序实现

//
//  main.c
//  SqBiTree
//
//  Created by Eason on 2020/8/7.
//  Copyright © 2020 Eason. All rights reserved.
//

#include <stdio.h>
#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
#define MAXSIZE 100
typedef int Status;  //作为返回状态 如ERROR OK FALSE TRUE,其实也就是返回一个int值
typedef int ElemType;   //元素数据类型,这里就先定义为int
typedef ElemType BiTree[MAXSIZE];   //二叉树的元素存储数组,通过数组的下标实现二叉树结构
//这里一定要注意的是这里存储容量MAXSIZE 因为获取孩子的判断是要判断T[2*MAXSIZE]这个数量级的,所以实际存储容量要比真实存储的内容大一倍
//比如放了10个元素,这时候我的存储容量至少为21以上,不然判断的时候数组越界会报错,数值原因见获取孩子方法
ElemType null=0;   //将0作为空元素

//初始化一个二叉树
Status initTree(BiTree T){
    for(int i=0;i<MAXSIZE;i++){   //将二叉树中所有元素位置置为空元素标志null即0
        T[i] = null;  //即将空元素存入
    }
    printf("二叉树初始化完成\n");
    return OK;
}

//清空一个二叉树(也可以使用#define clearTree initTree)
Status clearTree(BiTree T){   //同初始化一个二叉树相同
    for(int i=0;i<MAXSIZE;i++){
        T[i] = null;
    }
    return OK;
}

//创建一个二叉树
Status creatBTree(BiTree T){
    printf("创建一个元素为1-10的二叉树\n");
    int i=0;   //当前数组位置计位器
    int data=1;   //存入的数据元素
    while(data<=10){   //准备存入1-10
        T[i]=data;   //将当前数据元素存入当前数组位置处
        if(i!=0 && i>=MAXSIZE && T[(i+1)/2-1]==null && T[i]!=0){   //即当前结点是非根无双亲且不为空的结点,即为一个悬浮的结点,那么是不能给这个结点赋值的
            printf("出现了无双亲的非根结点\n");
            return ERROR;
        }
        i++;   //数组位置进一
        data++;   //数据元素+1
    }
    return OK;
}

//判断二叉树是否为空
Status isEmpty(BiTree T){
    if(T[0]==null){   //若二叉树没有根结点,则表明当前二叉树是空二叉树
        return TRUE;
    }else{
        return FALSE;
    }
}

//获取当前二叉树的根结点数据
Status getRoot(BiTree T, int *e){
    if(isEmpty(T)){   //如果当前二叉树为空,则没有根结点
        printf("当前二叉树为空,无根结点数据\n");
        return ERROR;
    }
    *e = T[0];   //如果不为空则将根结点的数据存入e中供返回查看
    return OK;
}

//获取二叉树的深度
int getDepth(BiTree T){
    int i;   //数组位置计位器
    for(i=MAXSIZE-1;i>=0;i--){   //从二叉树数组的最后位置向前找
        if(T[i]!=null){   //找到最后一个不为空的元素后推出循环
            break;
        }
    }
    i++;   //将i作为位置
    int depth = 1;   //初始depth为1
    while(i>=powl(2, depth)){   //2的depth次方,当2的depth次方大于当前最后元素位置时,depth就为当前二叉树的深度
        depth++;   //若当前深度仍不包含最后一个元素,则继续加深深度
    }
    return depth;   //返回深度值
}

//获取二叉树某个结点的parent(获取二叉树中e元素的双亲结点元素)
ElemType getParent(BiTree T, ElemType e){
    if(isEmpty(T)){   //判断当前二叉树是否为空
        printf("二叉树为空,无法查找\n");
        return ERROR;
    }
    for(int i=0;i<MAXSIZE;i++){   //寻找指定数值结点的位置
        if(T[i]==e){   //若当前位置元素与指定元素相等
            return T[(i+1)/2-1];   //则返回此位置元素的双亲结点数据,若返回0则表示无双亲结点
        }
    }
    printf("二叉树中无此结点,无法查找\n");
    return ERROR;
}

//获取二叉树某个结点的左孩子(获取二叉树中e元素的左孩子)
ElemType getLeftChild(BiTree T, ElemType e){
    if(isEmpty(T)){   //判断当前二叉树是否为空
        printf("二叉树为空,无法查找\n");
        return ERROR;
    }
    for(int i=0;i<MAXSIZE;i++){   //寻找指定数值结点的位置
        if(T[i]==e){   //若当前位置元素与指定元素相等
            return T[i*2+1];   //则返回此位置元素的左孩子结点的数据,若返回0则表示无左孩子
        }
    }
    return ERROR;
}

//获取二叉树某个结点的右孩子(获取二叉树中e元素的右兄弟)
ElemType getRightChild(BiTree T, ElemType e){
    if(isEmpty(T)){   //判断当前二叉树是否为空
        printf("二叉树为空,无法查找\n");
        return ERROR;
    }
    for(int i=0;i<MAXSIZE;i++){   //寻找指定数值结点的位置
        if(T[i]==e){   //若当前位置元素与指定元素相等
            return T[i*2+2];   //则返回此位置元素的右孩子结点的数据,若返回0则表示无右孩子
        }
    }
    return ERROR;
}

//获取二叉树某个结点的左兄弟(获取二叉树中e元素的左兄弟)
ElemType getLeftBrother(BiTree T, ElemType e){
    if(isEmpty(T)){   //判断当前二叉树是否为空
        printf("二叉树为空,无法查找\n");
        return ERROR;
    }
    for(int i=0;i<MAXSIZE;i++){   //寻找指定数值结点的位置
        if(T[i]==e && i%2==0){   //若当前位置元素与指定元素相等,并且本身位置为右
            return T[i-1];   //则返回此位置右孩子的数据
        }
    }
    return 0;   //若无可满足条件的元素则返回0,也就是说若返回0则表示这个结点是左结点,也可能是没有左兄弟
}

//获取二叉树某个结点的右兄弟(获取二叉树中e元素的右兄弟)
ElemType getRightBrother(BiTree T, ElemType e){
    if(isEmpty(T)){   //判断当前二叉树是否为空
        printf("二叉树为空,无法查找\n");
        return ERROR;
    }
    for(int i=0;i<MAXSIZE;i++){   //寻找指定数值结点的位置
        if(T[i]==e && i%2!=0){   //若当前位置元素与指定元素相等,并且本身位置为左
            return T[i+1];   //则返回此位置左孩子的数据
        }
    }
    return 0;   //若无可满足条件的元素则返回0,也就是说若返回0则表示这个结点是右结点,也可能是没有又兄弟
}

//获取某指定位置的结点数据(获取二叉树中第level层第num个结点元素)
ElemType getValue(BiTree T, int level, int num){
    if(isEmpty(T)){   //判断当前二叉树是否为空
        printf("二叉树为空,无法查找\n");
        return ERROR;
    }
    return T[(int)pow(2, level-1)+num-2];
}

//替换某指定位置的结点数据(将二叉树第level层第num个数据元素替换为value)
Status replace(BiTree T, int level, int num, ElemType value){
    int i = (int)pow(2, level-1)+num-2;   //将指定的level层第num个数据元素替换成在数组中的下标位置
    if(T[i+1/2-1]==null){   //若指定位置的结点无双亲结点则无法赋值
        printf("此结点的双亲结点为空,无法赋值\n");
        return ERROR;
    }
    if(value==null && (T[i*2+1]!=null || T[i*2+2]!=null)){   //若此结点有孩子结点那么则不可为这个结点赋控制
        printf("此结点的孩子结点不为空,不可以为其赋空值\n");
        return ERROR;
    }
    T[i] = value;   //将value存入指定位置
    return OK;
}

//--------------------二叉树的遍历----------------------
//均利用递归的方式进行遍历
//先序访问输出(供先序遍历调用)
void preOrderVisit(BiTree T, int now){   //先序遍历即先访问根结点然后遍历左子树最后访问右子树
    printf("%d ", T[now]);   //访问当前结点数据并打印
    if(T[now*2+1]!=null){   //若当前位置有左子树则先访问左子树
        preOrderVisit(T, now*2+1);   //访问左子树
    }
    if(T[now*2+2]!=null){   //若当前位置有右子树则访问右子树
        preOrderVisit(T, now*2+2);    //访问右子树
    }
}
//先序遍历
Status preOrderTraverse(BiTree T){
    if(isEmpty(T)){   //判断二叉树是否为空
        printf("二叉树为空,无法遍历\n");
        return ERROR;
    }
    preOrderVisit(T, 0);   //调用前序遍历函数
    printf("\n");
    return OK;
}

//中序访问输出(供中序遍历调用)
void inOrderVisit(BiTree T, int now){   //中序遍历即先遍历左子树后访问根结点最后遍历右子树(参考前序遍历,只是访问次序变更)
    if(T[now*2+1]!=null){
        inOrderVisit(T, now*2+1);
    }
    printf("%d ", T[now]);
    if(T[now*2+2]!=null){
        inOrderVisit(T,now*2+2);
    }
}

//中序遍历
Status inOrderTraverse(BiTree T){
    if(isEmpty(T)){
        printf("二叉树为空,无法遍历\n");
        return ERROR;
    }
    inOrderVisit(T, 0);
    printf("\n");
    return OK;
}

//后序访问输出(供后序遍历使用)
void postOrderVisit(BiTree T, int now){   //后序遍历即先遍历左子树后遍历右子树最后访问根结点(参考前序遍历,只是访问次序变更)
    if(T[now*2+1]!=null){
        postOrderVisit(T,now*2+1);
    }
    if(T[now*2+2]!=null){
        postOrderVisit(T,now*2+2);
    }
    printf("%d ", T[now]);
}

//后序遍历
Status postOrderTraverse(BiTree T){
    if(isEmpty(T)){
        printf("二叉树为空,无法遍历\n");
        return ERROR;
    }
    postOrderVisit(T, 0);
    printf("\n");
    return OK;
}

//层序遍历
Status levelOrderTraverse(BiTree T){   //即一层一层的访问元素,这里主要是判断哪些元素在哪一层
    if(isEmpty(T)){  //判断二叉树是否为空
        printf("二叉树为空,无法遍历\n");
        return ERROR;
    }
    int level = 1;   //初始为第一层
    int e;   //用于存储获取的元素数值
    for(int i=level;i<=getDepth(T);i++){   //从第一层到此二叉树的深度
        printf("第%d层:", i);   //打印当前层数
        for(int j=1;j<=pow(2,i-1);j++){   //从本层的第一个元素到本层的最后元素
            e = getValue(T, i, j);   //获取当前位置的元素数值
            printf("%d ", e);   //访问并打印当前获得的元素数值
        }
        printf("\n");
    }
    return OK;
}

//测试
int main(int argc, const char * argv[]) {
    BiTree T;
    int e;
    initTree(T);
    printf("初始化后的二叉树是否为空?(1是0否):%d\n", isEmpty(T));
    creatBTree(T);
    printf("创建完成后二叉树是否为空?(1是0否):%d\n", isEmpty(T));
    printf("前序遍历二叉树T:\n");
    preOrderTraverse(T);
    printf("中序遍历二叉树T:\n");
    inOrderTraverse(T);
    printf("后序遍历二叉树T:\n");
    postOrderTraverse(T);
    printf("层序遍历二叉树T:\n");
    levelOrderTraverse(T);
    getRoot(T, &e);
    printf("当前二叉树的根结点为:%d\n", e);
    printf("当前二叉树的深度为:%d\n", getDepth(T));
    e = getParent(T, 5);
    printf("结点5的parent为:%d\n", e);
    e = getLeftBrother(T, 5);
    printf("结点5的左兄弟为:%d\n", e);
    e = getRightBrother(T, 5);
    printf("结点5的右兄弟为:%d\n", e);
    e = getLeftChild(T, 5);
    printf("结点5的左孩子为:%d\n", e);
    e = getRightChild(T, 5);
    printf("结点5的右孩子为:%d\n", e);
    e = getValue(T, 4, 2);
    printf("获取第4层的第2个元素:%d\n", e);
    replace(T, 4, 2, 666);
    e = getValue(T, 4, 2);
    printf("将第4层的第2个元素替换为666后得:%d\n", e);
    printf("将二叉树清空后可得:\n");
    clearTree(T);
    levelOrderTraverse(T);
    return 0;
}

标签:结点,顺序,return,实现,BiTree,int,depth,二叉树
From: https://www.cnblogs.com/weiguanghao/p/17602060.html

相关文章

  • 二叉树的链式存储
    二叉树的链式存储////main.c//LinkBiTree////CreatedbyEasonon2020/8/10.//Copyright©2020Eason.Allrightsreserved.//#include<string.h>#include<stdlib.h>#include"math.h"#defineOK1#defineERROR0#defineTRUE1#d......
  • PHP实现think-queue介绍
    参考资料官方文档https://github.com/coolseven/notes/tree/master/thinkphp-queuethink-queue是ThinkPHP官方提供的一个消息队列服务,是专门支持队列服务的扩展包。think-queue消息队列适用于大并发或返回结果时间比较长且需要批量操作的第三方接口,可用于短信发送、邮件发送、APP......
  • 13.STL迭代器如何实现
    13.STL迭代器如何实现1.迭代器是一种抽象的设计理念,通过迭代器可以在不了解容器内部原理的情况下遍历容器,除此之外,STL中迭代器一个最重要的作用就是作为容器与STL算法的粘合剂。2.迭代器的作用就是提供一个遍历容器内部所有元素的接口,因此迭代器内部必须保存一个与容器相关联的......
  • 2023-08-02:给定一棵树,一共有n个点, 每个点上没有值,请把1~n这些数字,不重复的分配到二叉
    2023-08-02:给定一棵树,一共有n个点,每个点上没有值,请把1~n这些数字,不重复的分配到二叉树上,做到:奇数层节点的值总和与偶数层节点的值总和相差不超过1。返回奇数层节点分配值的一个方案。2<=n<=10^5。来自腾讯音乐。答案2023-08-02:大致步骤如下:1.计算出1到n的总和s......
  • 2023-08-02:给定一棵树,一共有n个点, 每个点上没有值,请把1~n这些数字,不重复的分配到二叉
    2023-08-02:给定一棵树,一共有n个点,每个点上没有值,请把1~n这些数字,不重复的分配到二叉树上,做到:奇数层节点的值总和与偶数层节点的值总和相差不超过1。返回奇数层节点分配值的一个方案。2<=n<=10^5。来自腾讯音乐。答案2023-08-02:大致步骤如下:1.计算出1到n的总和sum。2.确......
  • 4.智能指针的原理、常用的智能指针及实现
    4.智能指针的原理、常用的智能指针及实现1.auto_ptr当你在读这篇文章的时候,应该都有这样一个疑问?那就是为什么要使用智能指针。我们先看这样一个示例:#include<iostream>#include<string>#include<exception>usingnamespacestd;voidmemory_demo1(){ string*str......
  • 9.手写实现智能指针类需要实现哪些函数?
    9.手写实现智能指针类需要实现哪些函数?1.智能指针是一个数据类型,一般用模板实现,模拟指针行为的同时还提供自动垃圾回收机制。它会自动记录SmartPointer<T*>对象的引用计数,一旦T类型对象的引用计数为0,就释放该对象。除了指针对象外,我们还需要一个引用计数的指针设定对象的值,并将......
  • canvas实现视频播放并支持自动播放
    背景:在工作中很多时候会遇到大屏首页需要酷炫的动态背景,很多时候酷炫的动效用css和js比较难于实现。此时就会产生两种方案,第一种是采用gif,第二种会采用video方案。但是第一种方案有时候导出的gif图片往往会比较大,在首屏加载有时候会不太理想,资源比较大在加载时会出现一卡一卡......
  • 3.什么是内存池,如何实现
    3.什么是内存池,如何实现内存池(MemoryPool)是一种内存分配方式。通常我们习惯直接使用new、malloc等申请内存,这样做的缺点在于:由于所申请内存块的大小不定,当频繁使用时会造成大量的内存碎片并进而降低性能。内存池则是在真正使用内存之前,先申请分配一定数量的、大小相等(一般情......
  • jvm attach过程与底层实现
    rasp的技术重点之一是java-agent技术,通过agent可以获取到Instrumentation接口的实现,通过这个inst变量对字节码进行修改。javaagent可以在jvm启动时使用-agentjar参数启动,也可以在运行时通过attach相应进程,并且指明需要加载的jar包,就可以进入到jar包中定义好的agentmain方法处,执......