双标记层次次序构建树

利用带双标记层次次序信息,来构造左孩子右兄弟方式表示的树。

#include <iostream>
#include <queue>
using namespace std;

const int N = 10;                        // 结点数量
template <class T> class Tree;           //声明树类

// 带“双标记”的次序结点类
template <class T>
class DualTagWidthTreeNode
{
public:
    T info;                   //树结点信息
    int ltag;                 //左标记
    int rtag;                 //右标记

    DualTagWidthTreeNode() {};               //构造函数
    virtual ~DualTagWidthTreeNode() {};      //析构函数
};

// 树结点类的ADT
template <class T>
class TreeNode
{
    friend class Tree<T>;
private:
    T m_Value;                                //树结点的值
    TreeNode<T>*    pChild;                    //左子结点
    TreeNode<T>*    pSibling;                //右兄弟结点
public:
    TreeNode() {};
    TreeNode(const T &value)
    {
        m_Value = value;
        pChild = NULL;
        pSibling = NULL;
    };
    T Value()
    {
        return m_Value;
    };                     // 获得结点的信息
    TreeNode<T> *LeftMostChild()
    {
        return pChild;
    };   // 返回第一个左子树
    TreeNode<T> *RightSibling()
    {
        return pSibling;
    };  // 返回第一个右兄弟
    void setValue(T &value)
    {
        m_Value = value;
    };      //设置结点的值
    void setChild(TreeNode<T> *pointer)
    {
        pChild = pointer;
    };   //设置左孩子
    void setSibling(TreeNode<T> *pointer)
    {
        pSibling = pointer;
    };  //设置右孩子
};

// 树类ADT,只写出了相关的变量及函数
template <class T>
class Tree
{
private:
    TreeNode<T> *root;
    TreeNode<T> *getParent(TreeNode<T> *root, TreeNode<T> *current);
public:
    Tree()
    {
        root = NULL;
    };
    Tree(DualTagWidthTreeNode<T> *nodeArray, int count); //带双标记先根次序构造算法
    TreeNode<T> *getRoot()
    {
        return root;
    };          //返回树中的根结点
    void Visit(T Value)
    {
        cout << Value;
    };           //访问
    void RootFirstTraverse(TreeNode<T> *root);      //先根次序周游,作为测试使用
};

// 函数功能:带双标记层次次序构造算法
template <class T>
Tree<T>::Tree(DualTagWidthTreeNode<T>* nodeArray, int count)
{
    //由带双标记位的层次次序表示构造左孩子右兄弟方式表示的树
    using std::queue;                                 //使用STL队列
    queue<TreeNode<T>*> aQueue;
    //准备建立根结点
    TreeNode<T>* pointer=new TreeNode<T>;
    root=pointer;
    //处理一个结点
    for(int i=0; i<count-1; i++)
    {
        pointer->setValue(nodeArray[i].info);
        if(nodeArray[i].ltag==0)
            aQueue.push(pointer);                   //将结点入队
        else
            pointer->setChild(NULL);                //左孩子设为空
        TreeNode<T>* temppointer=new TreeNode<T>;
        if(nodeArray[i].rtag == 0)
            pointer->setSibling(temppointer);
        else
        {
            pointer->setSibling(NULL);              //右兄弟设为空
            pointer=aQueue.front();                 //取队列首结点指针
            aQueue.pop();                           //队首元素出队列
            pointer->setChild(temppointer);
        }
        pointer=temppointer;
    }
    //处理最后一个结点
    pointer->setValue(nodeArray[count-1].info);
    pointer->setChild(NULL);
    pointer->setSibling(NULL);
}

// 函数功能:先根深度遍历
template <class T>
void Tree<T>::RootFirstTraverse(TreeNode<T> *root)
{
    while (root != NULL)
    {
        Visit(root->Value());
        RootFirstTraverse(root->LeftMostChild());
        root = root->RightSibling();
    }
}

// 函数功能:周游树,在这里只列举一种(先根次序)
void Traverse(Tree<char> *tree)
{
    cout << "FirstRoot traverse:  ";
    tree->RootFirstTraverse(tree->getRoot()); // 先根深度优先周游
    cout << endl;
}

