数据结构 实验报告11

 

 

一、实验目的和要求

目的:熟悉后序线索二叉树并实现后序遍历

要求:

(1)创建二叉树。

(2)转换为后序线索二叉树。

(3)实现后序遍历的非递归算法。

二、实验环境

编译器:Vscode +DevC++

系统:Windows10

CPU:i5-8265U@1.60GHz

三、实验内容

(1)创建二叉树。

(2)转换为后序线索二叉树。

(3)实现后序遍历的非递归算法。

四、实验过程

4.1 任务定义和问题分析

1.创建二叉树

沿用之前使用二叉树创建模板;(若兼容后序线索二叉树的话)

或者重新创建二叉树类(后序线索二叉树需要其他辅助变量)

      2.转换成后序线索二叉树

            在转换时只需要按照后序遍历,(需要记录当前结点的前驱)逐个将空指针利用起来

      3.实现后序遍历的非递归算法

            需要经过多重循环,首先通过while找到最左结点,然后遍历后继……

4.2 数据结构的选择和概要设计

必是选择链式结构;

在创建树时,使用扩展先序序列创建;

    1. 详细设计

第一尝试:

      首先将之前写的二叉树类扩展了,添加了rtag和ltag变量用于识别指针是否指向儿子;其次添加了一个全局结点指针变量,用于实现对前驱的记录

      接着对后序遍历进行修改

 

然后就是添加函数  使其能够进行对后序非递归遍历

在编写此方面代码时就出现了问题

我的第一版函数是如下操作的

      1.先找到第一个结点(最左的结点)

      2.再遍历其后继

      3.然后再找到当前结点的最左儿子

      4.重复2,3操作直到结点为空

在实际面对下面二叉树时,就出现了预想不到的事情:

 

进入了死循环————CDBCDB

下面展示后序线索(绿色指向前驱,红色指向后继):

 

不难看出再程序寻到B时对A的左子树操作就完成了,需要去操作A的右子树,然而对于非递归遍历来说,我们现在就是过了河的卒,无法回头,在执行到B时没有操作能够支持我们去操作A的右子树

故而 添加辅助空间:父亲指针

 

并在创建树时,记录每个结点的父亲结点

在执行非递归后序遍历时,操作如下

  1. 找寻到以当前结点为根的树的后序遍历的起始节点
  2. 按次序找寻后继并输出数据
  3. 判断是否达到根结点(是:输出数据并结束遍历;否:进行下一步)
  4. 逐层向上返回,并输出数据,直到是从当前左子树返回为止
  5. 去访问右孩子
  6. 回到第一步

五、测试及结果分析

5.1 实验数据

 

 

5.2 结果及分析

正确实现了二叉树向后序线索树的转换

并实现了后序遍历的非递归输出

六、实验收获

熟悉了线索二叉树

 

七、参考文献

数据结构-线索二叉树(后序线索二叉树及遍历)

《大话数据结构》

八、附录(源代码)

/*

 * @Descripttion: 

 * @version: 

 * @Author: Nice_try

 * @Date: 2020-05-26 09:10:57

 * @LastEditors: Nice_try

 * @LastEditTime: 2020-05-26 17:59:12

 */

#include <iostream>

#include<cstdio>

#include<algorithm>

#include<typeinfo>

using namespace std;

#define Link 0   //表示该节点有非空孩子节点

#define Thread 1 //表示该节点有后续节点(对于右子树来说)

#define MAXSIZE 100



template <class T>

struct BT_Thread_Node

{

    T Data;

    BT_Thread_Node *Left_Child;

    BT_Thread_Node *Right_Child;

    BT_Thread_Node *Parent; //指向该节点的父母节点

    int Ltag;

    int Rtag;

};



template <class T>

class Thread_Binary_tree

{

private:

    BT_Thread_Node<T> *Tree;

    BT_Thread_Node<T> *Pre_Node;

    BT_Thread_Node<T> *BT_Node_Stack[MAXSIZE];

    int Top;

    int Create_Thread_BTree(BT_Thread_Node<T> *&Tree, BT_Thread_Node<T> *Parent);

    void PostOrder_Thread_Op(BT_Thread_Node<T> *&Tree);

    void _PostOrder_Op(BT_Thread_Node<T> *&Tree);



public:

    Thread_Binary_tree();

    ~Thread_Binary_tree();

    void PostOrder_Thread();

    void _PostOrder();

};



template <class T>

int Thread_Binary_tree<T>::Create_Thread_BTree(BT_Thread_Node<T> *&Tree, BT_Thread_Node<T> *Parent_Node)

{

    T Data;

    cin >> Data;

    if(Data=='#'||Data==-1)

        Tree = NULL;

    else

    {

        Tree = new BT_Thread_Node<T>;

        Tree->Parent = Parent_Node; //指向父母节点

        Tree->Data = Data;

        Tree->Ltag = Link;

        Tree->Rtag = Link;

        Create_Thread_BTree(Tree->Left_Child, Tree); //Tree是孩子的父母节点

        Create_Thread_BTree(Tree->Right_Child, Tree);

    }

    return 1;

}



template <class T>

void Thread_Binary_tree<T>::PostOrder_Thread_Op(BT_Thread_Node<T> *&Tree)

{

    if (Tree == NULL)

        return;



    PostOrder_Thread_Op(Tree->Left_Child);  //左

    PostOrder_Thread_Op(Tree->Right_Child); //右



    if (Tree->Left_Child == NULL) //根

    {

        Tree->Left_Child = Pre_Node;

        Tree->Ltag = Thread;

    }

    if (Pre_Node != NULL && Pre_Node->Right_Child == NULL)

    {

        Pre_Node->Right_Child = Tree;

        Pre_Node->Rtag = Thread;

    }



    Pre_Node = Tree;

}



