数据结构 实验报告10

一、实验目的和要求

目的:熟悉树型结构的建立并实现二叉树深度的求解

要求:两种及以上存储结构(建议 顺序存储结构和链式存储结构各一)、两种及以上方法(建议 递归遍历和层次遍历方法各一)。分析各代码性能。

二、实验环境

编译器:Vscode +DevC++

系统:Windows10

CPU:i5-8265U@1.60GHz

三、实验内容

(1)两种及以上存储结构

(2)两种及以上方法建立

(3)分析四种及以上代码的性能

四、实验过程

4.1 任务定义和问题分析

顺序存储结构

使用一块连续的存储空间存储二叉树

优点:结构紧凑,没有额外的指针空间,随机存取能力强

缺点:插入和删除元素时操作费时,所需空间大时,容易崩溃,不利于对碎片空间的利用

由完全二叉树结点性质可得出结点的序号关系:

编号为i的结点的左儿子的编号为2i(如果存在左结点的话)

编号为i的结点的右儿子的编号为2i+1(如果存在右结点的话)

而非完全二叉树也可以使用上面的规则编号,就是会有许多编号无人认领,造成浪费

 

链式存储结构

二叉树是一种非线性的结构

使用链式结构能够很直观地表示二叉树的逻辑结构

并且即使二叉树是非二叉树的时候 仍旧能够很好的表示,不会像顺序结构产生空结点

优点:能够很好的利用内存中的碎片空间,提高内存空间的利用效率

缺点:不能随机存取某个结点,需要进行遍历,耗时

 

递归遍历分为前序遍历,中序遍历,后序遍历三种。

三者复杂度相同

前序遍历:对于当前节点,先输出该节点,然后输出他的左孩子,最后输出他的右孩子。

中序遍历:对于当前结点,先输出它的左孩子,然后输出该结点,最后输出它的右孩子。

后序遍历:对于当前结点,先输出它的左孩子,然后输出它的右孩子,最后输出该结点。

层序遍历:又称广度优先遍历,从名字可以看出和广度优先搜索有关,遍历方式即从根结点开始按层遍历,根结点为第1层,其子结点为第二层,依次从上到下,从左到右遍历。

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

数据结构选择顺序和链式两种

遍历方式选择前序、中序、后序、层序四种

 

要想降低实验难度,就需要尽量使得结点能够兼容顺序和链式两种,而前序、中序、后序、层序要能兼容顺序和链式两种数据结构

(这里的兼容既可以是接口兼容,也可以是名称兼容)

    1. 详细设计

结点使用一个类来表示,尽量兼容顺序结构和链式结构

类内包含数据域,左儿子指针,右儿子指针。

 

前序、中序、后序三者的代码主要内容都一样,就是前后遍历顺序不一样,较为容易设计 递归边界是指定结点为空

 

层序遍历需要利用队列才可顺利运行

而队列的大小在不知道树的大小之前需要尽量设置大一点

 

在存储结构和遍历方法之间还有一个操作:建树

在实际书写建树时,遇到了很多障碍,我在书写时总是想写成线段树,一度进行不下去,不得已查阅资料,对树进行了复习。建树即是构造好根结点后向此二叉树中插入结点即可。

 

求二叉树的深度:

深搜----一条路径走到头,然后再拐回来试试其他路径

在书写代码时遇到诸多bug  最后都集中到不能返回结点中的数据这个问题

最后发现是 我使用的是返回临时变量 和&起冲突了

(真·排bug1小时)

五、测试及结果分析

5.1 实验数据

 

 

所以深度为3

正确

5.2 结果及分析

上面已经很好的将两种数据结构的优劣讲清楚了

而遍历方式上,递归遍历需要更多的栈空间

层序遍历需要多的辅助空间,并且代码复杂程度上更大

 

在无特殊要求情形下,应该使用链式结构+递归遍历来实现二叉树

六、实验收获

熟悉了二叉树的性质于建立

 

七、参考文献

树的前序遍历、中序遍历、后序遍历详解

 

八、附录(源代码)

#include <cstddef>

#include <iostream>

#include <queue>

#include <stack>

#include <stdlib.h>

using namespace std;

//二叉树结点定义

template<typename DataType>class Bitnode

{

public:

    //构建空结点

    Bitnode()

    {

        lchild = NULL;

        rchild = NULL;

    }

    //构建指定数据域的结点

    Bitnode(DataType newData)

    {

        data = newData;

        lchild = NULL;

        rchild = NULL;

    }

    //获取数据域

    DataType getData()

    {

        return data;

    }

    //获取左子结点

    Bitnode<DataType>* getLchild()

    {

        return lchild;

    }

    //获取右子结点

    Bitnode<DataType>* getRchild()

    {

        return rchild;

    }

// private:

    DataType data;//数据域

    Bitnode *lchild;//左子树指针

    Bitnode *rchild;//右子树指针

};

// template <class T>

// struct Bitnode

// {

//     Bitnode(const T &data)

//         : lchild(NULL), rchild(NULL), data(data)

//     {

//     }

//     Bitnode<T>*getLchild()

//     {

//         return lchild;

//     }

//     Bitnode<T> *getRchild()

//     {

//         return rchild;

//     }

//     T getData()

//     {

//         return data;

//     }

//     Bitnode<T> *lchild;

//     Bitnode<T> *rchild;

//     T data;

// };

//二叉树线性表示

template <typename DataType>

class SeqBt

{

private:

