二叉树实现(C语言完整代码+详细注释版)【数据结构】

注释详细完整且健壮的二叉树的顺序/链式以及线索二叉树实现与常规操作的代码:

二叉树的顺序实现

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

二叉树的链式实现

//
//  main.c
//  LinkBiTree
//
//  Created by Eason on 2020/8/10.
//  Copyright © 2020 Eason. All rights reserved.
//

#include <string.h>
#include <stdlib.h>
#include "math.h"
#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
#define MAXSIZE 100   //二叉树的最大长度
typedef char ElemType;  //二叉树的数据元素类型
typedef int Status;   //用int作为状态类型,对应预定义的OK ERROR TRUE FALSE
int i=1;   //创建二叉树时的字符串定位器
typedef char String[MAXSIZE];   //定义一个字符数组作为字符串来创建二叉树
String S;   //数组对象
typedef struct BTNode   //二叉树的链式存储结构
{
   ElemType data;
   struct BTNode *leftChild,*rightChild;
}BTNode,*BTree;   //BTree = *BTNode

//字符串初始化(将ch长度地址范围里的字符依次读入字符串中)
Status initString(String S, char *ch){
    if(strlen(ch)>=MAXSIZE){   //判断用来初始化的字符长度是否超出预定义的字符串长度
        return ERROR;
    }
    S[0] = strlen(ch);   //S[0]用来存储字符串长度
    int loc=0;   //ch定位器
    for(int i=1;i<=S[0];i++){   //依次循环读入字符串中
        S[i] = *(ch+loc);   //当前ch下一个地址的ch
        loc++;   //加到第几个位置的ch
    }
    printf("字符串初始化完成\n");
    return OK;
}

//打印字符串
Status printString(String S){   //没啥好说的就是个循环遍历打印初始化过的字符串
    for(int i=0;i<=strlen(S);i++){
        printf("%c ", S[i]);
    }
    printf("\n");
    return OK;
}
//初始化链二叉树
Status initTree(BTree *T){   //将二叉树的根结点置为空则初始化成功
    *T=NULL;
    printf("初始化成功!\n");
    return OK;
}

//判断链二叉树是否为空
Status isEmpty(BTree T){  //若二叉树的根结点为空,则此树为空
    if(T==NULL){
        return TRUE;
    }else{
        return FALSE;
    }
}

//创建链二叉树(利用初始化的字符串向二叉树中读入来创建二叉树)
void createBTree(BTree *T){
    ElemType ch;   //临时字符存储器
    ch = S[i++];   //将当前数组的位置的字符读入ch中后位置++
    if(ch=='#'){   //若字符为‘#’则说明此位置为空
        *T=NULL;   //则将此位置置为空
    }else{
        *T=(BTree)malloc(sizeof(BTNode));  //若此处的字符不为空,则为其分配一个结点大小的内存
        if(!*T){   //判断能否为新结点申请内存
            printf("内存分配失败\n");
            exit(OVERFLOW);
        }else{   //分配内存成功
            (*T)->data = ch;   //将此位置的数据置为对应的字符值
            createBTree(&(*T)->leftChild);   //递归继续寻找是否左孩子结点存在若存在则按照步骤分配内存成立对应的结点,若无则返回向下
            createBTree(&(*T)->rightChild);   //此时是若结点无左孩子则递归寻找是否是有右孩子若有则按照步骤分配内存成立对应的结点,若无则返回上一级的结点判断右孩子继续递归
        }
    }
}

//销毁二叉树(清空二叉树clearBTree()相同)
Status destroyBTree(BTree *T){
    if(*T){   //若当前结点存在
        if((*T)->leftChild){   //则判断是否有左孩子,若有则先销毁左孩子
            destroyBTree(&(*T)->leftChild);   //递归销毁左孩子
        }
        if((*T)->rightChild){   //无左孩子则判断是否有右孩子,若有则销毁右孩子
            destroyBTree(&(*T)->rightChild);   //递归销毁右孩子
        }
        free(*T);   //若都没有则释放当前结点
        *T=NULL;   //将结点置空
    }
    return OK;
}

