12、数据结构与算法 - 二叉树(二)顺序存储二叉树

顺序存储二叉树
 

#include <stdio.h>
#include "string.h"
#include "stdlib.h"
#include "math.h"
#include "time.h"

#define OK 1
#define ERROR 0
#define TURE 1
#define FALSE 0

#define MAXSIZE 100 //初始化分配空间
#define MAX_TREE_SIZE 100

 

typedef int Status;//函数类型,其值是返回结果状态码
typedef int CElemType;
typedef CElemType SqBiTree[MAX_TREE_SIZE];//0号存储单元根结点
CElemType Nil = 0;//设整形以0 为空 或 INT_MAX(65535)

typedef struct {
    int level;//结点层
    int order;//本层的序号(按照满二叉树给定序号规则)
}Position;

 

二叉树的基本操作

#pragma mark - 二叉树的基本操作
//1、访问
Status visit(CElemType c){
    printf("%d ",c);
    return OK;
}

//2、init 构造空二叉树T,因为T是固定数组,不会改变
Status InitBiTree(SqBiTree T){
    for (int i=0; i<MAX_TREE_SIZE; i++) {
        T[i] = Nil;
    }
    return OK;
}

//3、按层序次序输入二叉树中的结点值(字符型或整形),
Status CreateBiTree(SqBiTree T){
    int i = 0;
//    printf("按层序输入结点的值(整形),0表示空结点,输入 999 结束。结点数 <= %d\n",MAX_TREE_SIZE);
    /*
     1              -->1
     2     3        -->2
     4  5  6   7    -->3
     8  9 10        -->4
     
     1 2 3 4 5 6 7 8 9 10 Nil Nil Nil
     */
    while (i <10) {
        T[i] = i+1;
        printf("%d ",T[i]);
        
//        结点不为空,且无双亲结点
        if (i !=0 && T[(i+1)/2-1] == Nil && T[i] != Nil) {
            printf("出现了没有双亲的非根结点 %d",T[i]);
            exit(ERROR);
        }
        i++;
    }
    
//    将T的后面的结点赋值为空
    while (i < MAX_TREE_SIZE) {
        T[i] = Nil;
        i++;
    }
    printf("\n");
    return OK;
}
//技巧:
//如果想要2个函数的结果一样,但是目的不同
//在顺序存储结构中,两个函数完全一样的结果
#define ClearBiTree InitBiTree

//4、判断二叉树是否为空
//初始条件:二叉树已存在
//操作结果:若T 为空二叉树,则返回TRUE,否者返回FALSE
Status BiTreeEmpty(SqBiTree T){
//    根结点为空,则二叉树为空
    if (T[0] == Nil) {
        return TURE;
    }
    return FALSE;
}

//5、获取二叉树的深度
//初始条件:二叉树已存在
//操作结果:返回二叉树T 深度
int BiTreeDepth(SqBiTree T){
    
    int j= -1;
    int i;
    
//    找到最后一个结点
//    MAX_TREE_SIZE -> 100 -> 10 目的找到最后一个结点10 的位置
//    1 2 3 4 5 6 7 8 9 10 Nil Nil Nil ,反向遍历,找到10,然后开次方
    for (i = MAX_TREE_SIZE-1; i>=0; i--) {
        if (T[i] != Nil) {
            break;
        }
    }
    
    do{
        j++;
    }while (powl(2, j) <= i); //2 的 j 次方
    return j;
}
//pow 和 powl 一样类型不一样而已
//6、处于e位置上的结点值(e  层,本层序号)
//初始条件:二叉树T存在 e是T中某个结点(的位置)
//操作结构:返回e 处于位置(层,本层序号)的结点值
CElemType Value(SqBiTree T, Position e){
//    level -> 第几层
//    order -> 本层的序号(按照满二叉树给定的序号规则)
    printf("%d \n",(int)pow(2, e.level -1));
    printf("%d \n",e.order);
    
//    例如: 1 2 3 4  4位置对应的值是 powl(2,4-1) + 4-2 = 3  也就是 T[3]
    return T[(int)powl(2, e.level-1)+e.order-2];
}

