线索二叉树实例

来源:互联网 发布:大数据资格认证 编辑:程序博客网 时间:2024/06/05 08:12

线索二叉树:二叉树存储结构完全依靠链表,而二叉树的链表表示的关系是父结点和子结点(子树)的关系,
而无法直接获得前驱-后继的关系,即,当要求某个结点的前驱结点or后继结点比较麻烦;
为了在不增加指针的情况下直接快速找到前驱/后继结点,可以使用 线索二叉树 来实现;

由于遍历方法不同时,产生的元素顺序不同,则每个元素的前驱/后继结点也不一定相同,
所以线索二叉树就由此分为先序线索二叉树,中序线索二叉树和后序线索二叉树;

这里写图片描述

    上图为 中序线索二叉树,由上图二叉树结构可知,其中序遍历结果为 B F D A C G E H 其中 B、D、F、C等元素拥有空的指针域;    这些空的指针域可以用来存放前驱或者后继结点的地址,这种指针称为线索(Thread);    而为了与存放子树(子树)的指针区分开来,增加了两个标志lflag,rflag表示左/右指针是哪种指针;    由此可得 线索二叉树 结构为:    typedef char DATA;          //定义树结点的元素类型    typedef enum{        SubTree,        Thread    }NodeFlag;                  //定义枚举类型NodeFlag,包含SubTree(表示子树)和Thread(表示线索),分别为 0,1    typedef struct ChainTree{   //定义二叉树结点类型        DATA data;              //结点数据        NodeFlag lflag;         //左标志:用来表示左指针是子树指针还是线索指针        NodeFlag rflag;         //右标志:用来表示右指针是子树指针还是线索指针        struct ChainTree *left; //左子树结点指针        struct ChainTree *right;//右子树结点指针    }ChainBinTree;

线索二叉树实例代码

本实例是在二叉树代码的基础上增加和修改的 这里只展示新增和修改的部分, 原来的代码见: http://blog.ay2626.me/2017/08/27/20170826_ecs/

BinTree.h

    /*            修改结构体为:    */    typedef char DATA;          //定义树结点的元素类型    typedef enum{        SubTree,        Thread    }NodeFlag;                  //定义枚举类型NodeFlag,包含SubTree(表示子树)和Thread(表示线索),分别为 0,1    typedef struct ChainTree{   //定义二叉树结点类型        DATA data;              //结点数据        NodeFlag lflag;         //左标志:用来表示左指针是子树指针还是线索指针        NodeFlag rflag;         //右标志:用来表示右指针是子树指针还是线索指针        struct ChainTree *left; //左子树结点指针        struct ChainTree *right;//右子树结点指针    }ChainBinTree;    /*            增加的函数    */    /*二叉树按中序线索化*/    void BinTreeThreading_LDR(ChainBinTree *bt);    /*中序线索二叉树 找到后继结点*/    ChainBinTree *BinTreeNext_LDR(ChainBinTree *bt);    /*中序线索二叉树遍历*/    void ThreadBinTree_LDR(ChainBinTree *bt, void (*oper)(ChainBinTree *p));

BinTree.c

    /*            增加的函数    */    /********************************线索二叉树***************************/    ChainBinTree *Previous = NULL;//保存前驱结点指针    /*二叉树按中序线索化*/    void BinTreeThreading_LDR(ChainBinTree *bt){        if(bt){//判断结点非空            //左子树操作            BinTreeThreading_LDR(bt->left);             //递归调用,线索化左子树            //当前结点操作            bt->lflag = (bt->left) ? SubTree : Thread;  //设置左指针域标志            bt->rflag = (bt->right) ? SubTree : Thread; //设置右指针域标志            if(Previous){                               //判断前驱结点是否存在(就第一个没有前驱)                if(Previous->rflag == Thread)           //判断起前驱结点的右标志是否为线索,如果不是,则说明该前驱结点存在右子树                    Previous->right = bt;               //设置前驱结点的右线索指向后继结点(当前)                if(bt->lflag == Thread)                 //判断当前结点的左标志是否为线索,如果不是,则说明当前结点存在左子树                    bt->left = Previous;                //设置当前结点的左线索指向前驱结点            }            Previous = bt;//保存刚访问的结点到Previous,作为下一个结点的前驱结点            //右子树操作            BinTreeThreading_LDR(bt->right);//递归调用,线索化右子树        }    }    /*中序线索二叉树 找到后继结点*/    ChainBinTree *BinTreeNext_LDR(ChainBinTree *bt){        ChainBinTree *nextNode;                 //存放后继结点        if(!bt)            return NULL;        if(bt->rflag == Thread){                //判断当前结点右标志是否为线索,如果是则说明right存放的是后继结点的地址,直接返回            return bt->right;        }else{            nextNode = bt->right;               //暂时存放当前结点的右子树的根节点            while(nextNode->lflag == SubTree){  //循环获取右子树的“最左结点”,这就是要求的后继结点                nextNode = nextNode->left;            }            return nextNode;        }    }    /*中序线索二叉树遍历*/    void ThreadBinTree_LDR(ChainBinTree *bt, void (*oper)(ChainBinTree *p)){        if(bt){            while(bt->lflag == SubTree){    //循环找到第一个中序遍历的结点                bt = bt->left;            }            do{                oper(bt);                bt = BinTreeNext_LDR(bt);   //获取后继结点,把地址赋值给bt            }while(bt);        }    }

main.c

    /*                修改的main函数为:    */    int main()    {        ChainBinTree *root = NULL;          //root为指向二叉树根节点的指针        char select;        void (*oper1)();                    //指向函数的指针        oper1 = oper;                       //指向具体操作的函数        do{            printf("\n1.设置二叉树根元素 2.添加二叉树结点  3.先序  4.中序  5.后序  6.按层  7.二叉树深度  8.生成中序线索二叉树  9.遍历中序线索二叉树  0.退出");            select = getch();            switch(select){                case '1':                    root = initRoot();                    break;                case '2':                    addNode(root);                    break;                case '3':                    binTree_DLR(root, oper1);                    printf("\n");                    break;                case '4':                    binTree_LDR(root, oper1);                    printf("\n");                    break;                case '5':                    binTree_LRD(root, oper1);                    printf("\n");                    break;                case '6':                    binTree_Level(root, oper1);                    printf("\n");                    break;                case '7':                    printf("%d", binTreeDepth(root));                    break;                case '8':                    BinTreeThreading_LDR(root);                    break;                case '9':                    ThreadBinTree_LDR(root, oper1);                    break;            }        }while(select != '0');        binTreeClear(root);        root = NULL;        return 0;    }

个人博客 欢迎来访: http://ay2626.me