数据结构复习:线索二叉树的实现

#include <stdio.h>
#include <stdlib.h>

//线索二叉树实现
//利用空闲的n+1个空链域 解决 中序、先序、后序访问序列的 某个结点找前驱 和 找和后继的问题
typedef struct {
    int value;
} ElemType;
typedef struct ThreadNode {
    ElemType data;
    struct ThreadNode *lchild, *rchild;
    int ltag = 0, rtag = 0;//左有标志位 为0的时候为指向左右孩子结点,为1的时候表示指针是线索
    struct ThreadNode *parent;
} BiTNode, ThreadNode, *BiTree, *ThreadTree;

//初始化一颗空树
void InitBiTNode(BiTree &bt) {
    bt = NULL;
}


ThreadNode *pre = NULL;//全局变量 pre 指向当前访问结点的前驱

void visit(ThreadNode *q) {
    printf("%d ", q->data);
    //pre此时指向的是当前访问结点的前驱
    if (q->lchild == NULL) { //当前结点的 左孩子为不存在
        q->lchild = pre; //设置 q 的左线索 指向 pre
        q->ltag = 1;
    }
    if (pre != NULL && pre->rchild == NULL) {//前驱结点的右孩子如果为空
        pre->rchild = q; // 设置前驱结点的 右线索指向 q
        pre->rtag = 1; //修改标志位
    }
    pre = q;
}

//中序线索化
void InThread(ThreadTree &T) {
    if (T != NULL) {
        InThread(T->lchild);
        visit(T);
        InThread(T->rchild);
    }
}

//创建中序线索化
void CreateInThread(ThreadTree T) {
    printf("构建中序线索二叉树\n");
    pre = NULL;//pre指针指向NULL
    if (T != NULL) {
        InThread(T);//中序线索化
        if (pre->rchild == NULL) {//如果最后一个访问结点没有右孩子,设置 右线索为 NULL,同时修改标志位
            pre->rtag = 1;
        }
    }
    printf("\n");
}

//找到p为根的子树中,第一个被中序遍历的结点
ThreadNode *InFirstNode(ThreadNode *p) {
    while (p->ltag == 0) {
        p = p->lchild;
    }
    return p;
}

//中序线索二叉树中找到结点p的后继结点
ThreadNode *InNextNode(ThreadNode *p) {
    if (p->rtag == 0) {
        //中序遍历顺序为左 根 右
        //下一个要访问的结点为 右子树 最左边的结点
        return InFirstNode(p->rchild);//左子树中最左下结点
    } else {
        return p->rchild;
    }
}

//对中序线索二叉树进行中序遍历(利用线索实现的非递归算法)
void Inorder(ThreadNode *T) {

    for (ThreadNode *p = InFirstNode(T); p != NULL; p = InNextNode(p)) {
        printf("%d ", p->data);
    }
    printf("\n");
}

//找到p为根的子树中,最后一个被中序遍历的结点
ThreadNode *InLastNode(ThreadNode *p) {
    while (p->rtag == 0) {
        p = p->rchild;
    }
    return p;
}

//中序线索二叉树中找到结点p的前驱结点
ThreadNode *InPreNode(ThreadNode *p) {
    if (p->ltag == 0) {
        //中序遍历顺序为根 左 右
        //当前结点为结点,前一个被访问的结点为左子树中最靠右的结点
        return InLastNode(p->lchild);//左子树中最左下结点
    } else {
        return p->lchild;
    }
}

//对中序线索二叉树进行逆向中序遍历(利用线索实现的非递归算法)
void RevInorder(ThreadNode *T) {

    for (ThreadNode *p = InLastNode(T); p != NULL; p = InPreNode(p)) {
        printf("%d ", p->data);
    }
    printf("\n");
}

//先序线索化
void PreThread(ThreadTree T) {
    if (T != NULL) {
        visit(T);
        if (T->ltag == 0) {//防止T的指针左指针被修改为前驱线索而产生循环
            PreThread(T->lchild);
        }
        if (T->rtag == 0) {
            PreThread(T->rchild);
        }

    }
}

//创建先序线索化
void CreatePreThread(ThreadTree T) {
    printf("构建先序线索二叉树\n");
    pre = NULL;//pre指针指向NULL
    if (T != NULL) {
        PreThread(T);//中序线索化
        if (pre->rchild == NULL) {//如果最后一个访问结点没有右孩子,设置 右线索为 NULL,同时修改标志位
            pre->rtag = 1;
        }
    }
    printf("\n");
}

//先序线索二叉树中找到结点p的后继结点
ThreadNode *PreNextNode(ThreadNode *p) {
    if (p->rtag == 0) {
        //先序遍历顺序为根 右 左
        //一定有右孩子
        if (p->ltag == 0 && p->lchild != NULL) {//如果有左孩子,先序后继为左孩子
            return p->lchild;
        } else {
            return p->rchild;
        }
    } else { //如果是线索
        return p->rchild;
    }
}

