编程成长之路

我们都是站在父母的肩上去看他们不曾看到的风景!加油!
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

二叉树的顺序实现

Posted on 2023-08-02 22:57  来颗维C  阅读(12)  评论(0编辑  收藏  举报

二叉树的顺序实现

//
//  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;
}