数据结构与算法_二叉树遍历

本文详细介绍了二叉树的四种遍历方式:前序遍历、中序遍历、后序遍历和层序遍历,通过图示和代码展示了遍历过程。同时,总结了C++编程中构造析构函数的作用和一般特点。
摘要由CSDN通过智能技术生成

0. 前言

二叉树的顺序存储结构就是用一维数组存储二叉树中的节点,并且节点的存储位置,
也就是数组的下标要能体现节点之间的逻辑关系
存储的方式以数组存储,读取以二叉树的特点输出

0.1 二叉树的结构体
typedef struct MyTree
{
 	char data;
 	struct MyTree *Lchild, *Rchild;
 	MyTree();
 	~MyTree();
} *MyTreeNode;

1.二叉树的遍历

二叉树的遍历是指从二叉树的某个节点出发,按照某种次序依次访问二叉树中的所有节点,使得每个节点被访问一次,且仅被访问一次

1.1 二叉树前序遍历(根→左→右)

下图遍历结果:ABDGHCEIF
前序遍历
执行代码

void preOrderTraverse(MyTreeNode T, int level)
{
 	if (T)
 	{
  		visit(T->data, level + 1);//访问根节点
  		preOrderTraverse(T->Lchild, level + 1);//左子树遍历
  		preOrderTraverse(T->Rchild, level + 1);//右子树遍历
 	}
}
1.2 二叉树的中序遍历(左-根-右)

遍历结果:
中序遍历结果
中序遍历代码

void MidOrderTraverse(MyTreeNode T, int level)
{
 	if (T)
 	{
  		MidOrderTraverse(T->Lchild, level + 1);//左子树遍历
  		visit(T->data, level + 1);//访问根节点
  		MidOrderTraverse(T->Rchild, level + 1);//右子树遍历
 	}
}
1.3 后序遍历(左-右-根)

遍历结果:GHDBIEFCA
二叉树后序遍历
后序遍历代码

void PostOrderTraverse(MyTreeNode T, int level)
{
 	if (T)
 	{
  		PostOrderTraverse(T->Lchild, level + 1);//左子树遍历
  		PostOrderTraverse(T->Rchild, level + 1);//右子树遍历
  		visit(T->data, level + 1);//访问根节点
 	}
}
1.4 二叉树层序遍历结果

层序遍历结果
层序遍历代码

void LevelOrderTraverse(MyTreeNode T)
{
 	queue<MyTreeNode> s;
 	MyTreeNode p;
 	MyTreeNode q;
 	p = T;
 	if (p == NULL)
 	{
  		cout << "tree is empty" << endl;
  		return;
 	}
 	s.push(p);//将根节点入队
 	while (!s.empty())
 	{
  		//根节点入队
 		 p = s.front();//队列s头部压入p中
  		s.pop();
  		//左节点入队
  		if (NULL != p->Lchild)
  		{
   			q = p->Lchild;
  			s.push(q);
 		 }
  		if (NULL != p->Rchild)
  		{
   			q = p->Rchild;
   			s.push(q);
  		}
  		cout << p->data << endl;
 	}
}

2. 完整代码