    int maxNode;

    DataType *data;

public:

    SeqBt(int nodes)

    {

        if(nodes>0)

        {

            maxNode = nodes;

            data = new DataType[maxNode];

        }

    }

    ~SeqBt()

    {

        delete[] data;

    }

};

//二叉树链式表示

template <typename DataType>class Bintree

{

private:

    Bitnode<DataType> *root;//设置根结点

public:

    Bintree()

    {

        root = new Bitnode < DataType > ();//初始化根结点

    }

    //建立有数据的根结点

    Bintree(DataType rootData)

    {

        root = new Bitnode<DataType>(rootData);

        root->lchild = NULL;

        root->rchild = NULL;

    }

    Bintree(const DataType *array, size_t size, const DataType &invalid) //构造函数

    {

        size_t index = 0;

        CreateBinTree(root, array, size, index, invalid);

    }

    void preorder(Bitnode<DataType> *node);

    void inorder(Bitnode<DataType> *node);

    void postorder(Bitnode<DataType> *node);

    void layorder(Bitnode<DataType> *node);

    int getDepth(int numberofnodes);

    void CreateBinTree(Bitnode<DataType> *&root, const DataType *array, size_t size, size_t &index, const DataType &invalid)

    {

        if (index < size && invalid != array[index])

        {

            //根节点

            Bitnode<DataType> *newNode = new Bitnode<DataType> (array[index]);

            CreateBinTree(newNode->lchild, array, size, ++index, invalid);

            CreateBinTree(newNode->rchild, array, size, ++index, invalid);

            root = newNode;

        }

    }

    Bitnode<DataType>*getRoot()

    {

        return root;

    }

    size_t _Height(Bitnode<DataType>* root) //二叉树的高度

    {

        if (NULL == root)

            return 0;

        if (NULL == root->lchild && NULL == root->rchild)

            return 1;

        return _Height(root->lchild) > _Height(root->rchild) ? _Height(root->lchild) + 1 : _Height(root->rchild) + 1;

    }

};

//层序遍历

template <typename DataType>

void Bintree<DataType>::layorder(Bitnode<DataType> *node)

{

    int max = 50;

    int front, rear;

    Bitnode<DataType> *current;

    int count = 0;

    if(node!=NULL)

    {

        Bitnode<DataType>* queue[max] ;

        front = rear = 0;

        queue[rear] = node;

        rear++;

        count++;

        while(count!=0)

        {

            current = queue[front];

            cout << current->getData()<<"\n";

            if(current->getLchild()!=NULL)

            {

                queue[rear] = current->getLchild();

                rear = (rear + 1) % max;

                count++;

            }

            if (current->getRchild() != NULL)

            {

                queue[rear] = current->getRchild();

                rear = (rear + 1) % max;

                count++;

            }

            front = (front + 1) % max;

            count--;

        }

    }

}

//求二叉树的深度

template <typename DataType>

int Bintree<DataType>::getDepth(int numberofnodes)

//传入参数结点的个数

{

    Bitnode<DataType> *nodestack [numberofnodes];//设置存储二叉树结点的栈

    int depthStack[numberofnodes];//声明深度栈

    int currentDepth=0, maxDepth = 0;//当前深度,最大深度



    int top = -1;//栈的游标指针初始值

    Bitnode<DataType> *node = root;//设置当前访问的结点指针并初始化为根结点

    if(node!=NULL)//判空

    {

        currentDepth = 1;//初始化深度为1,根结点为第一层

        do//循环遍历整棵树 将访问的结点入栈

        //不停反复查找最长的路径

        {

            while(node!=NULL)

            {

                nodestack[++top] = node;//将访问到的不为空的结点入栈

                depthStack[top] = currentDepth;//将相应的深度入栈

                node = node->getLchild();//继续访问当前结点左子结点

                currentDepth++;//更新深度

            }//走到了当前路径最深处

            node = nodestack[top];//出栈栈顶,更换路径

            currentDepth = depthStack[top--];

            cout << maxDepth << " "<<currentDepth<<"\n";

            if(node->getLchild()==NULL&&node->getRchild()==NULL)//是否为叶子结点

                if(currentDepth>maxDepth)//更新最大深度

                    maxDepth = currentDepth;

            node = node->getRchild();//左子结点访问完毕 开始访问右子结点

            currentDepth++;//更新深度

        } while (!(node==NULL&&top==-1));

        

    }

    return maxDepth;

}







#include"tree-s.h"

#include<cstdio>

int main()

{

    // char pStr[] = {'A', 'B', 'D', '#', '#', '#', 'C', 'E', '#', '#', 'F'};

    char pStr[] = {'A', 'B', 'C', 'D'};

    Bintree<char> bt1(pStr, sizeof(pStr) / sizeof(pStr[0]), '#');

    // Bintree<int> bt1;

    cout << "递归前序遍历:" << endl;

    // system("pause");

    bt1.preorder(bt1.getRoot());

    

    

    cout << endl;

    cout << "递归中序遍历:" << endl;

    bt1.inorder(bt1.getRoot());

    cout << endl;

    cout << "递归后序遍历:" << endl;

    bt1.postorder(bt1.getRoot());

    cout << endl;

    cout << "层次遍历:" << endl;

    bt1.layorder(bt1.getRoot());

    cout << "\n";

    cout << "深度:"<< "\n";

    cout << bt1._Height(bt1.getRoot());

    cout << "\n";

    system("pause");

}

 

  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值