//7、获取二叉树根结点的值
//初始条件:二叉树T存在
//操作结果:当T不为空,用e 返回T的根,返回OK;否者返回ERROR
Status Root(SqBiTree T,CElemType *e){
    if (BiTreeEmpty(T)) {
        return ERROR;
    }
    *e = T[0];
    return OK;
}

//8、给处于位置e 的结点赋值
//初始条件:二叉树存在,e是T中某个结点的位置
//操作结果:给处于位置e的结点赋值Value;
Status Assign(SqBiTree T,Position e,CElemType value){
//    找到当前e在数组中的具体位置索引
    int i = (int)powl(2, e.level-1)+e.order-2;
    
//    叶子结点的双亲为空
    if (value != Nil && T[(i+1)/2-1] == Nil) {
        return ERROR;
    }
    
//    给双亲赋值空值但是有叶子结点
    if (value == Nil && (T[i*2+1] != Nil || T[i*2+2] != Nil)) {
        return ERROR;
    }
    
    T[i] = value;
    return OK;
}

//9、获取e 的双亲
//初始条件:二叉树存在, e是T中的某一个结点
//操作结果:若e 是T的非根结点,则返回它的双亲,否者返回空
CElemType Parent(SqBiTree T,CElemType e){
//    判断树是否为空
    if (BiTreeEmpty(T)) {
        return Nil;
    }
    
    for (int i=1; i<MAX_TREE_SIZE-1; i++) {
//        找到e
        if (T[i] == e) {
//            i/2 取整 可以写成 (i+1)/2-1
            return T[(i+1)/2-1];
        }
    }
//    没有找到
    return Nil;
}

//10、获取某个结点的左孩子
//初始条件:二叉树T存在,e是某个结点
//操作结果:返回e的左孩子,若e无左孩子,则返回空
CElemType LeftChild(SqBiTree T,CElemType e){
    
//    二叉树是否为空
    if (BiTreeEmpty(T)) {
        return Nil;
    }
    
    for (int i=0; i<MAX_TREE_SIZE-1; i++) {
        if (T[i] == e) {
            return T[i*2+1];
        }
    }
    
//    没有找到
    return Nil;
}

//11、获取某个结点的右孩子
//初始条件:二叉树T存在,e是某个结点
//操作结果:返回e的右孩子,若e无右孩子,则返回空
CElemType RightChild(SqBiTree T,CElemType e){
    if (!BiTreeEmpty(T)) {
        return Nil;
    }
    
    for (int i=1; i<MAX_TREE_SIZE-1; i++) {
        if (T[i] == e) {
            return T[i*2+2];
        }
    }
    
    return Nil;
}

//12、获取结点的左兄弟
//初始条件:二叉树T存在,e是某个结点
//操作结果:返回e的左,若e无左兄弟,则返回空
CElemType LeftSibling(SqBiTree T,CElemType e){
    if (!BiTreeEmpty(T)) {
        return Nil;
    }
    
    for (int i=1; i<MAX_TREE_SIZE-1; i++) {
        /* 找到e且其序号为偶数(是右孩子) */
        if (T[i] == e && i%2 ==0){
            return T[i-1];
        }
    }
    return Nil;
}

//13、获取结点的右兄弟
//初始条件:二叉树T存在,e是某个结点
//操作结果:返回e的右,若e无右兄弟,则返回空
CElemType RightSibling(SqBiTree T,CElemType e){
    if (!BiTreeEmpty(T)) {
        return Nil;
    }
    
    for (int i=1; i<MAX_TREE_SIZE-1; i++) {
        /* 找到e且其序号为奇数(是左孩子) */
        if (T[i] == e && i%2 ==1) {
            return T[i+1];
        }
    }
    return Nil;
}

//结点的左孩子、右孩子,双亲结点

 

二叉树的遍历
            

1、层序遍历

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


 2、前序遍历

//15、前序遍历二叉树
void PreTraverse(SqBiTree T,int e){
//    打印结点数据
    visit(T[e]);
    
//    先序遍历左子树
    if(T[2*e+1] != Nil){
        PreTraverse(T, 2*e+1);
    }
    
//    最后遍历右子树
    if(T[2*e+2] != Nil){
        PreTraverse(T, 2*e+2);
    }
}