template <class T>

void Thread_Binary_tree<T>::_PostOrder_Op(BT_Thread_Node<T> *&Tree)

{

    if (Tree == NULL)

        return;



    BT_Thread_Node<T> *Cur_Node = Tree;

    Pre_Node = NULL;

    while (Cur_Node != NULL)

    {

        while (Cur_Node->Left_Child != Pre_Node) //change,找到起始节点(在左树的最左边)

        {

            Cur_Node = Cur_Node->Left_Child;

        }



        while (Cur_Node != NULL && Cur_Node->Rtag == Thread) //按线索找到次树节点

        {

            BT_Node_Stack[++Top] = Cur_Node;

            cout << Cur_Node->Data << " ";

            Pre_Node = Cur_Node; //每次访问节点后,PreNode更新

            Cur_Node = Cur_Node->Right_Child;

        }



        if (Cur_Node == Tree) //如果当前节点为根节点,说明遍历完成

        {

            BT_Node_Stack[++Top] = Cur_Node;

            cout << Cur_Node->Data << " ";

            return;

        }



        while (Cur_Node != NULL && Cur_Node->Right_Child == Pre_Node) //当前节点的右孩子节点刚好上次遍历,说明该袖珍树只差根就遍历完成

        {

            BT_Node_Stack[++Top] = Cur_Node;

            cout << Cur_Node->Data << " ";

            Pre_Node = Cur_Node;

            Cur_Node = Cur_Node->Parent; //访问袖珍树后回到上一层

        }



        if (Cur_Node != NULL && Cur_Node->Rtag == Link) //回到上一层后,先访问右孩子

        {

            Cur_Node = Cur_Node->Right_Child;

        }

    }

}



template <class T>

Thread_Binary_tree<T>::Thread_Binary_tree() : Pre_Node(NULL), Top(-1)

{

    Create_Thread_BTree(Tree, NULL);

}



template <class T>

Thread_Binary_tree<T>::~Thread_Binary_tree()

{

    while (Top != -1)

    {

        delete BT_Node_Stack[Top];

        Top--;

    }

}



template <class T>

void Thread_Binary_tree<T>::PostOrder_Thread()

{

    PostOrder_Thread_Op(Tree);

}



template <class T>

void Thread_Binary_tree<T>::_PostOrder()

{

    _PostOrder_Op(Tree);

}

 

 

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,下面是数据结构二叉树的实验报告。 一、实验目的 1. 了解二叉树的概念、性质和基本操作; 2. 掌握二叉树的遍历算法; 3. 实现二叉树的建立、遍历和查找等基本操作。 二、实验原理 二叉树是一种树形结构,它的每个节点最多有两个子节点。二叉树的性质如下: 1. 每个节点最多有两个子节点,分别称为左子节点和右子节点; 2. 左子树和右子树都是二叉树; 3. 空树也是一棵二叉树。 二叉树的遍历有三种方式: 1. 先序遍历:先访问根节点,然后遍历左子树,最后遍历右子树; 2. 中序遍历:先遍历左子树,然后访问根节点,最后遍历右子树; 3. 后序遍历:先遍历左子树,然后遍历右子树,最后访问根节点。 三、实验步骤 本次实验我们将实现二叉树的建立、遍历和查找等基本操作。 1. 定义二叉树结构体。 ```c typedef struct Node { int data; struct Node *left; struct Node *right; } Node, *pNode; ``` 2. 实现二叉树的创建函数。 ```c pNode createTree() { int data; scanf("%d", &data); if(data == -1) { return NULL; } else { pNode node = (pNode)malloc(sizeof(Node)); node->data = data; node->left = createTree(); node->right = createTree(); return node; } } ``` 3. 实现二叉树的先序遍历函数。 ```c void preOrder(pNode node) { if(node != NULL) { printf("%d ", node->data); preOrder(node->left); preOrder(node->right); } } ``` 4. 实现二叉树的中序遍历函数。 ```c void inOrder(pNode node) { if(node != NULL) { inOrder(node->left); printf("%d ", node->data); inOrder(node->right); } } ``` 5. 实现二叉树的后序遍历函数。 ```c void postOrder(pNode node) { if(node != NULL) { postOrder(node->left); postOrder(node->right); printf("%d ", node->data); } } ``` 6. 实现二叉树的查找函数。 ```c pNode search(pNode node, int data) { if(node == NULL) { return NULL; } else if(node->data == data) { return node; } else if(node->data > data) { return search(node->left, data); } else { return search(node->right, data); } } ``` 7. 编写主函数进行测试。 ```c int main() { pNode root = createTree(); printf("先序遍历结果:"); preOrder(root); printf("\n中序遍历结果:"); inOrder(root); printf("\n后序遍历结果:"); postOrder(root); printf("\n请输入要查找的节点值:"); int data; scanf("%d", &data); pNode node = search(root, data); if(node == NULL) { printf("未找到该节点!"); } else { printf("已找到该节点,节点值为:%d", node->data); } return 0; } ``` 四、实验结果 经过测试,程序能够正确地实现二叉树的建立、遍历和查找等基本操作。 五、实验总结 通过本次实验,我们深入理解了二叉树的概念、性质和基本操作,并实现了二叉树的建立、遍历和查找等基本操作。同时,也加深了对指针和动态内存分配的理解。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值