二叉树遍历课程设计报告

沈阳航空航天大学

课 程 设 计 报 告

课程设计名称:

算法分析课程设计

课程设计题目:

二叉树深度优先遍历

   院:

    业:

   级:

   名:

   号:

指导教师:

完成时间: 2023 6 30

算法分析课程设计报

序号

评价项目

评分

满分

得分

1

课设态度,查阅资料和自我学习的能力。

10

2

课设题目的理解情况和完成情况,以及程序的正确性与完善性。

40

3

检查过程中问题回答的准确程度

20

4

课程设计报告的格式和内容,侧重考虑内容充实度、图表齐全度、对设计和实现过程的描述详实度、运行和调试的全面度等方面。

30

累计得分

指导教师评语:

                                                                             

课设成绩:     

指导教师签名

日期

    年   月   日

注:成绩评定采用五级记分制。优秀(90~100分)、良好(80~89分)、中等(70~79分)、及格(60~69分)、不及格(60分以下)

课程设计任务书

课程名称

算法分析课程设计        专业       

学生姓名

班级

学号

题目名称

二叉树深度优先遍历

起止日期

2023

年   6  月

19日起  至  2023

6  月  30  日 止

课设内容和要求:

一、课程设计内容

构建一个二叉树,对二叉树实现深度优先遍历,不允许使用递归,要求使用栈完成。具体要求:

1.构建一个二叉树,二叉树结点个数超过20个,并且二叉树左右节点分布均匀。

2.输出二叉数的先序遍历、中序遍历、后序遍历的结果。

二、课程设计要求

1.独立完成课程设计任务;

2.通过老师当场验收;

3.交出完整的课程设计报告。

参考资料:

[1] 张光河主编. 数据结构--Python语言描述. 北京:人民邮电出版社,2018

[2] 王硕等编著.  Python算法设计与分析. 北京:人民邮电出版社,2020

[3] 裘宗燕编著. 数据结构与算法(Python语言描述). 北京:机械工业出版社,2021

  •  )  不同意(   )  教研室主任签字:

指导教师(签名)

2023年

6

27

学生签名(签名)

2023年

6

27

课程设计总结

树是常用的数据结构。通过实验加深了我对树的遍历的认识,巩固了课本中所学的关于树的基本算法。按要求完成了实验内容。通过实验,有如下几点收获和体会:

  1. 通过实验还提高了一点改错能力,对于一些常见问题加深了印象。

2、编程需要有耐心,尤其实在单步调试的时候,更是马虎不得,有时候关键就是那么一步,错过了就得从头来过了。编程也需要勇气,要勇于发现自己的错误,也要勇于推翻自己之前的思路,要坚信"没有最好,只有更好"。编程,最好是一鼓作气,得天天"摸摸"它,时时想着它,要是过一阵再去碰它那就得先去读懂自己的程序了,一切的一切几乎都得从头开始。编程需要细心,有时一个不注意小错误就能引出大问题。编程也需要规范,不仅为了他人能看得懂程序,也为了方便自己以后程序的更改与进一步的完善。

3、程序由算法和数据结构组成,一个好的程序不仅算法重要,数据结构的设计也很重要。

4.以前在学 C++ 语言时总觉得函数的非递归调用是一样很复杂的算法,经常会理解不了而导致编程的错误。但在这次实验中,二叉树的先序、中序与后序的输出都用了非递归算法。而且用起来并不复杂,这使我更进一步学习理解了函数的递归调用并得到灵活的运用。经过本次实验基本上解决的一些所遇到的问题,我对二叉树的结构等有了较为深入的理解。我会继续我的兴趣编写程序的,相信在越来越好。

   

目  录

1  课程设计报告名称与项目背景

1.1 课程设计名称

1.2  课程设计项目背景

2 课设内容与要求

2.1  课程设计内容

2.2  课程设计要求

3  模块设计

3.1  总体设计

3.2  具体设计

3.2.1 先序创建模块

3.2.2 先序遍历模块

3.2.3 中序遍历模块

3.2.4 后序遍历模块

4  输出测试

参考文献

附录:

 1  课程设计报告名称与项目背景

    1.  课程设计名称

二叉树深度优先遍历

1.2  课程设计项目背景

