zoukankan      html  css  js  c++  java
  • 线索二叉树

    线索二叉树分别在节点中子树为空时设为其前驱或者后继节点,其遍历中序线索二叉树效率会比较高一点。该程序可实现线索二叉树包括中序遍历等基本操作,代码如下:
    xiansuotree.c主要为线索二叉树的基本操作函数

    //start from the very beginning,and to create greatness
    //@author: Chuangwei Lin
    //@E-mail:979951191@qq.com
    //@brief: 线索二叉树的基本操作
    #include "xiansuotree.h"
    
    ThreadBinTree *Previous=NULL;     //前驱结点指针 
    /******************************************************
    函数名:
    参数:bt为父结点,node为子结点,n=1表示添加左子树,n=2表示添加右子树 
    功能:添加数据到二叉树
    *******************************************************/
    int BinTreeAddNode(ThreadBinTree *bt,ThreadBinTree *node,int n)  
    {
        if(bt==NULL)
        {
            printf("父结点不存在,请先设置父结点!
    ");
            return 0;
        } 
        switch(n)
        {
            case 1: //添加到左结点 
                if(bt->left) //左子树不为空 
                {
                    printf("左子树结点不为空!
    ");
                    return 0;
                }else
                    bt->left=node;
                break;
            case 2://添加到右结点
                if( bt->right) //右子树不为空 
                {
                    printf("右子树结点不为空!
    "); 
                    return 0;
                }
                else
                    bt->right=node;
                break;
            default:
                printf("参数错误!
    ");
                return 0;
        }
        return 1;
    }
    /******************************************************
    函数名:BinTreeFind(ThreadBinTree *bt,DATA data)   
    参数:树节点,数据
    功能:在二叉树中查找值为data的结点
    *******************************************************/
    ThreadBinTree *BinTreeFind(ThreadBinTree *bt,DATA data)   
    {
        ThreadBinTree *p;
        if(bt==NULL)
            return NULL;
        else
        {
            if(bt->data==data)
                return bt; 
            else
            { // 分别向左右子树递归查找 
                if(p=BinTreeFind(bt->left,data))
                    return p;
                else if(p=BinTreeFind(bt->right, data)) 
                    return p;
                else
                    return NULL; 
            } 
        } 
    }
    /******************************************************
    函数名:BinTreeClear(ThreadBinTree *bt) 
    参数:树节点
    功能:清空二叉树,使之变为一棵空树
    *******************************************************/
    void BinTreeClear(ThreadBinTree *bt) 
    {
         if(bt)//该节点不为空
         {
             BinTreeClear(bt->left); //清空左子树 
             BinTreeClear(bt->right);//清空右子树 
             free(bt);//释放当前结点所占内存 
             bt=NULL;
         }
         return; 
    }
    /******************************************************
    函数名:BinTreeThreading_LDR(ThreadBinTree *bt) 
    参数:树结点
    功能:二叉树按中序线索化
    *******************************************************/
    void BinTreeThreading_LDR(ThreadBinTree *bt)    
    {
        if(bt) //结点非空时,当前访问结点
        {
            BinTreeThreading_LDR(bt->left); //递归调用,将左子树线索化
            //bt->left为真就取SubTree(子树),否则为前驱
            bt->lflag=(bt->left)?SubTree:Thread; //设置左指针域的标志
            bt->rflag=(bt->right)?SubTree:Thread;//设置右指针域的标志
            if(Previous) //若当前结点的前驱Previous存在
            {//以下两句完成一对对应关系
                if(Previous->rflag==Thread) //若当前结点的前驱右标志为线索(没有右孩子,则要指向后继)
                    Previous->right=bt;//设Previous的右线索指向后继
                if(bt->lflag==Thread) //若当前结点的左标志为线索(没有左孩子,则要指向前驱)
                    bt->left=Previous;//设当前结点的左线索指向中序前驱 
            }
            Previous=bt;//让Previous保存刚访问的结点
            BinTreeThreading_LDR(bt->right);//递归调用,将右子树线索化
        }
    }
    /******************************************************
    函数名:BinTreeNext_LDR(ThreadBinTree *bt) 
    参数:树节点
    功能:求指定结点的后继 
    *******************************************************/
    ThreadBinTree *BinTreeNext_LDR(ThreadBinTree *bt) 
    {//后继是右孩子数最左下方的结点
        ThreadBinTree *nextnode;
        if(!bt) 
            return NULL; //若当前结点为空,则返回空 
        if(bt->rflag==Thread) //若当前结点的右子树为空,则是指向后继,直接返回后继
            return bt->right; //返回右线索所指的中序后继,右指向后继
        else//如果是指向右孩子
        {
            nextnode=bt->right; //从当前结点的右子树开始查找
            while(nextnode->lflag==SubTree) //循环处理所有左子树不为空的结点
                nextnode=nextnode->left;//后继肯定就是右孩子数的最左下方的结点,因为接下来就是遍历他
            return nextnode; //返回左下方的结点
        }
    }
    /******************************************************
    函数名:BinTreePrevious_LDR(ThreadBinTree *bt) 
    参数:树节点
    功能:求指定结点的前驱
    *******************************************************/
    ThreadBinTree *BinTreePrevious_LDR(ThreadBinTree *bt)  
    {//前驱是左孩子数的最右结点
        ThreadBinTree *prenode;
        if(!bt) 
            return NULL; //若当前结点为空,则返回空 
        if(bt->lflag==Thread) //若当前结点的左子树为空,则就是指向前驱
            return bt->left; //返回左线索所指的中序后继
        else
        {
            prenode=bt->left; //从当前结点的左子树开始查找
            while(prenode->rflag==SubTree) //循环处理所有右子树不为空的结点
                prenode=prenode->right;
            return prenode; //返回右下方的结点
        }
    }
    /******************************************************
    函数名:ThreadBinTree_LDR(ThreadBinTree *bt,void (*oper)(ThreadBinTree *p))  
    参数:树节点,操作函数
    功能:遍历中序线索二叉树
    *******************************************************/
    void ThreadBinTree_LDR(ThreadBinTree *bt,void (*oper)(ThreadBinTree *p))  
    {
        if(bt) //二叉树不为空
        {
            while(bt->lflag==SubTree)//有左子树 
                bt=bt->left; //从根往下找最左下结点,即中序序列的开始结点
            do{//因为前驱和后继的关系已经弄好了
               oper(bt); //处理结点 
               bt=BinTreeNext_LDR(bt);//找中序后继结点
            }while(bt);
        }
    }
    /******************************************************
    函数名:oper(ThreadBinTree *p)  
    参数:树节点
    功能:操作二叉树结点数据
    *******************************************************/
    void oper(ThreadBinTree *p)  
    {
         printf("%c ",p->data); //输出数据
         return;
    }
    /******************************************************
    函数名:InitRoot()   
    参数:无
    功能:初始化二叉树的根
    *******************************************************/
    ThreadBinTree *InitRoot()    
    {
        ThreadBinTree *node;
        if(node=(ThreadBinTree *)malloc( sizeof(ThreadBinTree))) //分配内存
        {
            printf("
    输入根结点数据:");
            scanf("%s",&node->data);
            node->left=NULL;
            node->right=NULL;
            return node;
        }
        return NULL;
    }
    /******************************************************
    函数名:AddNode(ThreadBinTree *bt)
    参数:树节点
    功能:增加特定父节点的子结点
    *******************************************************/
    void AddNode(ThreadBinTree *bt)
    {
         ThreadBinTree *node,*parent;
         DATA data;
         char select;
        if(node=(ThreadBinTree *)malloc(sizeof(ThreadBinTree))) //分配内存
        {
            printf("
    输入二叉树结点数据:");
            scanf("%s",&node->data);
            node->left=NULL; //设置左右子树为空 
            node->right=NULL;
            printf("输入父结点数据:");
            scanf("%s",&data);
            parent=BinTreeFind(bt,data);//查找指定数据的结点 
            if(!parent)//若未找到指定数据的结点 
            {
                printf("未找到父结点!
    ");
                free(node); //释放创建的结点内存 
                return;
             }
             printf("1.添加到左子树
    2.添加到右子树
    ");
             do{
                select=getchar();
                select-='0';
                if(select==1 || select==2)
                    BinTreeAddNode(parent,node,select); //添加结点到二叉树 
             }while(select!=1 && select!=2);
        }
        return ;
    }

    lcwxiansuo.c为主函数,主要实现其验证

    //start from the very beginning,and to create greatness
    //@author: Chuangwei Lin
    //@E-mail:979951191@qq.com
    //@brief: 线索二叉树操作验证函数
    #include "xiansuotree.h"
    
    int main() 
    {
        ThreadBinTree *root=NULL; //root为指向二叉树根结点的指针 
        char select;
        void (*oper1)(); //指向函数的指针 
        oper1=oper; //指向具体操作的函数 
        do{
            printf("
    1.设置二叉树根元素    2.添加二叉树结点
    ");
            printf("3.生成中序线索二叉树  4.遍历线索二叉树
    ");
            printf("00.退出
    ");
            select=getchar();
            switch(select)
            {
            case '1': //设置根元素 
                 root=InitRoot();
                 break;
            case '2': //添加结点 
                 AddNode(root);
                 break;
            case '3'://生成中序线索二叉树
                 BinTreeThreading_LDR(root);
                 printf("
    生成中序线索二叉树完毕!
    ");
                 break;
            case '4'://遍历中序线索二叉树 
                 printf("
    中序线索二叉树遍历的结果:");
                 ThreadBinTree_LDR(root,oper1);
                 printf("
    ");
                 break;
            case '0':
                 break;
            }
            select=getchar();//这里加一个去掉回车符
        }while(select!='0');
        BinTreeClear(root);//清空二叉树 
        root=NULL;
        return 0;
    }
    

    该头文件包括基本的数据结构和函数的声明

    //start from the very beginning,and to create greatness
    //@author: Chuangwei Lin
    //@E-mail:979951191@qq.com
    //@brief: 线索二叉树基本操作的头文件
    #include <stdio.h> 
    #include <stdlib.h> 
    typedef char DATA;       //定义元素类型 
    //枚举
    typedef enum 
    {
        SubTree, //枚举值SubTree(子树)为0
        Thread   //Thread(线索)为1
    }NodeFlag;
    
    typedef struct ThreadTree  //定义线索二叉树结点类型 
    {
        DATA data;  //元素数据
        NodeFlag lflag; //左标志,其取值只有两种
        NodeFlag rflag; //右标志 
        struct ThreadTree *left;    //左子树结点指针
        struct ThreadTree *right;   //右子树结点指针
    }ThreadBinTree;
    
    int BinTreeAddNode(ThreadBinTree *bt,ThreadBinTree *node,int n);  
    ThreadBinTree *BinTreeFind(ThreadBinTree *bt,DATA data);
    void BinTreeClear(ThreadBinTree *bt);
    void BinTreeThreading_LDR(ThreadBinTree *bt);
    ThreadBinTree *BinTreeNext_LDR(ThreadBinTree *bt);
    ThreadBinTree *BinTreePrevious_LDR(ThreadBinTree *bt); 
    void ThreadBinTree_LDR(ThreadBinTree *bt,void (*oper)(ThreadBinTree *p));
    void oper(ThreadBinTree *p);
    ThreadBinTree *InitRoot(); 
    void AddNode(ThreadBinTree *bt);

    运行结果如下:
    这里写图片描述
    建立了一个线索二叉树,然后生成中序线索二叉树,最后遍历线索二叉树
    这里写图片描述

  • 相关阅读:
    Windows PE导出表编程3(暴力覆盖导出函数)
    Windows PE导出表编程3(暴力覆盖导出函数)
    Windows PE导出表编程2(重组导出表函数地址)
    Windows PE导出表编程2(重组导出表函数地址)
    Windows核心编程 第二十章 DLL的高级操作技术
    Windows核心编程 第二十章 DLL的高级操作技术
    Windows核心编程 第十九章 DLL基础
    CodeForces A. Points in Segments
    PAT 甲级 1031 Hello World for U
    PAT L1-006 连续因子
  • 原文地址:https://www.cnblogs.com/sigma0-/p/12630499.html
Copyright © 2011-2022 走看看