ThreadNode *LeftDeepestNode(ThreadNode *p);

ThreadNode *RightDeepestNode(ThreadNode *p);

//因为先序遍历顺序为根 左 右,所有,如果 p->ltg == 0时候,无法通过找到前驱,需要通过重新遍历或者三叉链表实现
//三叉链表寻找先序线索前驱结点
ThreadNode *PrePreNode(ThreadTree root, ThreadNode *p) {
    if (p->ltag == 0) {
        //4.如果p 是根结点,没有前驱
        if (p == root)
            return NULL;
        if (p->parent != NULL) {
            ThreadNode *parent = p->parent;
            //先序访问顺序:根 左 右
            //1.如果p结点为父结点的左孩子,那么父结点为前驱结点
            //2.如果p结点为右孩子,且左兄弟为NULL,那么父结点为前驱结点
            if (parent->lchild == p ||
                (parent->lchild == NULL && parent->rchild == p)) {
                return parent;
            } else {
                //3.如果p是右孩子,且左兄弟非空
                //找到左兄弟子树中按照先序遍历最后一个访问的结点
                //先往右走,右边没了往左走,左边没了往右走,直到找到最深处的叶子结点
                return RightDeepestNode(parent->lchild);
            }
        } else {
            return NULL;
        }
    } else {
        return p->lchild;
    }
}


//后序线索化
void PostThread(ThreadTree &T) {
    if (T != NULL) {
        PostThread(T->lchild);
        PostThread(T->rchild);
        visit(T);
    }
}

//创建后序线索化
void CreatePostThread(ThreadTree &T) {
    printf("构建后序线索二叉树\n");
    pre = NULL;//pre指针指向NULL
    if (T != NULL) {
        PostThread(T);//中序线索化
        if (pre->rchild == NULL) {//如果最后一个访问结点没有右孩子,设置 右线索为 NULL,同时修改标志位
            pre->rtag = 1;
        }
    }
    printf("\n");
}

//后序线索找前驱
ThreadNode *PostPreNode(ThreadNode *p) {
    if (p->ltag == 0) {
        //p 一定有左孩子
        //因为后序访问顺序为: 左 右 根
        //若p 有右孩子结点q,那么前驱为按照后序遍历最后一个访问的结点
        //如果q没有孩子,那么前驱就是q,如果q有孩子,按照后序遍历访问顺序 左右根,在q这颗子树中,q为根结点,所有前驱是q
        if (p->rtag == 0 && p->rchild != NULL) {
            return p->rchild;
        } else {
            //如果p 没有右孩子,那么前驱为左孩子
            return p->lchild;
        }
    } else {
        return p->lchild;
    }
}


ThreadNode *RightDeepestNode(ThreadNode *p) {
    while (p->rtag == 0) {
        p = p->rchild;
    }
    if (p->ltag == 1) {
        return p;
    } else {
        return LeftDeepestNode(p);
    }

}

ThreadNode *LeftDeepestNode(ThreadNode *p) {
    while (p->ltag == 0) { //寻找最左边的结点
        p = p->lchild;
    }
    if (p->rtag == 1) { // 如果该结点没有右结点
        return p;
    } else {
        return RightDeepestNode(p);
    }
}
//因为后序遍历顺序为左 右 根,所有,如果 p->rtg == 0时候,无法通过找到后继,需要通过重新遍历或者三叉链表实现

//三叉链表寻找后序线索后继结点
ThreadNode *PostPostNode(ThreadTree root, ThreadNode *p) {
    if (p->rtag == 0) {
        //4.如果p 是根结点,没有前驱
        if (p == root)
            return NULL;
        if (p->parent != NULL) {
            ThreadNode *parent = p->parent;
            //后序访问顺序:左 右 根
            //1.如果p结点为父结点的右孩子,那么父结点为前驱结点
            //2.如果p结点为左孩子,且右兄弟为NULL,那么父结点为前驱结点

            if (parent->rchild == p ||
                (parent->rchild == NULL && parent->lchild == p)) {
                return parent;
            } else {
                //3.如果p是左孩子,且右兄弟非空
                //找到右兄弟子树中按照后序遍历第一个访问的结点
                //先往左走,左边没了往右走,右边没了往左走,直到找到最深处的叶子结点
                return LeftDeepestNode(parent->rchild);
            }
        } else {
            return NULL;
        }
    } else {
        return p->rchild;
    }
}