树是数据结构中的重中之重,尤其以各类二叉树为学习的难点。先从整体上认识下二叉树及其他各种树的区别和用途。树有很多种,其中二拆树因为其特殊的结构和特点在计算上最为常用。常见的二叉树:二叉查找树,平衡二叉树(AVL),红黑树,字典树,满二叉树,完全二叉树,霍夫曼树,伸展树,最小堆,最大堆等,B+树,B-树则属于多路搜索树。在操作系统源程序中,树和森林被用来构造文件系统。我们看到的window和linux等文件管理系统都是树型结构。在编译系统中,如C编译器源代码中,二叉树的中序遍历形式被用来存放C 语言中的表达式。其次二叉树本身的应用也非常多,如哈夫曼二叉树用于JPEG编解码系统(压缩与解压缩过程)的源代码中,甚至于编写处理器的指令也可以用二叉树构成变长指令系统,另外二叉排序树被用于数据的排序和快速查找。用的最多的应该是平衡二叉树,有种特殊的平衡二叉树红黑树,查找、插入、删除的时间复杂度最坏为O(log n)Java集合中的TreeSet和TreeMap,C++ STL中的set、map,以及Linux虚拟内存的管理,都是通过红黑树去实现的。还有哈夫曼树编码方面的应用。B-Tree,B+-Tree在文件系统中的应用。Dijkstra算法是最短路径算法中为人熟知的一种,是单起点全路径算法。该算法被称为是“贪心算法”的成功典范。该算法如果不优化速度非常慢,如果用二叉树算法优化效率快很多,类似的,很多人工智能算法都是用二叉树优化的

2 课设内容与要求

2.1  课程设计内容

构建一个二叉树,对二叉树实现深度优先遍历,不允许使用递归,要求使用栈完成。具体要求:

1.构建一个二叉树,二叉树结点个数超过20个,并且二叉树左右节点分布均匀。

2.输出二叉数的先序遍历、中序遍历、后序遍历的结果。

2.2  课程设计要求

1.独立完成课程设计任务;

2.通过老师当场验收;

3.交出完整的课程设计报告。

3  模块设计

3.1  总体设计

首先申请节点空间,再通过先序建立的方法创建二叉树,二叉树采用链式存储结构,以链表和栈实现,每个节点里面有一个字符型数据和两个左右子树节点的指针,创建二叉树时先输入父节点的值,然后输入左子节点然后右子节点,空节点以#表示。前序遍历、中序遍历、后序遍历均非递归算法实现使用栈来实现。

图一程序流程图

3.2  具体设计

3.2.1 先序创建模块

图二 二叉树示例

算法的基本思路:为了能够确定新读入的结点链接到当前结点(双亲)的左子树还是右子树,引入了链接标志flag,其初始值为假。flag值为真,则表示需将新读入的结点s插入当前结点(双亲)p的右子树,否则插入p的左子树。

具体步骤主要包括如下三步:

(1) 如果新读入的数据非空,当flag值为假时,将新读入的结点链接到当前结点(双亲)p的左子树,同时当前结点(双亲)p入栈(作为待插入的右子树的双亲结点),然后把新读入的结点作为当前结点(双亲)p。当flag值为真时,将新读入的结点链接到当前结点(双亲)p的右子树,并将flag置为假;

(2) 如果新读入的数据为空,且flag为真,则栈顶元素出栈;

(3) 如果新读入的数据为空,且flag为假,则继续读入数据,此时数据若非空,则建立新结点s,并链接到当前结点的右子树,同时将当前结点(双亲)p指向s;若为空数据,则栈顶结点出栈给p,同时flag值置为1,表示左子树已经处理完毕,再读入新结点则放到双亲的右子树。若栈为空,则结束二叉树的创建。

2、按照图(2)所示,使用先序法创建二叉树,需要读入的数据依次为:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

A

B

#

C

D

#

#

#

E

#

F

G

H

#

#

K

#

#

#

表1数据输入表

3.2.2 先序遍历模块

1.根节点A入栈,并打印该结点的值,P指向其左孩子

图三 先序遍历过程图

  1. 继续遍历结点,此时B结点存在并打印该结点的值,则将该结点入栈,P指向B结点的左孩子但是左孩子为空,P指向B的右孩子。

图四 先序遍历过程图

3.继续遍历结点,此时C结点存在并打印该结点的值,则将该结点入栈,P指指向C节点的左孩子。

图五 先序遍历过程图

依次类推最终先序遍历输出为ABCDEFGHK

3.2.3 中序遍历模块

算法思想:

1.从根节点开始检索,如果当前节点不为空,则将当前节点入栈,让当前节点成为其左孩子节点,再继续上一步的操作

2.加入当前节点为空了,说明其父节点已经没有左孩子了,那么将栈顶元素出栈并输入

3.判断栈顶元素是否有右孩子,如果有右孩子,则停止依次继续出栈的操作,并检索它的右孩子,重复第一步;如果没有右孩子,则继续将栈顶元素出栈

4.当栈为空,并且当前节点为空时,遍历完成,退出;

分析:

首先从根节点开始,沿着根的左孩子,将左孩子依次进行入栈。当B入栈之后,B的左子树遍历完成所以B出栈。

图六 中序遍历过程图

接着指针指到C,将C入栈继续遍历C的左子树指针指到D将入栈因为D没有左子树所以D出栈。

图七 中序遍历过程图

接着指针到C因为C没有右子树所以C出栈。

图八 中序遍历过程图

依次类推最终中序遍历输出为BDCAEHGKF。

