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

    #include "stdafx.h"
    #include <iostream>
    #include <iomanip>
    #include <stack>
    #include <queue>
    #include <Windows.h>
    using namespace std;
    
    enum TYPE
    {
        TYPE_LINK = 0,
        TYPE_CLUES,
    };
    typedef struct _Node
    {
        int data;
        struct _Node *left;
        struct _Node *right;
        bool isVisit;        //用于后序非递归遍历,表示节点是否可以访问
        TYPE lType;          //标示左子树为指向左子树还是前驱
        TYPE rType;          //标示右子树为指向右子树还是后驱
        _Node()
        {
            data = 0;
            left = NULL;
            right = NULL;
            isVisit = false;
            lType = TYPE_LINK;
            rType = TYPE_LINK;
        }
    }Node, *_PNode;
    
    //假定二叉树如下图所示,利用前序和中序、后序与中序可以唯一确定一棵二叉树的原理
    //                       1
    //                     /   \
    //                    2     3
    //                  / \     / \
    //                 4   5   6   7 
    //               / \  /
    //              8   9 10
    
    const int MAX_NUM = 10;                             //二叉树的节点数
    int pre[MAX_NUM] = {1, 2, 4, 8, 9, 5, 10, 3, 6, 7}; //前序遍历的数组
    int mid[MAX_NUM] = {8, 4, 9, 2, 10, 5, 1, 6, 3, 7}; //中序遍历的数组
    int post[MAX_NUM] = {8, 9, 4, 10, 5, 2, 6, 7,3, 1}; //后序遍历的数组
    
    //获取前序数组的data在中序数组的索引
    int GetPositionInMid(int data)
    {
        for (int i = 0; i < MAX_NUM; i++)
        {
            if (mid[i] == data)
            {
                return i;
            }
        }
    }
    
    //利用前序和中序可以唯一确定一棵二叉树
    //参数说明
    // pRoot   —— 需要建造节点的指针引用
    // iPre    —— 表示pRoot节点的左子树(右子树)在前序数组的第一个索引
    // iMid    —— 表示pRoot节点的左子树(右子树)在中序数组的第一个索引
    // length  —— 表示pRoot节点的左子树(右子树)的长度
    void PreAndMidRecurCreate(_PNode &pRoot, int iPre, int iMid, int length)
    {
        if (length <= 0)
        {
            return;
        }
        pRoot = new Node;
        pRoot->data = pre[iPre];
        int pos = GetPositionInMid(pre[iPre]);
        PreAndMidRecurCreate(pRoot->left, iPre + 1, iMid, pos - iMid);
        PreAndMidRecurCreate(pRoot->right, iPre + (pos - iMid) + 1, pos + 1, length - (pos - iMid) - 1);
    }
    
    //利用后序和中序可以唯一确定一棵二叉树
    //参数说明
    // pRoot   —— 需要建造节点的指针引用
    // iPost   —— 表示pRoot节点的左子树(右子树)在后序数组的第一个索引
    // iMid    —— 表示pRoot节点的左子树(右子树)在中序数组的第一个索引
    // length  —— 表示pRoot节点的左子树(右子树)的长度
    void PostAndMidRecurCreate(_PNode &pRoot, int iPost, int iMid, int length)
    {
        if (length <= 0)
        {
            return;
        }
        pRoot = new Node;
        pRoot->data = post[iPost];
        int pos = GetPositionInMid(post[iPost]);
        PostAndMidRecurCreate(pRoot->left, iPost - 1 - (length - (pos - iMid) - 1), iMid, pos - iMid);
        PostAndMidRecurCreate(pRoot->right, iPost - 1, pos + 1, length - (pos - iMid) - 1);
    }
    //****************************************二叉树的线索*******************************************begin
    
    _PNode prePreNode;   //前序线索二叉树指向的节点前驱
    _PNode preMidNode;   //中序线索二叉树指向的节点前驱
    _PNode prePostNode;  //后序线索二叉树指向的节点前驱
    
    //前序线索二叉树的递归函数
    void PreInClues(_PNode &pRoot)
    {
        if (NULL != pRoot)
        {
            if (NULL == pRoot->left)   //1、如果当前节点左子树为空,则线索
            {
                pRoot->left = prePreNode;
                pRoot->lType = TYPE_CLUES;
            }
            if (NULL == prePreNode->right)//2、如果前驱节点右子树为空,则线索
            {
                prePreNode->right = pRoot;
                prePreNode->rType = TYPE_CLUES;
            }
            prePreNode = pRoot;
            if (pRoot->lType == TYPE_LINK)
            {
                PreInClues(pRoot->left);
            }
            if (pRoot->rType == TYPE_LINK)
            {
                PreInClues(pRoot->right);
            }
        }
    }
    
    //前序线索二叉树
    //参数说明   pPreRoot —— 指向根节点的指针
    //         pRoot    ——  根节点的指针
    void PreTraversalInClues(_PNode &pPreRoot, _PNode &pRoot)
    {
        pPreRoot = new Node;
        pPreRoot->right = pPreRoot;
        pPreRoot->rType = TYPE_CLUES;
        pPreRoot->lType = TYPE_LINK;
        if (NULL == pRoot)
        {
            pPreRoot->left = pPreRoot;
        }
        else
        {
            pPreRoot->left = pRoot;
            prePreNode = pPreRoot;
            PreInClues(pRoot);
            prePreNode->right = pPreRoot;
            prePreNode->rType = TYPE_CLUES;
            pPreRoot->right = prePreNode;
        }
    }
    
    //中序线索化的输出
    void PreCluesOutput(_PNode pPreRoot)
    {
        _PNode pNode = pPreRoot->left;
        while (pNode != pPreRoot)
        {
            cout<<pNode->data<<'\t';
            if (pNode->lType == TYPE_LINK)
            {
                pNode = pNode->left;
            }
            else 
            {
                pNode = pNode->right;
            }
        }
    }
    
    //中序线索二叉树的递归函数
    void MidInClues(_PNode &pRoot)
    {
        if (NULL != pRoot)
        {
            MidInClues(pRoot->left);
            if (NULL == pRoot->left)  //1、如果当前节点左子树为空,则线索
            {
                pRoot->left = preMidNode;
                pRoot->lType = TYPE_CLUES;
            }
            if (NULL == preMidNode->right) //2、如果前驱节点右子树为空,则线索
            {
                preMidNode->right = pRoot;
                preMidNode->rType = TYPE_CLUES;
            }
            preMidNode = pRoot;
            MidInClues(pRoot->right);
        }
    }
    
    //中序线索二叉树
    void MidTraversalInClues(_PNode &pPreRoot, _PNode &pRoot)
    {
        pPreRoot = new Node;
        pPreRoot->right = pPreRoot;
        pPreRoot->rType = TYPE_CLUES;
        pPreRoot->lType = TYPE_LINK;
        if (NULL == pRoot)
        {
            pPreRoot->left = pPreRoot;
        }
        else
        {
            pPreRoot->left = pRoot;
            preMidNode = pPreRoot;
            MidInClues(pRoot);
            preMidNode->right = pPreRoot;
            preMidNode->rType = TYPE_CLUES;
            pPreRoot->right = preMidNode;
        }
    }
    
    //中序线索化的输出
    void MidCluesOutput(_PNode pPreRoot)
    {
        _PNode pNode = pPreRoot->left;
        while (pNode != pPreRoot)
        {
            while (pNode->lType ==  TYPE_LINK)
            {
                pNode = pNode->left;
            }
            cout<<pNode->data<<'\t';
            while (pNode->rType == TYPE_CLUES && pNode->right != pPreRoot)
            {
                pNode = pNode->right;
                cout<<pNode->data<<'\t';
            }
            pNode = pNode->right;
        }
    }
    
    //****************************************二叉树的线索*******************************************end
    int _tmain(int argc, _TCHAR* argv[]) { _PNode pRoot1 = NULL; _PNode pRoot2 = NULL; _PNode pPreRoot = NULL; _PNode pMidRoot = NULL; //cout<<endl<<"******************根据前序和中序建造二叉树********************"<<endl<<endl; PreAndMidRecurCreate(pRoot1, 0, 0, MAX_NUM); //cout<<endl<<"******************根据后序和中序建造二叉树********************"<<endl<<endl; PostAndMidRecurCreate(pRoot2, MAX_NUM - 1, 0, MAX_NUM);
    cout
    <<endl<<"******************输出前序线索二叉树********************"<<endl<<endl; PreTraversalInClues(pPreRoot, pRoot1); PreCluesOutput(pPreRoot); cout<<endl<<"******************输出中序线索二叉树********************"<<endl<<endl; MidTraversalInClues(pMidRoot, pRoot2); MidCluesOutput(pMidRoot); cout<<endl; return 0; }

    运行界面如下:

  • 相关阅读:
    BZOJ1877: [SDOI2009]晨跑
    SPFA的两个优化:SLF与LLL
    BZOJ1858: [Scoi2010]序列操作
    java线程基础巩固---如何捕获线程运行期间的异常
    java线程基础巩固---如何给你的应用程序注入钩子程序
    类的命名空间与卸载详解及jvisualvm使用
    okhttp拦截器之RetryAndFollowUpInterceptor&BridgeInterceptor分析
    okhttp初识拦截器
    类加载器双亲委托机制实例深度剖析
    类加载器重要方法详解
  • 原文地址:https://www.cnblogs.com/venow/p/2627274.html
Copyright © 2011-2022 走看看