1. 首页
  2. 综合百科
  3. 顺序是什么意思(学习数据结构)

顺序是什么意思(学习数据结构)

简介:关于顺序是什么意思(学习数据结构)的相关疑问,相信很多朋友对此并不是非常清楚,为了帮助大家了解相关知识要点,小编为大家整理出如下讲解内容,希望下面的内容对大家有帮助!
如果有更好的建议或者想看更多关于综合百科技术大全及相关资讯,可以多多关注茶馆百科网。

第四章:树与二叉树(二叉树的遍历和线索二叉树)

上一篇文章讲了第四章的数据结构:树和二叉树(二叉树的顺序存储和链式存储)。下面学习二叉树和线索二叉树的遍历(数据结构相关文章在理木客,微信官方账号同步更新,同名,欢迎关注)。

1.二叉树的遍历

二叉树的遍历:按照一定的搜索路径访问树中的每个节点。树中的每个节点只被访问一次。

根据访问根节点的顺序,我们将其分为

优先遍历:先行根-左子树-右子树

中间顺序遍历:第一个左子树-根-右子树

后序遍历:先左子树-右子树-根

注意,每当根访问时,它总是首先访问左子树,然后访问右子树。

1.1先序遍历

前序遍历:

访问根节点;

递归遍历左侧子树;

递归遍历右边的子树;

注意:每个节点的分支遵循上述访问顺序,反映了“递归调用”

时间复杂度:不适用

上图先序遍历结果:阿卜德费奇

思维过程:

(1)首先访问根节点a,

(2)将A分为左子树和右子树。因为是递归调用,所以左子树也遵循‘先根节点-后左-后右’的顺序,所以访问的是节点B。

(3)然后访问节点d,

(4)访问节点F时,有分支,也遵循‘先根节点-再左-再右’的顺序。

(5)访问节点E,当左边的大的子树已经被访问。

(6)然后按照最后一次访问右边子树的顺序,访问右边的大子树,右边的大子树也会先访问根节点c。

(7)访问左子树g,

(8)因为没有G的左子树,接下来访问G的右子树H,

(9)最后访问C的右边子树I。

优先遍历的递归算法;

voidPreOrder(BiTreeT){if(T!=null){ visit(T);前序(T-l child);前序(T-rchild);}}

1.2中序遍历

按照左子树-根节点-右子树的顺序访问。

中间顺序遍历:

用中间顺序遍历左子树;

访问根节点;

用中间顺序遍历右边的子树。

时间复杂度:不适用

上图中序遍历结果:DBEFAGHCI

中序遍历的递归算法:

voidPreOrder(BiTreeT){if(T!=null){ PreOrder(T-l child);访问(T);前序(T-rchild);}}

1.3后序遍历

按照左子树-右子树-根节点的顺序访问。

后序列遍历:

用postorder递归遍历左子树;

使用后序递归遍历右边的子树;

访问根节点;

时间复杂度:不适用

上图后序遍历的结果:DEFBHGICA

后序遍历的递归算法:

voidPreOrder(BiTreeT){if(T!=null){ PreOrder(T-l child);前序(T-rchild);访问(T);}}

2.二叉树的非递归遍历

以上三种遍历方法都是用递归来遍历的。先说一下如何使用非递归算法进行遍历。我们需要使用堆栈,以中间顺序遍历为例:

算法思想

最初,依次扫描根节点和根节点的所有剩余节点,并依次堆叠。

弹出并访问一个节点。

扫描该节点的右子节点,并将其堆叠。

依次扫描右子节点的所有左节点并堆叠。

重复此过程,直到堆栈为空。

注意区分扫描和访问

按照上面的算法思想解释如上图所示的二叉树,我们用非递归算法遍历:

1:依次扫描根节点和根节点的所有剩余节点,并依次堆叠。

2.堆叠一个节点并访问它。