#include<iostream>
#include<stack>
#include<queue>//单纯的队列容器
using namespace std;
typedef struct MyTree
{
 	char data;
 	struct MyTree *Lchild, *Rchild;
	 MyTree();
 	~MyTree();
} *MyTreeNode;
//MyTree()函数实现
MyTree::MyTree()
{
 	data = '0';
 	Lchild = Rchild = nullptr;
}
//MyTree()函数实现
MyTree::~MyTree()
{
 	if (Lchild != nullptr)
  		delete[] Lchild;
 	Lchild = nullptr;
 	if (Rchild != nullptr)
  		delete[] Rchild;
 	Rchild = nullptr;
}
//创建一颗二叉树,约定用户遵照前序遍历的方式输入数据
void CreatMyTree(MyTreeNode & BiTree)
{
 	char cTreeData;
 	cin >> cTreeData;
 	if ('#' == cTreeData)//#  表示结束
 	{
  		cTreeData = NULL;
 	}
 	else
 	{
  		BiTree = new MyTree;
  		BiTree->data = cTreeData;
  		CreatMyTree(BiTree->Lchild);
  		CreatMyTree(BiTree->Rchild);
 	}
}
//访问二叉树的具体节点的函数
void visit(char cTree, int level)
{
 	printf("%c 位于第 %d 层\n", cTree, level);
}
//前序遍历二叉树-递归
void preOrderTraverse(MyTreeNode T, int level)
{
 	if (T)
	 {
  		visit(T->data, level + 1);//访问根节点
  		preOrderTraverse(T->Lchild, level + 1);//左子树遍历
  		preOrderTraverse(T->Rchild, level + 1);//右子树遍历
 	}
}
//中序遍历二叉树-递归
void MidOrderTraverse(MyTreeNode T, int level)
{
 	if (T)
 	{
 		 MidOrderTraverse(T->Lchild, level + 1);//左子树遍历
 		 visit(T->data, level + 1);//访问根节点
 		 MidOrderTraverse(T->Rchild, level + 1);//右子树遍历
 	}
}
//后序遍历二叉树-递归
void PostOrderTraverse(MyTreeNode T, int level)
{
 	if (T)
 	{
 		 PostOrderTraverse(T->Lchild, level + 1);//左子树遍历
 		 PostOrderTraverse(T->Rchild, level + 1);//右子树遍历
 		 visit(T->data, level + 1);//访问根节点
 	}
}
//层次遍历二叉树
void LevelOrderTraverse(MyTreeNode T)
{
 	queue<MyTreeNode> s;
 	MyTreeNode p;
 	MyTreeNode q;
 	p = T;
 	if (p == NULL)
 	{
 		 cout << "tree is empty" << endl;
  		 return;
 	}
 	s.push(p);//将根节点入队
 	while (!s.empty())
 	{
 		 //根节点入队
 		 p = s.front();//队列s头部压入p中
 		 s.pop();
  		//左节点入队
  		if (NULL != p->Lchild)
  		{
   			q = p->Lchild;
   			s.push(q);
  		}
  		if (NULL != p->Rchild)
  		{
   			q = p->Rchild;
   			s.push(q);
  		}
  		cout << p->data << endl;
 	}
}
int main()
{
 	//输入实例:ABDH##I##E#J##CF#K##G###
 	MyTreeNode tree;//创建二叉树指针
	 cout << "请输入一个二叉树序列:" << endl;
	 CreatMyTree(tree);
	 //打印前序遍历的结果
 	cout << endl << "前序遍历的结果为:" << endl;
 	preOrderTraverse(tree, 0);
 	//打印中序遍历的结果
 	cout << endl << "中序遍历的结果为:" << endl;
 	MidOrderTraverse(tree, 0);
 	//打印后序遍历的结果
	 cout << endl << "后序遍历的结果为:" << endl;
 	PostOrderTraverse(tree, 0);
 	cin.get();
 	cin.get();
 	cin.get();
 	return 0;
}

3.总结

3.1该如何理解构造析构函数的存在:

因为类或者结构体的存在,相当于重新定义一个数据类型,则个数据类型不仅仅在像通常所理解的整数,字符类型,而是包含了多种特征的一个类型。因此构造函数的存在就是用来给这样的一个数据类型(对象)来初始化(因为其它数据类型在使用时也需要初始化,计算机内部要给变量创建内存空间并赋值,不初始化会导致内存错误);而析构函数的存在就像是使用完指针,将指针的内存释放一样,也需要释放对象的内存空间。

3.2 C++编程的一般特点:

在解决一个实际问题的时候,并不像通常所理解的那样,直接对问题求解,因为计算机内部需要对代码进行编译,也就是说需要开辟内存,释放内存等一系列操作,因而在解决一个问题时通常需要准备工作(包括:定义变量、指针申请内存、文件打开预定义、类或结构体对象初始化);在解决完问题时,也需要同计算机内存进行释放,工作包括(指针释放、文件关闭、类或结构体变量析构)

3.3 中序遍历过程图示

已知的二叉树组成
二叉树
中序遍历图示
在这里插入图片描述

4.参考文章

https://blog.csdn.net/wjwfighting/article/details/81670229
https://blog.csdn.net/shell33168/article/details/88645346
https://www.cnblogs.com/didiaodidiao/p/9128762.html

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值