//获得二叉树的深度
int getDepth(BTree *T){
    int deep = 0;   //深度计数
    if(*T!=NULL){   //如果当前结点不为空
        int leftdeep = getDepth(&(*T)->leftChild);   //则先判断其左子树的深度
        int rightdeep = getDepth(&(*T)->rightChild);  //然后判断右子树的深度
        deep = leftdeep>=rightdeep?leftdeep+1:rightdeep+1;   //二叉树的深度对应左右子树中最大的一个 再加上当前的深度1
    }
    return deep;   //将深度值返回
}

//获取根结点的数据
char getRoot(BTree T){
    if(isEmpty(T)){   //判断二叉树是否为空
        printf("根结点不存在,无法获取\n");
        return ERROR;
    }
    return T->data;   //若二叉树不为空,则返回当前结点的数据域
}

//获取指定结点的数据
char getValue(BTree T){
    if(isEmpty(T)){   //判断当前结点是否存在
        printf("当前结点不存在,无法获取\n");
        return ERROR;
    }
    return T->data;   //返回当前结点的数据
}

//为指定结点的数据更换数值(将结点T的数据域更换为指定的value值)
Status replaceValue(BTree *T, char *value){
    (*T)->data = *value;   //将制定的value值替换入指定结点的数据域中
    return OK;
}

//前序遍历
void preOrederTraverse(BTree T){
    if(T==NULL){    //判断当前结点是否存在,不存在则推出当前方法返回上一级,若无上一级则退出
        return;
    }
    printf("%c ", T->data);   //先访问根结点
    preOrederTraverse(T->leftChild);   //后遍历左子树
    preOrederTraverse(T->rightChild);   //最后遍历右子树
}

//中序遍历
void inOrderTraverse(BTree T){
    if(T==NULL){   //判断当前结点是否存在,不存在则推出当前方法返回上一级,若无上一级则退出
        return;
    }
    inOrderTraverse(T->leftChild);   //先遍历左子树
    printf("%c ", T->data);   //后访问根结点
    inOrderTraverse(T->rightChild);   //最后遍历右子树
}

//后序遍历
void postOrderTraverse(BTree T){
    if(T==NULL){   //判断当前结点是否存在,不存在则推出当前方法返回上一级,若无上一级则退出
        return;
    }
    postOrderTraverse(T->leftChild);    //先遍历左子树
    postOrderTraverse(T->rightChild);   //再遍历右子树
    printf("%c ", T->data);   //最后访问根结点
}


//测试
int main()
{
    BTree T;
    initTree(&T);
    initString(S, "EASO#N###H##EGO###G#O##");
    printf("字符串初始为:\n");
    printString(S);
    printf("创建二叉树T\n");
    createBTree(&T);
    printf("完成创建二叉树T\n");
    printf("二叉树的深度为:%d\n", getDepth(&T));
    printf("前序遍历二叉树T:\n");
    preOrederTraverse(T);
    printf("\n中序遍历二叉树T:\n");
    inOrderTraverse(T);
    printf("\n后序遍历二叉树T:\n");
    postOrderTraverse(T);
    printf("\n此时的根结点为:%c\n", getRoot(T));
    printf("将二叉树销毁后遍历可得:\n");
    destroyBTree(&T);
    preOrederTraverse(T);
    printf("此时的根结点为:%c\n", getRoot(T));
    return 0;
}

线索二叉树的实现

//
//  main.c
//  ThreadBTree
//
//  Created by Eason on 2020/8/16.
//  Copyright © 2020 Eason. All rights reserved.
//
//线索二叉树是将二叉树中那些未有左右孩子的结点利用起来用来指向前驱与后继结点
//线索二叉树会有一个头结点用来方便作为第一个结点的前驱与最后一个结点的后继,头结点的左孩子指向线索二叉树的根结点
#include <stdio.h>
#include <stdlib.h>
#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
#define Thread 1   //线索标志
#define Normal 0   //非线索标志
typedef char ElemType;   //二叉树数据类型
typedef int Status;   //状态变量对应OK ERROR TRUE FALSE
typedef struct TBTNode{   //线索二叉树的存储结构,多了判断孩子指针域是否为线索的判断位置
    ElemType data;   //数据域
    struct TBTNode *leftChild, *rightChild;   //左右孩子指针
    int lefttag;   //左孩子是否为线索标志 Thread为线索normal为非线索
    int righttag;   //右孩子标志同上
}TBTNode,*TBTree;   //结构别名TBTNode 指针TBTree = *TBTNode
char null = '#';   //用‘#’来表示此结点为空结点
TBTree pre;   //用在线索化过程中,一直作为刚刚访问过的结点