Status PreOrderTraverse(SqBiTree T){
    if(!BiTreeEmpty(T)){
        PreTraverse(T, 0);
    }
    printf("\n");
    return OK;
}
            


3、中序遍历

//16、中序遍历
void InTraverse(SqBiTree T,int e){
//    左子树不为空
    if(T[2*e+1] != Nil){
        InTraverse(T, 2*e+1);
    }
    
    visit(T[e]);
    
//    右子树不为空
    if(T[2*e+2] != Nil){
        InTraverse(T, 2*e+2);
    }
}
            
Status InOrderTraverse(SqBiTree T){
    if(!BiTreeEmpty(T)){
        InTraverse(T, 0);
    }
    printf("\n");
    return OK;
}

 

4、后续遍历

//17、后续遍历
void PostTraverse(SqBiTree T,int e){
//    左子树不为空
    if(T[2*e+1] != Nil){
        PostTraverse(T, 2*e+1);
    }
    
//    右子树不为空
    if(T[2*e+2] != Nil){
        PostTraverse(T, 2*e+2);
    }
    visit(T[e]);
}

Status PostOrderTraverse(SqBiTree T){
    if(!BiTreeEmpty(T)){
        PostTraverse(T, 0);
    }
    printf("\n");
    return OK;
}

 

验证

int main(int argc, const char * argv[]) {
    // insert code here...
    printf("二叉树顺序存储结构实现!\n");
    
    Status iStatus;
    Position p;
    CElemType e;
    SqBiTree T;
    
    InitBiTree(T);
    CreateBiTree(T);
    printf("建立二叉树后,树空否?%d(1:是 0:否) \n",BiTreeEmpty(T));
    printf("树的深度=%d\n",BiTreeDepth(T));
    
    p.level=3;
    p.order=2;
    e=Value(T,p);
    printf("第%d层第%d个结点的值: %d\n",p.level,p.order,e);
    
    
    iStatus = Root(T, &e);
    if (iStatus) {
        printf("二叉树的根为:%d\n",e);
    }else
    {
        printf("树为空,无根!\n");
    }
    
    //向树中3层第2个结点位置上结点赋值99
    e = 99;
    Assign(T, p, e);
    
    //获取树中3层第2个结点位置结点的值是多少:
    e=Value(T,p);
    printf("第%d层第%d个结点的值: %d\n",p.level,p.order,e);
    
    //找到e这个结点的双亲;
    printf("结点%d的双亲为%d_",e,Parent(T, e));
    //找到e这个结点的左右孩子;
    printf("左右孩子分别为:%d,%d\n",LeftChild(T, e),RightChild(T, e));
    //找到e这个结点的左右兄弟;
    printf("结点%d的左右兄弟:%d,%d\n",e,LeftSibling(T, e),RightSibling(T, e));
    
    
    Assign(T, p, 5);
    
    printf("二叉树T层序遍历:");
    LevelOrderTraverse(T);
    
    printf("二叉树T先序遍历:");
    PreOrderTraverse(T);
    
    printf("二叉树T中序遍历:");
    InOrderTraverse(T);
    
    printf("二叉树T后序遍历:");
    PostOrderTraverse(T);
    
    return 0;
}

结果

二叉树顺序存储结构实现!
1 2 3 4 5 6 7 8 9 10 
建立二叉树后,树空否?0(1:是 0:否) 
树的深度=4
4 
2 
第3层第2个结点的值: 5
二叉树的根为:1
4 
2 
第3层第2个结点的值: 99
结点99的双亲为2_左右孩子分别为:10,0
结点99的左右兄弟:0,0
二叉树T层序遍历:1 2 3 4 5 6 7 8 9 10 
二叉树T先序遍历:1 2 4 8 9 5 10 3 6 7 
二叉树T中序遍历:8 4 9 2 10 5 1 6 3 7 
二叉树T后序遍历:8 9 4 10 5 2 6 7 3 1 

 

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值