int main() {

    BiTree bt;
    InitBiTNode(bt);

    //插入根结点
    BiTNode *root = (BiTNode *) malloc(sizeof(BiTNode));


    root->data = {1};
    root->lchild = NULL;
    root->rchild = NULL;
    root->ltag = 0;
    root->rtag = 0;

    bt = root;

    BiTNode *t1 = (BiTNode *) malloc(sizeof(BiTNode));
    t1->data = {6};
    t1->ltag = 0;
    t1->rtag = 0;
    root->lchild = t1;

    BiTNode *t11 = (BiTNode *) malloc(sizeof(BiTNode));
    t11->data = {3};
    t11->ltag = 0;
    t11->rtag = 0;

    t1->lchild = t11;
    t11->lchild = NULL;
    t11->rchild = NULL;

    BiTNode *t12 = (BiTNode *) malloc(sizeof(BiTNode));
    t12->data = {9};
    t12->ltag = 0;
    t12->rtag = 0;
    t1->rchild = t12;

    BiTNode *t121 = (BiTNode *) malloc(sizeof(BiTNode));
    t121->data = {8};
    t121->ltag = 0;
    t121->rtag = 0;
    t12->lchild = t121;
    t12->rchild = NULL;

    BiTNode *t1211 = (BiTNode *) malloc(sizeof(BiTNode));
    t1211->data = {7};
    t1211->ltag = 0;
    t1211->rtag = 0;

    t1211->lchild = NULL;
    t1211->rchild = NULL;
    t121->lchild = t1211;
    t121->rchild = NULL;


    BiTNode *t2 = (BiTNode *) malloc(sizeof(BiTNode));
    t2->data = {13};
    t2->ltag = 0;
    t2->rtag = 0;
    root->rchild = t2;

    BiTNode *t21 = (BiTNode *) malloc(sizeof(BiTNode));
    t21->data = {11};
    t21->ltag = 0;
    t21->rtag = 0;
    t2->lchild = t21;


    BiTNode *t211 = (BiTNode *) malloc(sizeof(BiTNode));
    t211->data = {10};
    t211->ltag = 0;
    t211->rtag = 0;
    t21->lchild = t211;
    t211->lchild = NULL;
    t211->rchild = NULL;

    t21->rchild = NULL;

    BiTNode *t22 = (BiTNode *) malloc(sizeof(BiTNode));
    t22->data = {14};
    t22->ltag = 0;
    t22->rtag = 0;
    t2->rchild = t22;
    t22->lchild = NULL;
    t22->rchild = NULL;

    root->parent = NULL; //1
    t1->parent = root;//1->6 左
    t2->parent = root;//1->13 右

    t11->parent = t1;//6->3 左
    t12->parent = t1;//6->9 有
    t121->parent = t12; //9->8 左
    t1211->parent = t121;//8->7 左

    t21->parent = t2;//13->11 左
    t22->parent = t2;//13->14 右
    t211->parent = t21;//11->10 左





    ThreadNode *t0 = t121;


//    CreateInThread(bt);
//    ThreadNode *n1 = InPreNode( t0);
//    ThreadNode *n2 = InNextNode(t0);
//    if (n1 != NULL && n2 != NULL) {
//        printf("%d 的线索前驱结点:%d,线索后继结点:%d\n", t0->data, n1->data, n2->data);
//    } else if (n1 == NULL && n2 != NULL) {
//        printf("%d 的线索后继结点:%d\n", t0->data, n2->data);
//    } else if (n1 != NULL && n2 == NULL) {
//        printf("%d 的线索前驱结点:%d\n", t0->data, n1->data);
//    }
//    printf("对中序线索二叉树进行中序遍历(利用线索实现的非递归算法):\n");
//    Inorder(bt);
//    printf("对中序线索二叉树进行逆向中序遍历(利用线索实现的非递归算法):\n");
//    RevInorder(bt);



//    CreatePreThread(bt);
//    ThreadNode *n1 = PrePreNode(root, t0);
//    ThreadNode *n2 = PreNextNode(t0);
//
//    if (n1 != NULL && n2 != NULL) {
//        printf("%d 的线索前驱结点:%d,线索后继结点:%d\n", t0->data, n1->data, n2->data);
//    } else if (n1 == NULL && n2 != NULL) {
//        printf("%d 的线索后继结点:%d\n", t0->data, n2->data);
//    } else if (n1 != NULL && n2 == NULL) {
//        printf("%d 的线索前驱结点:%d\n", t0->data, n1->data);
//    }



    CreatePostThread(bt);
    ThreadNode *n1 = PostPreNode(t0);
    ThreadNode *n2 = PostPostNode(root, t0);

    if (n1 != NULL && n2 != NULL) {
        printf("%d 的线索前驱结点:%d,线索后继结点:%d\n", t0->data, n1->data, n2->data);
    } else if (n1 == NULL && n2 != NULL) {
        printf("%d 的线索后继结点:%d\n", t0->data, n2->data);
    } else if (n1 != NULL && n2 == NULL) {
        printf("%d 的线索前驱结点:%d\n", t0->data, n1->data);
    }
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值