//创建线索二叉树(控制台输入来创建)
Status creatTBTNode(TBTree *T){
    ElemType temp;   //临时数据类型变量,用来存储控制台的输入
    scanf("%c", &temp);   //控制台输入存储临时变量temp 每次读入一个字符
    if(temp==null){   //如果当前temp为‘#’
        *T=NULL;   //则将此结点置空
    }else{
        *T = (TBTree)malloc(sizeof(TBTNode));    //若为当前结点的数据域非空则为新结点分配内存空间
        if(!*T){   //如果新结点不存在,即未能成功分配内存
            printf("内存分配失败导致结点创建失败\n");
            return ERROR;
        }
        (*T)->data = temp;   //将当前临时数据存入当前结点的数据域
        creatTBTNode(&(*T)->leftChild);   //递归创建左子树
        if((*T)->leftChild){   //若当前结点有左子树
            (*T)->lefttag=Normal;   //则将左线索标志置为Normal即非线索0
        }
        creatTBTNode(&(*T)->rightChild);   //递归创建右子树
        if((*T)->rightChild){   //若当前结点有右子树
            (*T)->righttag=Normal;   //则将右线索标志置为Normal即非线索0
        }
    }
    return OK;
}

//中序遍历线索化(从一个结点出发线索化)
void inOrderThread(TBTree T){
    if(T){   //如果结点存在
        inOrderThread(T->leftChild);   //递归线索化此结点的左子树
        if(!T->leftChild){   //若此结点不存在左孩子
            T->lefttag=Thread;   //则将此结点的左线索标志置为Thread即线索1
            T->leftChild = pre;   //将此结点的左孩子指向刚刚访问过的结点即前驱结点,即左孩子作为前驱结点的线索指向此结点的前驱结点
        }
        if(!pre->rightChild){   //若前驱结点的右孩子不存在
            pre->righttag=Thread;   //则将前驱结点的右线索标志置为Thread即线索1
            pre->rightChild = T;   //将前驱结点的右孩子指向当前结点即后继结点,即右孩子作为后继结点的线索指向此结点的后继结点
        }
        pre = T;   //完成后此结点作为前驱结点之后再次循环进行做准备
        inOrderThread(T->rightChild);   //递归线索化此结点的右子树
    }
}

//中序遍历线索化二叉树T(head为指向线索二叉树T根结点的头结点)
Status threadBTree(TBTree *head, TBTree T){
    *head = (TBTree)malloc(sizeof(TBTNode));   //为头结点分配内存空间
    if(!*head){   //若为头结点分配内存空间失败
        printf("头结点内存分配失败\n");
        return ERROR;
    }
    (*head)->lefttag=Normal;   //头结点的左线索标志为Normal 因为左孩子指向二叉树的根结点
    (*head)->righttag=Thread;   //头结点的右线索标志为Thread 因为其指向二叉树遍历的最后一个结点,即为最后一个结点的后继结点
    (*head)->rightChild=(*head);   //初始化为指向指向自己的后继结点
    if(!T){   //如果当前二叉树不存在
        (*head)->rightChild=*head;   //头结点的左孩子也指向自己,说明只有指向自己的头结点而无二叉树
    }else{
        (*head)->leftChild=T;   //如果二叉树存在,则头结点指向此二叉树的根结点
        pre = (*head);   //当前刚刚访问的为头结点(这点可以看出头结点的作用,方便对二叉树所有结点都执行相同的线索化操作,即便是第一个还是最后一个结点)
        inOrderThread(T);   //中序线索化二叉树T
        pre->righttag=Thread;   //中序二叉树后pre指向的中序遍历二叉树的最后一个结点
        pre->rightChild=*head;   //则最后一个结点的右孩子指向头结点,即后继结点为头,变成了一个循环链表
        (*head)->rightChild=pre;   //头结点的右孩子也指向遍历二叉树的最后一个结点,
    }
    return OK;
    
}