3.接下来,扫描节点7的右子节点,并将其放入堆栈。它的右子节点是空的,所以没有节点被推入堆栈。

4:然后继续堆叠节点4并访问它。

5.然后扫描节点4的右子节点,放入栈中。它的右子节点是空的,所以没有节点被推入堆栈。

6:然后继续堆叠节点2,并访问它。

7:然后扫描节点2的右子节点,放入栈中。它的右子节点是5,所以把节点5压入堆栈。

8:然后扫描节点5的所有节点。

左侧结点并依次进栈,它的左侧结点为空,故无任何结点压入栈中。

9:然后继续出栈5号结点并访问它,同样他右孩子结点为空,无任何结点进栈。


10:接着出栈1结点并访问它。


11:同样扫描1结点的右孩子结点,依次进栈


12:右孩子结点进栈后,依次将该节点的左侧结点依次进栈,然后继续循环步骤二,知道栈为空

代码实现:

voidInOrder2(BiTreeT){InitStack(S);BiTreep=T;//循环判断while(p||!IsEmpty(S)){//栈非空if(p){Push(S,p);p-p->lchild;//将p指向左孩子}else{Pop(S,p);//左孩子为空,出栈一个结点visit(p);//并访问它p=p->rchild;//指向右孩子}}}

3.层次遍历

层次遍历:顾名思义,从上到下从左到右依次遍历,遍历顺序及时标号顺序。


层次遍历需要借助队列,算法思想:

·初始将根入队并访问根结点

·若有左子树,则将左子树的根入队

·若有右子树,则将右子树的根入队

·然后出队节点并访问

·反复该过程直到队列为空

代码实现

voidleveOrder(BiTreeT){InitQueue(Q);BiTreep;//辅助变量EnQueue(Q,T);//根节点入队while(!isEmpty(Q)){DeQueue(Q,P);//出队队首元素visit(p);//并访问if(p->lchild!=NULL){//左孩子节点不为空,入队EnQueue(Q,p->lchild);}if(p->rchild!=NULL){//右孩子节点不为空,入队EnQueue(Q,p->rchild);}}}

4.遍历结果逆置

我们由一个二叉树可以得到遍历序列,那么我们是否可以通过遍历序列得到一个二叉树吗?

首先我们只通过一个遍历序列可以得到二叉树吗?例如先序遍历序列:124536,我们直到先遍历的肯定是根节点,但是2是左节点还是右节点缺无法确定,所以根据一个遍历序列无法全程逆置。


其实,(后)先序遍历序列和中序遍历序列可以确定一颗二叉树,而后遍历序列和先序遍历序列不可以确定一颗二叉树。

在学习遍历结果逆置的时候请务必清楚三种遍历方式.

先序遍历序列和中序遍历序列逆置思想:

·在先序序列中,第一个节点是根结点;

·根结点将中序遍历序列划分为两部分;

·然后在先序序列中确定两部分的结点,并且两部分的第一个结点分别为左子树的根和右子树的根;

·在子树中递归重复该过程,便能唯一确定一棵二叉树。

例如:先序序列:124536中序序列为:425163,请画出该二叉树。


先序遍历我们直到第一个结点时根节点,后序遍历序列我们知道最后一个结点为根结点,所以后序遍历序列加中序遍历序列的操作大同小异。

另外根据层次遍历序列和中序遍历序列也可以确定一个唯一二叉树。

5.线索二叉树

上面讲到二叉链表,我们知道不管二叉树的形态如何,空链域的个数总是多过非空链域的个数。准确的说,n各结点的二叉链表共有2n个链域,非空链域为n-1个,但其中的空链域却有n+1个。

因此,提出了一种方法,利用原来的空链域存放指针,指向树中其他结点,这种指针称为线索。同时提升了查找速度。

我们称这个线索二叉树的建立过程为:线索化

若无左子树,则将左指针指向其前驱结点。若无右子树,则将右指针指向其后继结点。

5.1先序线索化

结点1有左孩子2->结点2有左孩子->结点4没有左孩子故左指针指向前驱结点2->结点4没有右孩子故右指针指向后继结点5->结点5没有左孩子故左指针指向前驱结点->结点5没有右孩子故右指针指向后继结点3->结点3有左孩子6->结点6没有左孩子故左指针指向前驱节点3->结点6没有右孩子且没有后继结点->接着看结点3,它没有右孩子则将右指针指向后继结点6。


5.2中序线索化


5.3后序线索化


最常用的还是中序线索二叉树

显然,在决定lchild是指向左孩子还是前驱,rchild是指向右孩子还是后继,需要一个区分标志的。因此,我们在每个结点再增设两个标志域ltag和rtag

线索二叉树的结点结构

typedefstructThreadNode{ElemTypedata;structThreadNode*lchild,*rchild;intltag,rtag;}ThreadNode,*ThreadTree;

这种结点结构构成的二叉链表作为二叉树的存储结构,称为线索链表。对于指向前驱和后继的指针称为线索,线索化的二叉树就称为:线索二叉树

5.4中序线索二叉树


中序线索二叉树线索化代码

//传入一个根节点和前驱结点voidInThread(ThreadTree&p,ThreadTree&pre){if(p!=NULL){InThread(p->lchild,pre);//递归左子树线索化if(p->lchild==NULL){//没有左孩子p->lchild=pre;//左孩子指针指向前驱p->ltag=1;//前驱线索}if(pre!=NULL&&pre->rchild==NULL){//没有右孩子pre->rchild=p;//前驱右孩子指针指向后继(当前结点p)pre->rtag=1;//后继线索}pre=p;//修改前驱结点为当前结点InThread(p->rchild,pre);//递归右子树线索化}}

初始化和收尾

//传入线索二叉树的根节点voidCreateInThread(ThreadTreeT){ThreadTreepre=NULL;if(T!=NULL){InThread(T,pre);//实现线索化pre->rchild=NULL;//收尾最后遍历的结点的右孩子至为空pre->rtag=1;}}


引入头节点的线索二叉树


中序线索二叉树的遍历

//找最左侧的孩子结点ThreadNode*Firstnode(ThreadNode*p){while(p->ltag==0){p=p->lchild;}returnp;}//找后继结点ThreadNode*Nextnode(ThreadNode*p){if(p->rtag==0){returnFirstnode(p->rchild);}returnp->rchild;}voidInOrder(ThreadNode*T){for(ThreadNode*p=Firstnode(T);p!=NULL;p=Nextnode(p)){visit(p);}}

持续更新中~

往期文章:

学习数据结构--第一章:绪论

学习数据结构--第二章:线性表(顺序存储、插入、删除)

数据结构第二章:线性表(链式存储、单链表、双链表、循环链表)

学习数据结构--第二章:线性表(顺序表VS链表)

学习数据结构--第三章:栈和队列(栈的基本操作)

数据结构-第三章:栈和队列(队列的基本操作、循环、双端队列)

数据结构-第三章:栈和队列(栈的应用、括号匹配、表达式转换)

学习数据结构--第三章:栈和队列(特殊矩阵的压缩存储)

数据结构第四章:树与二叉树(树的基本概念、基本术语、性质)

数据结构第四章:树与二叉树(二叉树的概念、性质、特殊二叉树)

数据结构第四章:树与二叉树(二叉树的顺序存储和链式存储)

本文主要介绍了关于顺序是什么意思(学习数据结构)的相关养殖或种植技术,综合百科栏目还介绍了该行业生产经营方式及经营管理,关注综合百科发展动向,注重系统性、科学性、实用性和先进性,内容全面新颖、重点突出、通俗易懂,全面给您讲解综合百科技术怎么管理的要点,是您综合百科致富的点金石。
以上文章来自互联网,不代表本人立场,如需删除,请注明该网址:http://23.234.50.4:8411/article/99430.html