数据结构(C语言)-- 线索二叉树

 线索二叉树
 * 线性结构有前驱有后继。我们使用线索将二叉树转换成类似的线性结构
 * 什么是线索?线索其实就是将节点连在一起的指针;
 * 如果一个二叉树有 n 个节点,那么有多少个指针指向这些节点?
 * 有 n-1 个指针指向他们。
 * 一共有多少个指针?
 * 有 2n 个指针,2n - (n - 1) = n + 1 个指针没有用
 * 利用这个n + 1个指针,来指向我们二叉树遍历序列当中的前驱和后继。

以此二叉树为例:

 

 

前序遍历算法代码:

先序线索二叉树:是指如果节点没有左右孩子,则指针指向先序遍历的前驱和后继
 * 左 --> 前驱
 * 右 --> 后继

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

typedef struct TreeNode
{
    char data;
    struct TreeNode *leftChild;
    struct TreeNode *rightChild;
    int leftTag;  // 0 --> 指向Child
    int rightTag; // 0 --> 指向Child
} TreeNode;

// 当字符为 # 时 --> 空节点
void createTree(TreeNode **T, const char *data, int *index) // 以先序遍历创建
{
    char ch;
    ch = data[*index];
    *index += 1;
    if (ch == '#')
    {
        // 此时为空节点
        *T = NULL;
    }
    else
    {
        // 此时不为空
        *T = (TreeNode *)malloc(sizeof(TreeNode));
        (*T)->data = ch;
        (*T)->leftTag = 0;
        (*T)->rightTag = 0;
        // 创建左子树,逻辑一致,进行递归
        createTree(&((*T)->leftChild), data, index);
        // 创建右子树,逻辑一致,进行递归
        createTree(&((*T)->rightChild), data, index);
    }
}

void preThreadTree(TreeNode *T, TreeNode **pre)
{
    if (T != NULL)
    {
        if (T->leftChild == NULL) // 左孩子为空,则 左孩子可以指向前驱
        {
            T->leftTag = 1;
            T->leftChild = *pre;
        }
        if (*pre != NULL && (*pre)->rightChild == NULL)
        {
            (*pre)->rightTag = 1;
            (*pre)->rightChild = T;
        }

        *pre = T;
        if (T->leftTag == 0) // 是有左孩子的
        {
            preThreadTree(T->leftChild, pre);
        }

        preThreadTree(T->rightChild, pre);
    }
}

TreeNode *getNext(TreeNode *node)
{
    if (node->rightTag == 1)
    {
        return node->rightChild;
    }
    else
    {
        if (node->leftTag == 0)
        {
            return node->leftChild;
        }
        else
        {
            return node->rightChild;
        }
    }
    return node->leftChild;
}

void print(TreeNode *T) // 前序遍历
{
    for (TreeNode *node = T; node != NULL; node = getNext(node))
    {
        printf("%c ", node->data);
    }
}

int main(int argc, char const *argv[])
{
    TreeNode *T;
    TreeNode *pre = NULL;
    int index = 0;
    createTree(&T, argv[1], &index);
    preThreadTree(T, &pre);
    pre->rightTag = 1;
    pre->rightChild = NULL;
    printf("前序遍历,线索二叉树 > ");
    print(T);
    putchar(10);
    printf("----------------------------------------------------------\n");
    return 0;
}

运行结果:

superlan@GodFather:~/C_Language/data_structure$ ./a.out ABD#F##E##C##
前序遍历,线索二叉树 > A B D F E C 
----------------------------------------------------------

中序遍历算法代码:

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

typedef struct TreeNode
{
    char data;
    struct TreeNode *leftChild;
    struct TreeNode *rightChild;
    int leftTag;  // 0 --> 指向Child
    int rightTag; // 0 --> 指向Child
} TreeNode;

// 当字符为 # 时 --> 空节点
void createTree(TreeNode **T, const char *data, int *index) // 以先序遍历创建
{
    char ch;
    ch = data[*index];
    *index += 1;
    if (ch == '#')
    {
        // 此时为空节点
        *T = NULL;
    }
    else
    {
        // 此时不为空
        *T = (TreeNode *)malloc(sizeof(TreeNode));
        (*T)->data = ch;
        (*T)->leftTag = 0;
        (*T)->rightTag = 0;
        // 创建左子树,逻辑一致,进行递归
        createTree(&((*T)->leftChild), data, index);
        // 创建右子树,逻辑一致,进行递归
        createTree(&((*T)->rightChild), data, index);
    }
}

void inThreadTree(TreeNode *T, TreeNode **pre)
{
    if (T != NULL)
    {
        inThreadTree(T->leftChild, pre);
        // 处理
        if (T->leftChild == NULL) // 左孩子为空,则 左孩子可以指向前驱
        {
            T->leftTag = 1;
            T->leftChild = *pre;
        }
        if (*pre != NULL && (*pre)->rightChild == NULL)
        {
            (*pre)->rightTag = 1;
            (*pre)->rightChild = T;
        }
        *pre = T;
        inThreadTree(T->rightChild, pre);
    }
}