3.2.4 后序遍历模块

算法思想

1、沿着根的左孩子,依次入栈,直到左孩子为空;

2、读栈顶元素进行判定,若右孩子不空且未被访问,将右孩子执行第一步;

3、栈顶元素出栈。

分析

首先从根节点开始,沿着根的左孩子,将左孩子依次进行入栈。当D入栈之后,由于D没有右孩子,所以将D出栈,此时r指向D。

图九 后续遍历过程图

D出栈之后读栈顶元素CP指向C,发现C没有右孩子,然后将C出栈。

图十 后续遍历过程图

依次类推最终后序遍历输出DCBHKGFEA。

4  输出测试

1.运行改程序将如图的二叉数创建出来。

图十一 二叉树示例图

即输入:ABCD##E##FG##H##IJK##L##MN##O##。

回车将输出该二叉树的前序遍历、中序遍历、后序遍历如图所示:

图十二 运行结果图

2.若输入的二叉树为空树则会输出“树为空树”如图所示:

图十三 运行结果图

3.如果输入的树为仅有左子树如图所示:

图十四 二叉树示例图

则输出结果为:

图十五 运行结果图

4.如果输入的树为仅有右子树:

图十六 二叉树示例图

则输出结果为:

图十七 运行结果图

5.如果输入不符合二叉树的先序创建标准则会发生错误程序报错。

参考文献

[1] 桂劲松等.物联网系统设计(第2版)[M].北京:电子工业出版社,2017.

[2] 宋楠,韩广义.Arduino开发从零开始学:学电子的都玩这个[M].北京:清华大学出版社,2014.

[3] R. Schenkel, A. Theobald, G. Weikum. HOPI: An efficient connection index for complex XML document collections[C]. Proceedings of EDBT, Crete, Greece, 2004, 237-255.

[4] 谭浩强. C++程序设计(第3版)[M]. 清华大学出版社,2015

[5] 陆德旭. 人工智能教程----C++语言基础教程[M]. 青岛出版社,2018

[6] 张海龙. C++ Primer Plus(第6版)中文版[M]. 人民邮电出版社,2017

[7] 谭浩强. C程序设计(第五版)[M]. 清华大学出版社,2017

附录:

#include <iostream>

#include<stack>

#include<set>

#include<map>

using namespace std;

struct Btree {

char data;

Btree* lchild;

Btree* rchild;

};

void create(Btree*& root)//创建二叉树

{

char data;

cin >> data;

root = new Btree;

if (data == '#') root = NULL;

if (root != NULL)

{

root->data = data;

 create(root->lchild);

create(root->rchild);

}

}

void NORecursionprd(Btree*& tree) {//前序非递归算法

Btree* p = tree;

stack<Btree*> s;

s.push(tree);

while (!s.empty())

{

p = s.top();//获取栈顶元素

s.pop();//弹出栈顶元素

cout << p->data << '\t';

if (p->rchild) s.push(p->rchild);//先将右子树入栈

if (p->lchild)s.push(p->lchild);//再将左子树入栈,栈后进先出,符合前序遍历规则

}

}

void NORecursionldr(Btree*& tree)//中序遍历非递归算法

{

stack<Btree*> s;//建立栈

Btree* p = tree;

while (p != NULL || !s.empty()) {

while (p != NULL) {//依次将每个结点的左子树放入栈

s.push(p);

p = p->lchild;

}

if (!s.empty()) {//在栈非空时找到栈顶元素的右子树

p = s.top();

s.pop();

cout << p->data << '\t';//弹出栈顶元素,实现中序遍历

p = p->rchild;

}

}

}

void NORecursionlrd(Btree*& tree)

{

map<Btree*, int>judge;//利用map记录访问次数

stack<Btree*>s;//利用栈来模拟后序遍历

Btree* p = tree;//临时保存结点

while (p != NULL || !s.empty())

{

if (p != NULL)//如果结点不为空,一直往下找其左子树

{

s.push(p);

p = p->lchild;

judge[p] = 1;

}

else {//结点为空

p = s.top();//取栈顶元素

if (judge[p] == 2) {//若访问过两次,说明左右子树均已经访问,直接输出其数据即可

s.pop();

cout << p->data << '\t';

p = NULL;

}

else {//否则将访问其右子树,将其访问次数置为2

judge[p] = 2;

p = p->rchild;

}

}

}

}

int main()

{

Btree* tree = new Btree;

cout << "请输入首根结点数据:";

if (tree == NULL) cout << "树为空树!\n";

else {

create(tree);

cout << endl << "该树非递归先序遍历的结果为:\n";

NORecursionprd(tree);

cout << endl << "该树非递归中序遍历的结果为:\n";

NORecursionldr(tree);

cout << endl << "该树非递归后序遍历的结果为:\n";

NORecursionlrd(tree);

}

}

评论 19
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值