//中序遍历输出二叉树T(从线索二叉树的头结点开始)
Status inOrderTraverse(TBTree H){
    TBTree T;   //定义结点T作为二叉树的根结点
    T=H->leftChild;   //头结点的左孩子即为树的根结点
    while(H!=T){   //若不是指向头指针自身,即表示当前二叉树存在
        while(T->lefttag==Normal){   //如果当前左线索标志为Normal表示当前右左孩子结点
            T = T->leftChild;   //则指向左孩子结点,即先访问左孩子结点(即先遍历二叉树的左子树)
        }
        printf("%c ", T->data);   //访问当前结点的数据域
        while(T->righttag==Thread && T->rightChild!=H){   //如果右线索标志为Thread则表示右孩子表示的为后继结点
            T = T->rightChild;   //则指向此后继结点
            printf("%c ", T->data);   //访问当前结点的后继结点
        }
        T = T->rightChild;   //继续循环遍历右子树
    }
    return OK;
}

//测试
int main(int argc, const char * argv[]) {
    TBTree H, T;
    printf("请按前序顺序输入要创建的二叉树序列('#'为空):\n");  //例如:EOAE##S##HN###OT##P##
    creatTBTNode(&T);
    threadBTree(&H, T);
    printf("中序遍历线索二叉树:\n");
    inOrderTraverse(H);
    printf("\n");
    return 0;
}

