网站导航
:
网学
原创论文
原创专题
网站设计
最新系统
原创论文
论文降重
发表论文
论文发表
UI设计定制
论文答辩PPT格式排版
期刊发表
论文专题
最新论文
推荐专题
热门论文
论文专题
网站首页
论文模板
设计资源
程序设计
编程文档
营销学习
设计下载
参考使用
网学资源
网络学习
学习知识
交易代码
关于网学
安全工程
自动化
保险
表演
财务管理
参考选题
论文选题-查重参考论文
参考论文大全
电气工程及其自动化
电子论文
电子信息工程
电子商务
法律
法学
工程管理
公共关系学
公共事业管理
公路工程
公路交通运输
工商管理
广告学
国际经济与贸易
汉语国际教育
汉语言文学
环境科学与工程
化学
会计学
护理学
交通运输
教育管理
教育研究生
经济学
金融
计算机科学与技术
计算机应用
酒店管理
机械电子工程
机械论文
机械设计制造及其自动化
论文查重
旅游管理
python开发
生物工程
环境工程
数字媒体技术
ios开发
工程造价
家庭教育
农学
家政学
原创检测通过
期刊发表方法
当前位置:
网学
>
设计资源
>
.Net编程
> 正文
C#与数据结构--二叉树的遍历
论文降重修改服务、格式排版等
获取论文
论文降重及排版
论文发表
相关服务
二叉树的存储可分为两种:顺序存储结构和链式存储结构。
1.
顺序存储结构
把一个满二叉树自上而下、从左到右顺序编号,依次存放在数组内,可得到图6.8(a)所示的结果。设满二叉树结点在数组中的索引号为i,那么有如下性质。
(1)
如果i = 0,此结点为根结点,无双亲。
(2)
如果i > 0,则其双亲结点为(i -1) / 2 。(注意,这里的除法是整除,结果中的小数部分会被舍弃。)
(3)
结点i的左孩子为2i + 1,右孩子为2i + 2。
(4)
如果i > 0,当i为奇数时,它是双亲结点的左孩子,它的兄弟为i + 1;当i为偶数时,它是双新结点的右孩子,它的兄弟结点为i – 1。
(5)
深度为k的满二叉树需要长度为2
k-1
的数组进行存储。通过以上性质可知,使用数组存放满二叉树的各结点非常方便,可以根据一个结点的索引号很容易地推算出它的双亲、孩子、兄弟等结点的编号,从而对这些结点进行访问,这是一种存储二叉满二叉树或完全二叉树的最简单、最省空间的做法。为了用结点在数组中的位置反映出结点之间的逻辑关系,存储一般二叉树时,只需要将数组中空结点所对应的位置设为空即可,其效果如图6.8(b)所示。这会造成一定的空间浪费,但如果空结点的数量不是很多,这些浪费可以忽略。一个深度为k的二叉树需要2
k-1
个存储空间,当k值很大并且二叉树的空结点很多时,最坏的情况是每层只有一个结点,再使用顺序存储结构来存储显然会造成极大地浪费,这时就应该使用链式存储结构来存储二叉树中的数据。
1.
链式存储结构
二叉树的链式存储结构可分为二叉链表和三叉链表。二叉链表中,每个结点除了存储本身的数据外,还应该设置两个指针域left和right,它们分别指向左孩子和右孩子(如图6.9(a)所示)。当需要在二叉树中经常寻找某结点的双亲,每个结点还可以加一个指向双亲的指针域parent,如图6.9(b)所示,这就是三叉链表。
图6.10所示的是二叉链表和三叉链表的存储结构,其中虚线箭头表示parent指针所指方向。
二叉树还有一种叫双亲链表的存储结构,它只存储结点的双亲信息而不存储孩子信息,由于二叉树是一种有序树,一个结点的两个孩子有左右之分,因此结点中除了存放双新信息外,还必须指明这个结点是左孩子还是右孩子。由于结点不存放孩子信息,无法通过头指针出发遍历所有结点,因此需要借助数组来存放结点信息。图6.10(a)所示的二叉树使用双亲链表进行存储将得到图6.11所示的结果。由于根节点没有双新,所以它的parent指针的值设为-1。
双亲链表中元素存放的顺序是根据结点的添加顺序来决定的,也就是说把各个元素的存放位置进行调换不会影响结点的逻辑结构。由图6.11可知,双亲链表在物理上是一种顺序存储结构。二叉树存在多种存储结构,选用何种方法进行存储主要依赖于对二叉树进行什么操作来确定。而二叉链表是二叉树最常用的存储结构,下面几节给出的有关二叉树的算法大多基于二叉链表存储结构。
6.3 二叉树的遍历
二叉树遍历(Traversal)就是按某种顺序对树中每个结点访问且只能访问一次的过程。访问的含义很广,如查询、计算、修改、输出结点的值。树遍历本质上是将非线性结构线性化,它是二叉树各种运算和操作的实现基础,需要高度重视。
6.3.1 二叉树的深度优先遍历
图
6.12
二叉树的递归定义
D
L
R
我们是用递归的方法来定义二叉树的。每棵二叉树由结点、左子树、右子树这三个基本部分组成,如果遍历了这三部分,也就遍历了整个二叉树。如图6.12所示,D为二叉树中某一结点,L、R分别为结点D的左、右子树,则其遍历方式有6
种:
先左后右
先右后左先序
DLR DRL
中序
LDR RDL
后序
LRD RLD
这里只讨论先左后右的三种遍历算法。
如图6.13所示,在沿着箭头方向所指的路径对二叉树进行遍历时,每个节点会在这条搜索路径上会出现三次,而访问操作只能进行一次,这时就需要决定在搜索路径上第几次出现的结点进行访问操作,由此就引出了三种不同的遍历算法。
1.
先序遍历
若二叉树为非空,则过程为:
(1)
访问根节点。
(2)
先序遍历左子树。
(3)
先序遍历右子树。图6.13中,先序遍历就是把标号为(1)的结点按搜索路径访问的先后次序连接起来,得出结果为:ABDECF。
2.
中序遍历
若二叉树为非空,则过程为:
(1)
按中序遍历左子树。
(2)
访问根结点。
(3)
按中序遍历右子树。图6.13中,先序遍历就是把标号为(2)的结点按搜索路径访问的先后次序连接起来,得出结果为:DBEACF。
3.
后序遍历
若二叉树为非空,则过程为:
(1)
按后序遍历左子树。
(2)
按后序遍历右子树
(3)
访问根结点。图6.13中,先序遍历就是把标号为(3)的结点按搜索路径访问的先后次序连接起来,得出结果为:DEBFCA。【例6-1 BinaryTreeNode.cs】二叉树结点类
点击展开示例
using
System;
public class Node
{
//成员变量
private object _data; //数据
private Node _left; //左孩子
private Node _right; //右孩子
public object Data
{
get
{ return _data; }
}
public Node Left //左孩子
{
get
{ return _left; }
set
{ _left = value; }
}
public Node Right //右孩子
{
get
{ return _right; }
set
{ _right = value; }
}
//构造方法
public Node(object data)
{
_data = data;
}
public override string ToString()
{
return _data.ToString();
}
}
Node类专门用于表示二叉树中的一个结点,它很简单,只有三个属性:Data表示结点中的数据;Left表示这个结点的左孩子,它是Node类型;Right表示这个结点的右孩子,它也是Node类型。【例6-1 BinaryTree.cs】二叉树集合类
战场展开示例
using
System;
public class BinaryTree
{ //成员变量
private Node _head; //头指针
private string cStr; //用于构造二叉树的字符串
public Node Head //头指针
{
get
{ return _head; }
}
//构造方法
public BinaryTree(string constructStr)
{
cStr = constructStr;
_head = new Node(cStr[0]); //添加头结点
Add(_head, 0); //给头结点添加孩子结点
}
private void Add(Node parent, int index)
{
int leftIndex = 2 * index + 1; //计算左孩子索引
if (leftIndex < cStr.Length) //如果索引没超过字符串长度
{
if (cStr[leftIndex] != ''#'') //''#''表示空结点
{ //添加左孩子
parent.Left = new Node(cStr[leftIndex]);
//递归调用Add方法给左孩子添加孩子节点
Add(parent.Left, leftIndex);
}
}
int rightIndex = 2 * index + 2;
if (rightIndex < cStr.Length)
{
if (cStr[rightIndex] != ''#'')
{ //添加右孩子
parent.Right = new Node(cStr[rightIndex]);
//递归调用Add方法给右孩子添加孩子节点
Add(parent.Right, rightIndex);
}
}
}
public void PreOrder(Node node) //先序遍历
{
if (node != null)
{
Console.Write(node.ToString()); //打印字符
PreOrder(node.Left); //递归
PreOrder(node.Right); //递归
}
}
public void MidOrder(Node node) //中序遍历
{
if (node != null)
{
MidOrder(node.Left); //递归
Console.Write(node.ToString()); //打印字符
MidOrder(node.Right); //递归
}
}
public void AfterOrder(Node node) //后继遍历
{
if (node != null)
{
AfterOrder(node.Left); //递归
AfterOrder(node.Right); //递归
Console.Write(node.ToString()); //打印字符
}
}
}
BinaryTree是一个二叉树的集合类,它属于二叉链表,实际存储的信息只有一个头结点指针(Head),由于是链式存储结构,可以由Head指针出发遍历整个二叉树。为了便于测试及添加结点,假设BinaryTree类中存放的数据是字符类型,第5行声明了一个字符串类型成员cStr,它用于存放结点中所有的字符。字符串由满二叉树的方式进行构造,空结点用‘#’号表示(参考本章“二叉树存储结构”这一小节中的“顺序存储结构”)。图6.13所示的二叉树可表示为:“ABCDE#F”。11~
16行的构造方法传入一个构造字符串,并在Add()方法中根据这个字符串来构造二叉树中相应的结点。需要注意,这个构造方法只用于测试。
17~
39行的Add()方法用于添加结点,它的第一个参数parent表示需要添加孩子结点的双亲结点,第二个参数index表示这个双亲结点的编号(编号表示使用顺序存储结构时它在数组中的索引,请参考
本章“二叉树存储结构”这一小节中的“顺序存储结构”)。添加孩子结点的方法是先计算孩子结点的编号,然后通过这个编号在
cStr中取出相应的字符,并构造新的孩子结点用于存放这个字符,接下来递归调用Add()方法给孩子结点添加它们的孩子结点。注意,这个方法只用于测试。
40~
48行代码的PreOrder()方法用于先序遍历,它的代码跟之前所讲解的先序遍历过程完全一样。
49~
57行代码的MidOrder()方法用于中序遍历。
58~
66行代码的AfterOrder()方法用于后序遍历。
以上三个方法都使用了递归来完成遍历,这符合二叉树的定义。【例6-1 Demo6-1.cs】二叉树深度优先遍历测试
点击展开示例
using
System;
class Demo6_1
{
static void Main(string args)
{ //使用字符串构造二叉树
BinaryTree bTree = new BinaryTree("ABCDE#F");
bTree.PreOrder(bTree.Head); //先序遍
Console.WriteLine();
bTree.MidOrder(bTree.Head); //中序遍
Console.WriteLine();
bTree.AfterOrder(bTree.Head); //后序遍
Console.WriteLine();
}
}
运行结果: ABDECFDBEACFDEBFCA
6.3.2 二叉树的宽度优先遍历
之前所讲述的二叉树的深度优先遍历的搜索路径是首先搜索一个结点的所有子孙结点,再搜索这个结点的兄弟结点。是否可以先搜索所有兄弟和堂兄弟结点再搜索子孙结点呢?由于二叉树结点分属不同的层次,因此可以从上到下、从左到右依次按层访问每个结点。它的访问顺序正好和之前所述二叉树顺序存储结构中的结点在数组中的存放顺序相吻合。如图6.13中的二叉树使用宽度优先遍历访问的顺序为:ABCDEF。这个搜索过程不再需要使用递归,但需要借助队列来完成。
(1)
将根结点压入队列之中,开始执行步骤(2)。
(2)
若队列为空,则结束遍历操作,否则取队头结点D。
(3)
若结点D的左孩子结点存在,则将其左孩子结点压入队列。
(4)
若结点D的右孩子结点存在,则将其右孩子结点压入队列,并重复步骤(2)。【例6-2 BinaryTreeNode.cs.cs】二叉树结点类,使用例6-1同名文件。【例6-2 LevelOrderBinaryTree.cs】包含宽度优先遍历方法的二叉树集合类打开例6-1的【BinaryTree.cs】文件,在BinaryTree类中添加如入方法后另存为LevelOrderBinaryTree.cs文件。
点击展开示例
public void LevelOrder() //宽度优先遍历
{
Queue queue = new Queue(); //声明一个队例
queue.Enqueue(_head); //把根结点压入队列
while (queue.Count > 0) //只要队列不为空
{
Node node = (Node)queue.Dequeue(); //出队
Console.Write(node.ToString()); //访问结点
if (node.Left != null) //如果结点左孩子不为空
{ //把左孩子压入队列
queue.Enqueue(node.Left);
}
if (node.Right != null) //如果结点右孩子不为熔
{ //把右孩子压入队列
queue.Enqueue(node.Right);
}
}
}
【例6-2 Demo6-2.cs】二叉树宽度优先遍历测试
点击展开示例
using
System;
class Demo6_2
{
static void Main(string args)
{ //使用字符串构造二叉树
BinaryTree bTree = new BinaryTree("ABCDE#F");
bTree.LevelOrder();
}
}
运行结果:ABCDE
上一篇资讯:
关闭VisualStudio实时调试器
下一篇资讯:
.Net中操作Excel
相关资讯
相关文章
.Net中操作Excel
ServerApplicationUnavailable解决方案
Asp.net页面之间传递参数的几种方法
.Net中常用的JS(javascript)操作类
SqlHelper用法简单示例(技巧)
相关专题
WinForm窗体之间交互的一些方法
VS中创建自定义SQLRule
三种方法在Infopath中实现数据有效性验证
如何使用和开发自定义配置节
C#获得当前文件夹内所有文件的名称,大小,类型,属
网学推荐
·
原创论文的写法
·
论文数据图表制作
·
论文排版通过检测检测
·
提供系统开发和运行服务
·
提供原创参考资料
·
档案托管服务
·
原创参考论文导航
·
查重服务维普检测低于30%
·
我们提供原创参考论文和原创的参
·
原创的论文资料参考节省时间!
·
论文格式排版 格式核对!
·
UI设计定制、界面设计
·
程序和网站等UI设计定制!
·
原创参考论文参考定制!
·
职称和论文发表,可联系业务我们
·
本科毕业设计(论文)答辩指南
·
程序制作专家
原创论文
·
财务管理
·
参考选题
·
论文选题-查重参考论文
·
参考论文大全
·
电气工程及其自动化
·
电子论文
·
电子信息工程
·
电子商务
·
工程管理
·
公共关系学
·
公共事业管理
·
公路工程
·
公路交通运输
·
工商管理
·
广告学
·
家政学
文章排行榜
·
自然框架的源代码、Demo、数据库、
·
WebService身份验证
·
不要迷失在技术的海洋中
·
.net完美操作cookies
·
取出文本中的图片地址
·
谷歌眼中的搜索未来
·
GridView显示隐藏某一列
·
谈谈关于MVP模式中V-P交互问题【附
·
ASP.NET网站预编译概述
·
详解.net内存管理
·
json教程之C#开发json解析类
·
用FCKEditor编辑器上传图片、FLASH
·
C#调用WebService时的身份验证
·
WinForm窗体之间交互的一些方法
·
VS中创建自定义SQLRule
·
三种方法在Infopath中实现数据有效
·
如何使用和开发自定义配置节
·
C#获得当前文件夹内所有文件的名称
设为首页
|
加入收藏
|
网学首页
|
原创论文
|
计算机原创
版权所有 网学网 [
Myeducs.cn
] 您电脑的分辨率是
像素
Copyright 2008-2020
myeducs.Cn
www.myeducs.Cn
All Rights Reserved
湘ICP备09003080号
常年法律顾问:王律师