数据结构 实验报告11

一、实验目的和要求

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

要求:

(1)创建二叉树。

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

(3)实现后序遍历的非递归算法。
二、实验环境

编译器:Vscode +DevC++

系统:Windows10

CPU:i5-8265U@1.60GHz
三、实验内容

(1)创建二叉树。

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

(3)实现后序遍历的非递归算法。
四、实验过程
4.1 任务定义和问题分析

1.创建二叉树

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

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

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

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

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

            需要经过多重循环,首先通过while找到最左结点,然后遍历后继……
4.2 数据结构的选择和概要设计

必是选择链式结构;

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

        详细设计

第一尝试:

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

      接着对后序遍历进行修改

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

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

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

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

      2.再遍历其后继

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

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

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

进入了死循环————CDBCDB

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

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

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

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

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

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

五、测试及结果分析
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);
     
    }

 

  • 19
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
一、实验目的: 理解二叉树特别是完全二叉树的性质,掌握二叉树的存储结构(二叉链表);熟练掌握二叉树的常用操作算法(初始化、插入结点、删除结点、遍历等);初步掌握二叉树的应用。 二、实验内容: 要求采用二叉链表作为存储结构,完成二叉树的建立,前序、中序和后序遍历的操作,求所有叶子及结点总数的操作等。 具体要求如下: ①给出基于二叉链表的二叉树类的定义; ②给出二叉树初始化(构造函数)的实现; ③给出二叉树三种遍历算法的递归实现; ④二叉树先序遍历的非递归算法实现; ⑤利用二叉树的遍历算法求二叉树的结点数、二叉树的叶结点数、二叉树的高度; ⑥二叉树的撤销删除 三、实验步骤: 1、需求分析: 本演示程序用JAVA编写,完成树的生成,任意位置的插入、删除,以及遍历二叉树中的结点,查找和修改树中元素的值。 ① 输入的形式和输入值的范围:插入元素时需要输入插入的位置和元素的值;删除元素时输入删除元素的位置;遍历时采用三种遍历方法中的一种遍历方法;修改操作时需要输入的元素的值;查找操作时,需要找到要查找元素的位置。在所有输入中,元素的值都是整数。 ② 输出的形式:在所有四种操作中都显示操作是否正确以及操作后树中的内容。其中删除操作后显示删除的元素的值,遍历二叉树中的元素,查找操作、修改操作后显示修改的值。 ③ 程序所能达到的功能:完成树的生成(通过插入操作)、插入、删除、遍历、查找、修改操作。 ④ 测试数据: A. 树中已有以50,25,75,12,37,43,30,33,87,93,97为关键字的结点 B. 插入操作中依次输入10,20,30,40,50,60,70,80,90,100十个数 C. 删除操作中输入10删除值为10的元素 D. 查找操作中输入20,30,40,50返回这个元素在树中的位置 2.概要设计: 1)为了实现上述程序功能,需要定义树的抽象数据类型: public int iData; public double dData; public Node leftChild; public Node rightChild; private Node root;int value; private Node getSuccessor; 基本操作:{ Tree () 操作结果:构造一个空的二叉树 insert () 初始条件:是否存在一个空二叉树 操作结果:往二叉树中插入数值 delete () 初始条件:存在一非空的二叉树 操作条件:将二叉树中的元素删除 displayTree () 初始条件:存在一非空的树 操作条件:显示非空树中的所有元素的值 getString () 初始条件:存在一非空的二叉树 操作结果:返回整个字符串的数值 getChar () 初始条件:存在一非空的二叉树 操作结果:返回字符型的数值 getInt () 初始条件:存在一非空的二叉树 操作结果:返回整型的数值 find () 初始条件:存在一非空二叉树 操作结果:从二叉树中查找某一元素 traverse () 初始条件:存在一非空的二叉树 操作结果:对二叉树中的元素进行遍历 preorder () 初始条件:存在一非空的二叉树 操作结果:对二叉树中的元素进行先根遍历 inOrder () 初始条件:存在一非空的二叉树 操作结果:对二叉树中的元素进行中根遍历 postOrder () 初始条件:存在一非空的二叉树 操作结果:对二叉树中的元素进行后根遍历 DisplayNode () 初始条件:存在一非空的二叉树 操作结果:显示出二叉树中的整形数值和双精度浮点型数值 public static void main 操作结果:调用主函数
好的,下面是数据结构二叉树的实验报告。 一、实验目的 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、付费专栏及课程。

余额充值