数据结构--线索树代码详细注释

#include<iostream>
#include<iomanip>                           //iomanip格式控制库
using namespace std;

typedef char eleData;                       //eleData定义数据类型
//作者:一贰柒一肆
//内容:树的构建、中序非递归遍历、中序线索树、中序线索遍历
//与书本略有不同,可以用作参考


/*                     树的结构 
                         a
                      /     \
                     b       e                  
                    / \     / \
                   c   d   f   g              
*/


static string data="abc##d##ef##g##";                         //data存储数据
static int index=0;                                           //index用来检索数据

typedef enum flog{link,node}childFlog;                        //childFlog结点孩子标记,link代表线索,node代表结点

typedef struct node{
    eleData treeData;                                         //treeData树存储的数据类型
    node* leftChild;                                          //leftChild树的左孩子
    node* rightChild;                                         //rightChild树的右孩子
    childFlog left;                                           //left左孩子标记
    childFlog right;                                          //right有孩子标记
}*treePre,treeNode;                                           //treePre树的指针-------treeNode树的结点

void creatBiTree(treePre &T)                                  //creatBiTree创建二叉树C/C++存在指针变量、传递结构体与对象时要采用引用
{
    if(index==data.length())                                  //data内的数据检索完成,不再执行后续步骤
    {
        return;
    }
    if(data[index]=='#')                                      //遇到#表示没有数据是空结点index++继续读下一位
    {
        index++;
        return;
    }
    T=(treePre)malloc(sizeof(treeNode));                      //创建结点空间
    T->left=T->right=node;                                    //初始化左右孩子标记域为结点
    T->leftChild=T->rightChild=NULL;                          //初始化左右孩子指针域为NULL
    T->treeData=data[index++];                                //初始化当前结点数据域为data[index],之后index++读后续数据
    creatBiTree(T->leftChild);                                //创建左孩子
    creatBiTree(T->rightChild);                               //创建右孩子
}

void coutTreeMid(treePre T)                                   //普通树中序非递归遍历
{
    treePre sk[data.length()];                                //设置栈,栈容量是数据长度
    int top=-1;                                               //仅使用栈顶,初值设为-1表示栈空
    while(T||top!=-1)                                         //T代表访问的结点,top表示栈是否为空
    {
        if(T)                                                 //如果结点存在
        {
            sk[++top]=T;                                      //结点入栈
            T=T->leftChild;                                   //结点向左孩子下移
        }
        else                                                  //否则就是结点不存在的时候,该不存在结点为栈顶的左孩子
        {
            cout<<setw(2)<<left<<sk[top]->treeData;           //先输出栈顶的数据,栈顶是该不存在结点的父结点--->对该父结点中序遍历:左子树为空、就要先输出数据、再检查右子树
            T=sk[top--]->rightChild;                          //top--先检查右子树,再把该父结点退栈
        }
    }
}

void creatLinkBiTree(treePre &T,treePre &pre)                 //创造中序线索二叉树
{
    if(!T) return;                                            //如果结点不存在,直接回复、不进行后续操作

    creatLinkBiTree(T->leftChild,pre);                        //先线索化左子树
    
    if(!T->leftChild)                                         //如果该结点左孩子不存在
    {
        T->left=link;                                         //把左孩子标志域设置为线索link
        T->leftChild=pre;                                     //左孩子指针域指向前驱pre
    }

    if(!pre->rightChild)                                      //前驱结点若无右孩子
    {
        pre->right=link;                                      //把右孩子标志域设置为线索link
        pre->rightChild=T;                                    //右孩子指针域指向后继T
    }

    pre=T;                                                    //当前结点已经线索化,前驱要改变,变为当前结点

    creatLinkBiTree(T->rightChild,pre);                       //开始线索化右孩子
}
 
static void lookForNext(treePre &T,treePre treeHead)          //寻找下一个结点,多次使用设为静态
{
    if(T->right==link)                                        //如果当前结点的右标记域是线索
    {
        T=T->rightChild;                                      //则直接记录当前节点的右孩子即可
    }
    else                                                      //如果当前结点的右标记是结点
    {
        T=T->rightChild;                                      //则要在右子树寻找后继
        while(T!=treeHead&&T->left==node)                     //当T记录的不是头结点而且左孩子是结点时
        {
            T=T->leftChild;                                   //T就要向左孩子方向下移动
        }                                                     //结束时T的左孩子不是结点而是指向了前驱,T就是前驱的后继
    }
}

void coutLinkTree(treePre treeHead)                           //线索树的遍历
{
    treePre T=treeHead->rightChild;                           //T储存中序遍历第一个元素的位置
    while(T!=treeHead)                                        //当T不指向头结点时就继续循环,因为中序遍历最后一个元素的后继是头结点
    {
        cout<<setw(2)<<left<<T->treeData;                     //输出当前数据
        lookForNext(T,treeHead);                              //找到下一个数据用T记录
    }
}

treePre coutMidFirst(treePre T)                               //找到中序遍历的第一个数据
{
    while(T->leftChild)                                       //第一个左孩子为空的结点就是中序遍历的第一个结点
    {
        T=T->leftChild;                                       //指针沿左孩子方向向下移动
    }
    return T;                                                 //循环结束时就是第一个左孩子为空的结点,将该结点回复,因为该结点就是中序遍历的第一个结点
}
int main()
{
    treePre tree;                                             //树根

    cout<<"\t***创造二叉树***"<<endl;
    creatBiTree(tree);                                        //调用函数创造二叉树

    cout<<"\t***创造树成功***"<<endl;
    cout<<"中序非递归遍历:";
    coutTreeMid(tree);                                        //调用函数遍历普通二叉树
    
    cout<<endl<<"\t***将树线索化***"<<endl;
    treePre treeHead=(treePre)malloc(sizeof(treeNode));       //为线索树添加头结点
    treeHead->left=node;                                      //初始化左孩子标记域为结点
    treeHead->right=link;                                     //初始化右孩子标记域为线索
    treeHead->leftChild=tree;                                 //初始化左孩子指针域记录根结点
    treeHead->rightChild=coutMidFirst(tree);                  //初始化右线索指向中序遍历的第一个结点

    treePre pre=treeHead;                                     //设置前驱,初始指向头节点

    
    creatLinkBiTree(tree,pre);                                //调用函数创建线索二叉树
    pre->rightChild=treeHead;                                 //最后一个结点的后继指向头结点

    cout<<"\t***线索化成功***"<<endl;
    cout<<"线索化遍历:";
    coutLinkTree(treeHead);                                   //调用函数进行线索化遍历

    return 0;
}

直接上代码,大家看看不懂可以留言--有空就回复

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值