TreeNode *getFirst(TreeNode *T)
{
    while (T->leftTag == 0)
    {
        T = T->leftChild;
    }
    return T;
}
TreeNode *getNext(TreeNode *node)
{
    if (node->rightTag == 1)
    {
        return node->rightChild;
    }
    else
    {
        return getFirst(node->rightChild);
    }
}

void inprint(TreeNode *T) // 中序遍历
{
    for (TreeNode *node = getFirst(T); node != NULL; node = getNext(node))
    {
        printf("%c ", node->data);
    }
}

int main(int argc, char const *argv[])
{
    TreeNode *T;
    TreeNode *pre = NULL;
    int index = 0;
    createTree(&T, argv[1], &index);
    inThreadTree(T, &pre);
    pre->rightTag = 1;
    pre->rightChild = NULL;
    printf("中序遍历,线索二叉树 > ");
    inprint(T);
    putchar(10);
    printf("----------------------------------------------------------\n");
    return 0;
}

运行结果:

superlan@GodFather:~/C_Language/data_structure$ ./a.out ABD#F##E##C##
中序遍历,线索二叉树 > D F B E A C 
----------------------------------------------------------

后序遍历算法代码:

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

typedef struct TreeNode
{
    char data;
    struct TreeNode *leftChild;
    struct TreeNode *rightChild;
    struct TreeNode *parent;
    int leftTag;  // 0 --> 指向Child
    int rightTag; // 0 --> 指向Child
} TreeNode;

// 当字符为 # 时 --> 空节点
void createTree(TreeNode **T, const char *data, int *index, TreeNode *parent) // 以先序遍历创建
{
    char ch;
    ch = data[*index];
    *index += 1;
    if (ch == '#')
    {
        // 此时为空节点
        *T = NULL;
    }
    else
    {
        // 此时不为空
        *T = (TreeNode *)malloc(sizeof(TreeNode));
        (*T)->data = ch;
        (*T)->leftTag = 0;
        (*T)->rightTag = 0;
        (*T)->parent = parent;
        // 创建左子树,逻辑一致,进行递归
        createTree(&((*T)->leftChild), data, index, *T);
        // 创建右子树,逻辑一致,进行递归
        createTree(&((*T)->rightChild), data, index, *T);
    }
}
TreeNode *getFirst(TreeNode *T)
{
    while (T->leftTag == 0)
    {
        T = T->leftChild;
    }
    if (T->rightTag == 0)
    {
        return getFirst(T->rightChild);
    }
    return T;
}

void postThreadTree(TreeNode *T, TreeNode **pre)
{
    if (T != NULL)
    {
        postThreadTree(T->leftChild, pre);
        postThreadTree(T->rightChild, pre);
        if (T->leftChild == NULL)
        {
            T->leftTag = 1;
            T->leftChild = *pre;
        }
        if (*pre != NULL && (*pre)->rightChild == NULL)
        {
            (*pre)->rightTag = 1;
            (*pre)->rightChild = T;
        }
        *pre = T;
    }
}

TreeNode *getNext(TreeNode *node)
{
    if (node->rightTag == 1)
    {
        return node->rightChild;
    }
    else
    {
        // 如果是根节点
        if (node->parent == NULL)
        {
            return NULL;
        }
        // 如果是右孩子
        else if (node->parent->rightChild == node)
        {
            return node->parent;
        }
        // 如果是左孩子
        else
        {
            if (node->parent->leftTag == 0)
            {
                return getFirst(node->parent->rightChild);
            }
            else
            {
                return node->parent;
            }
        }
    }
}

/**
 * 寻找第一个节点:
 * 1、找到最左边的节点
 * 2、判断这个节点,是否有右子树,如果有的话,继续寻找以右子树为根树的最左边节点
 * 如果没有那么就是第一个节点
 */
void print(TreeNode *T) // 中序遍历
{
    for (TreeNode *node = getFirst(T); node != NULL; node = getNext(node))
    {
        printf("%c ", node->data);
    }
}

int main(int argc, char const *argv[])
{
    TreeNode *T;
    TreeNode *pre = NULL;
    int index = 0;
    createTree(&T, argv[1], &index, NULL);
    postThreadTree(T, &pre);

    printf("后序遍历,线索二叉树 > ");
    print(T);
    putchar(10);
    printf("----------------------------------------------------------\n");
    return 0;
}

运行结果如下:

superlan@GodFather:~/C_Language/data_structure$ ./a.out ABD#F##E##C##
后序遍历,线索二叉树 > F D E B C A 
----------------------------------------------------------

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值