// 函数功能:显示森林结构.图6.5(a)所示的森林
void DisplayTree()
{
    cout << "      A              G      \n";
    cout << "   /  |  \\         /   \\   \n";
    cout << "  B   C    D      H     I   \n";
    cout << "     / \\          |         \n";
    cout << "    E   F         J         \n";
    cout << "\n";
    cout << "rtag =  0  have right sibling" << endl;
    cout << "rtag =  1  havn't right sibling" << endl;
    cout << "ltag =  0  have left child" << endl;
    cout << "ltag =  1  havn't left child" << endl << endl;
}

// 函数功能:显示森林结构的带双标记层次次序表示
void DisplayNode(char *Info, int *nRtag, int *nLtag)
{
    if (Info != NULL)
    {
        cout << "info   ";
        for (int i = 0; i < N; i ++)
            cout << Info[i] << " ";
        cout << endl;
    }

    if (nRtag != NULL)
    {
        cout << "rtag   ";
        for (int i = 0; i < N; i ++)
            cout << nRtag[i] << " ";
        cout << endl;
    }

    if (nLtag != NULL)
    {
        cout << "ltag   ";
        for (int i = 0; i < N; i ++)
            cout << nLtag[i] << " ";
        cout << endl;
    }
}

int main()
{
    // 显示森林结构
    DisplayTree();

    // 带双标记层次次序构造算法,图6.5(a)所示的森林的带双标记位的层次次序表示为例
    char strInfo[N] = {'A', 'G', 'B', 'C', 'D', 'H', 'I', 'E', 'F', 'J'};
    int nRtag[N] = {0, 1, 0, 0, 1, 0, 1, 0, 1, 1};
    int nLtag[N] = {0, 0, 1, 0, 1, 0, 1, 1, 1, 1};

    cout << "Dualtag_Width create tree." << endl;       //打印带双标记位的层次次序表示
    DisplayNode(strInfo, nRtag, nLtag);

    DualTagWidthTreeNode<char> *nodeArray = new DualTagWidthTreeNode<char>[N];

    for (int i = 0; i < N; i ++)                   //设置带双标记位的层次次序结点类
    {
        nodeArray[i].info = strInfo[i];
        nodeArray[i].rtag = nRtag[i];
        nodeArray[i].ltag = nLtag[i];
    }

    Tree<char> aTree(nodeArray, N); // 建树
    Traverse(&aTree);               // 周游树,结果:ABCEFDGHJI
    return 0;
}

  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
很抱歉,我是一名语言模型,无法提供代码实现。但我可以给出算法思路供参考: 1. 首先需要定义一个的节点结构体,包含节点的值、左右子节点指针、link、rlink、深度等信息。 2. 根据输入的带双标记的先根次序表示构建一棵二叉。具体方法是,从根节点开始,依次读取每个节点的值和标记,如果是左儿子标记,则将其作为当前节点的左子节点;如果是右儿子标记,则将其作为当前节点的右子节点;如果是回溯标记,则回溯到当前节点的父节点。在构建过程中,需要维护一个指针,指向当前节点。 3. 构建完成后,遍历整棵,计算每个节点的link和rlink。具体方法是,在先序遍历过程中,记录当前节点的深度和祖先节点的link。如果当前节点是左子节点,则将其link指向当前节点的父节点的link;如果当前节点是右子节点,则将其link指向当前节点的兄弟节点的link;如果当前节点是根节点,则将其link指向空。在后序遍历过程中,记录当前节点的深度和祖先节点的rlink。如果当前节点是右子节点,则将其rlink指向当前节点的父节点的rlink;如果当前节点是左子节点,则将其rlink指向当前节点的兄弟节点的rlink;如果当前节点是根节点,则将其rlink指向空。 4. 最后,输出带双标记层次次序表示。具体方法是,从根节点开始,进行层次遍历。对于每个节点,输出其值和深度,以及link和rlink的值。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值