参考:
《大话数据结构》

  • 41
    点赞
  • 170
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
数据结构》(C语言)是为“数据结构”课程编写的教材,也可作为学习数据结构及其算法的C程序设计的参数教材。 本书的前半部分从抽象数据类型的角度讨论各种基本类型的数据结构及其应用;后半部分主要讨论查找和排序的各种实现方法及其综合分析比较。其内容和章节编排 1992年4月出的《数据结构》(第二)基本一致,但在本书中更突出了抽象数据类型的概念。全书采用类C语言作为数据结构和算法的描述语言。 本书概念表述严谨,逻辑推理严密,语言精炼,用词达意,并有配套出的《数据结构题集》(C语言),便于教学,又便于自学。 数据结构是计算机和信息技术类相关专业的一门重要的专业基础课程。本教材结合数据结构课程的现状和发展趋势,具有难度适中、结构合理、应用性强的特点。 全书共分10章,其中第1章是数据结构基础,介绍了数据结构的基本概念;第2~5章主要讨论几种基本的线性结构,即线性表、栈和队列、串、数组和广义表;第6~7章主要介绍非线性结构,即树和二叉树、图;第8~9章主要讨论两种基本的运算,即查找和排序;第10章主要介绍文件。, 全书采用C语言作为数据结构和算法的描述语言,对数据结构的定义和算法的描述详细,代码注释完整,便于初学者模仿训练,循序渐进地获得稳步提高。本书既可作为高等学校计算机科学与技术、软件工程和通信工程等信息类专业的本、专科学生教材,也可供软件设计人员参考使用。
全集内容结构如下: ├─图 │ ├─关键路径(有向无环图及其应用2) │ │ 1.txt │ │ ALGraph.cpp │ │ ALGraph.h │ │ CriticalPath.cpp │ │ CriticalPath.h │ │ InfoType.cpp │ │ InfoType.h │ │ LinkList.cpp │ │ LinkQueue.cpp │ │ LinkQueue.h │ │ Main.cpp │ │ SqStack.cpp │ │ SqStack.h │ │ Status.h │ │ VertexType.cpp │ │ VertexType.h │ │ │ ├─图的关节点 │ │ 1.txt │ │ ALGraph.cpp │ │ ALGraph.h │ │ FindArticul.cpp │ │ FindArticul.h │ │ InfoType.cpp │ │ InfoType.h │ │ LinkList.cpp │ │ LinkQueue.cpp │ │ LinkQueue.h │ │ main.cpp │ │ Status.h │ │ VertexType.cpp │ │ VertexType.h │ │ │ ├─图的数组表示法 │ │ InfoType.cpp │ │ InfoType.h │ │ Main.cpp │ │ MGraph.cpp │ │ MGraph.h │ │ Status.h │ │ VertexType.cpp │ │ VertexType.h │ │ │ ├─图的遍历 │ │ ALGraph.cpp │ │ ALGraph.h │ │ DEBUG.txt │ │ InfoType.cpp │ │ InfoType.h │ │ LinkList.cpp │ │ LinkQueue.cpp │ │ LinkQueue.h │ │ Main.cpp │ │ MGraph.cpp │ │ MGraph.h │ │ MTraverse.cpp │ │ MTraverse.h │ │ Status.h │ │ t1.txt │ │ t2.txt │ │ VertexType.cpp │ │ VertexType.h │ │ │ ├─图的邻接表存储结构 │ │ ALGraph.cpp │ │ ALGraph.h │ │ InfoType.cpp │ │ InfoType.h │ │ LinkList.cpp │ │ LinkQueue.cpp │ │ LinkQueue.h │ │ Main.cpp │ │ Status.h │ │ t1.txt │ │ t2.txt │ │ VertexType.cpp │ │ VertexType.h │ │ │ ├─最短路径(从某个源点到其余各顶点的的最短路径) │ │ 1.txt │ │ 2.txt │ │ InfoType.cpp │ │ InfoType.h │ │ Main.cpp │ │ MGraph.cpp │ │ MGraph.h │ │ ShortestPath_DIJ.cpp │ │ ShortestPath_DIJ.h │ │ Status.h │ │ VertexType.cpp │ │ VertexType.h │ │ │ └─最短路径(每一对顶点间的最短路径) │ 1.txt │ 2.txt │ InfoType.cpp │ InfoType.h │ Main.cpp │ map.txt │ MGraph.cpp │ MGraph.h │ RailwaySearch.cpp │ ShortestPath_FLOYD.cpp │ ShortestPath_FLOYD.h │ Status.h │ VertexType.cpp │ VertexType.h │ ├─排序 │ ├─冒泡排序 │ │ 1.txt │ │ main.cpp │ │ RedType.cpp │ │ RedType.h │ │ Sq_BubbleSort.cpp │ │ Sq_BubbleSort.h │ │ │ ├─哈希表(哈希查找) │ │ ElemType.cpp │ │ ElemType.h │ │ HashTable.cpp │ │ HashTable.h │ │ main.cpp │ │ Records.txt │ │ │ ├─基数排序 │ │ 1.txt │ │ main.cpp │ │ SLL_RadixSort.cpp │ │ SLL_RadixSort.h │ │ │ ├─归并排序 │ │ 1.txt │ │ main.cpp │ │ RedType.cpp │ │ RedType.h │ │ sq_MergeSort.cpp │ │ sq_MergeSort.h │ │ │ ├─快速排序 │ │ 1.txt │ │ 2.txt │ │ 3.txt │ │ main.cpp │ │ RedType.cpp │ │ RedType.h │ │ Sq_QuitSort.cpp │ │ Sq_QuitSort.h │ │ │ ├─拓扑排序(有向无环图及其应用) │ │ 1.txt │ │ ALGraph.cpp │ │ ALGraph.h │ │ InfoType.cpp │ │ InfoType.h │ │ LinkList.cpp │ │ LinkQueue.cpp │ │ LinkQueue.h │ │ Main.cpp │ │ SqStack.cpp │ │ SqStack.h │ │ Status.h │ │ TopologicalSort.cpp │ │ TopologicalSort.h │ │ VertexType.cpp │ │ VertexType.h │ │ │ ├─插入排序 │ │ 1.txt │ │ main.cpp │ │ RedType.cpp │ │ RedType.h │ │ Sq_InsertSort.cpp │ │ Sq_InsertSort.h │ │ │ ├─插入排序(希尔排序) │ │ main.cpp │ │ RedType.cpp │ │ RedType.h │ │ Sq_InsertSort.cpp │ │ Sq_InsertSort.h │ │ │ ├─插入排序(表插入排序) │ │ 1.txt │ │ main.cpp │ │ RedType.cpp │ │ RedType.h │ │ SL_InsertSort.cpp │ │ SL_InsertSort.h │ │ │ ├─选择排序(堆排序) │ │ 1.txt │ │ 2.txt │ │ 3.txt │ │ main.cpp │ │ RedType.cpp │ │ RedType.h │ │ Sq_HeapSort.cpp │ │ Sq_HeapSort.h │ │ │ ├─选择排序(树形选择排序) │ │ 1.txt │ │ main.cpp │ │ RedType.cpp │ │ RedType.h │ │ Sq_TreeSelectionSort.cpp │ │ Sq_TreeSelectionSort.h │ │ │ └─选择排序(简单选择排序) │ 1.txt │ main.cpp │ RedType.cpp │ RedType.h │ Sq_SelectSort.cpp │ Sq_SelectSort.h │ ├─查找 │ ├─动态查找表(二叉排序树) │ │ 1.txt │ │ BiTree.cpp │ │ BiTree.h │ │ DElemType.cpp │ │ DElemType.h │ │ DSTable.cpp │ │ DSTable.h │ │ LinkQueue.cpp │ │ LinkQueue.h │ │ main.cpp │ │ QElemType.h │ │ Status.h │ │ TElmeType.h │ │ │ ├─平衡二叉树(二叉排序树的平衡旋转生成) │ │ 1.txt │ │ BBSTree.cpp │ │ BBSTree.h │ │ BiTree.cpp │ │ BiTree.h │ │ DElemType.cpp │ │ DElemType.h │ │ DSTable.cpp │ │ DSTable.h │ │ LinkQueue.cpp │ │ LinkQueue.h │ │ main.cpp │ │ QElemType.h │ │ Status.h │ │ TElmeType.h │ │ │ ├─平衡的m路查找树—B_树 │ │ BTree.cpp │ │ BTree.h │ │ main.cpp │ │ Record.h │ │ Status.h │ │ │ ├─键树(Trie树) │ │ 1.txt │ │ main.cpp │ │ Record.h │ │ Status.h │ │ TrieTree.cpp │ │ TrieTree.h │ │ │ ├─键树(双链键树) │ │ 1.txt │ │ DLTree.cpp │ │ DLTree.h │ │ main.cpp │ │ Record.h │ │ Status.h │ │ │ ├─静态查找表(有序表的查找) │ │ 1.txt │ │ main.cpp │ │ SElemType.cpp │ │ SElemType.h │ │ SSTable.cpp │ │ SSTable.h │ │ Status.h │ │ │ ├─静态查找表(静态树表查找) │ │ 1.txt │ │ BiTree.cpp │ │ BiTree.h │ │ LinkQueue.cpp │ │ LinkQueue.h │ │ main.cpp │ │ QElemType.h │ │ SElemType.cpp │ │ SElemType.h │ │ SSTable.cpp │ │ SSTable.h │ │ Status.h │ │ TElmeType.h │ │ │ └─静态查找表(顺序表的查找) │ 1.txt │ main.cpp │ SElemType.cpp │ SElemType.h │ SSTable.cpp │ SSTable.h │ Status.h │ ├─树 │ ├─二叉树的二叉链表存储 │ │ BiTree.cpp │ │ BiTree.h │ │ LinkQueue.cpp │ │ LinkQueue.h │ │ main.cpp │ │ QElemType.h │ │ Status.h │ │ TElmeType.h │ │ │ ├─二叉树的顺序存储结构 │ │ main.cpp │ │ SqBiTree.cpp │ │ SqBiTree.h │ │ Status.h │ │ TELemType_define.cpp │ │ │ ├─哈夫曼树和哈夫曼编码 │ │ HuffmanTree.cpp │ │ HuffmanTree.h │ │ main.cpp │ │ Status.h │ │ │ ├─最小生成树 │ │ 1.txt │ │ InfoType.cpp │ │ InfoType.h │ │ Main.cpp │ │ MGraph.cpp │ │ MGraph.h │ │ MiniSpanTree_Kruskal.cpp │ │ MiniSpanTree_Kruskal.h │ │ MiniSpanTree_PRIM.cpp │ │ MiniSpanTree_PRIM.h │ │ Status.h │ │ VertexType.cpp │ │ VertexType.h │ │ │ ├─树的二叉链表 │ │ CSTree.cpp │ │ CSTree.h │ │ LinkQueue.cpp │ │ LinkQueue.h │ │ main.cpp │ │ QElemType.h │ │ Status.h │ │ TElmeType.h │ │ │ ├─深度优先生成森林(无向图的连通性和生成树) │ │ ALGraph.cpp │ │ ALGraph.h │ │ CSTree.cpp │ │ CSTree.h │ │ DFSForest.cpp │ │ DFSForest.h │ │ InfoType.cpp │ │ InfoType.h │ │ LinkList.cpp │ │ LinkQueue.cpp │ │ LinkQueue.h │ │ Main.cpp │ │ QElemType.h │ │ Status.h │ │ TElmeType.h │ │ VertexType.cpp │ │ VertexType.h │ │ │ └─线索二叉树BiThrTree.cpp │ BiThrTree.h │ main.cpp │ Status.h │ TElmeType.h │ └─表和数组 ├─KMP算法 │ Basic_operation_functions.h │ def_SString.h │ KMP.h │ main.cpp │ Status.h │ ├─n阶对称矩阵的压缩存储 │ Basic_operation_functions.h │ mian.cpp │ Status.h │ struct SyMatrix.h │ ├─三元组稀疏矩阵的压缩存储 │ Basic_operation_functions.h │ B_opera_fun_called_fun.h │ main.cpp │ Status.h │ struct TSMatrix.h │ Universal_main.h │ Universa_ts_b_opera_fun.h │ ├─不设头结点的单链表 │ LinkList.cpp │ LinkList.h │ main.cpp │ Status.h │ ├─串的堆存储结构 │ Basic_operation_functions.h │ HString.h │ Line_List.h │ main.cpp │ Status.h │ ├─串的定长顺序存储结构 │ Basic_operation_functions.h │ def_SString.h │ Main.cpp │ Status.h │ ├─广义表 │ GList.cpp │ GList.h │ main.cpp │ SString.cpp │ SString.h │ Status.h │ ├─数组 │ Basic_operation_functions.h │ main.cpp │ Status.h │ struct array.h │ ├─文本编辑(串和行表操作) │ Basic_operation_functions.h │ HString.h │ Line_List.h │ main.cpp │ Status.h │ ├─栈的顺序存储结构 │ main.cpp │ SqStack.cpp │ SqStack.h │ Status.h │ ├─走迷宫 │ Basic_called_functions.h │ Basic_operation_functions.h │ Main_Maze.cpp │ Status.h │ struct SqStack.h │ └─链队列 Basic_called_functions.cpp Basic_called_functions.h Basic_operation_functions.cpp main.cpp QElemType.h Status.h Struct_LinkQueue.h
以下是交换二叉树每个节点的左孩子和右孩子的C语言代码及注释: ```c #include <stdio.h> #include <stdlib.h> // 二叉树节点结构体 typedef struct TreeNode { int val; struct TreeNode* left; struct TreeNode* right; } TreeNode; // 创建二叉树(手动输入) TreeNode* createBinaryTree() { int val; printf("请输入节点的值(-1表示该节点为空):"); scanf("%d", &val); if (val == -1) { return NULL; } TreeNode* root = (TreeNode*)malloc(sizeof(TreeNode)); root->val = val; root->left = createBinaryTree(); root->right = createBinaryTree(); return root; } // 交换二叉树每个节点的左孩子和右孩子 void swapLeftAndRight(TreeNode* root) { if (root == NULL) { return; } // 交换左孩子和右孩子 TreeNode* temp = root->left; root->left = root->right; root->right = temp; // 递归处理左子树 swapLeftAndRight(root->left); // 递归处理右子树 swapLeftAndRight(root->right); } // 中序遍历二叉树(用于验证交换结果) void inorderTraversal(TreeNode* root) { if (root == NULL) { return; } inorderTraversal(root->left); printf("%d ", root->val); inorderTraversal(root->right); } int main() { // 创建二叉树 TreeNode* root = createBinaryTree(); // 交换二叉树每个节点的左孩子和右孩子 swapLeftAndRight(root); // 中序遍历二叉树(用于验证交换结果) inorderTraversal(root); return 0; } ``` 注:以上代码中,使用了二叉树的中序遍历来验证交换结果是否正确。如果交换成功,中序遍历的结果应该是一个完全颠倒的二叉树

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值