热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

中根遍历二叉查找树所得序列一定是有序序列_带你搞定考研二叉树算法(下)...

递归数据结构的定义▼▼▼采用递归方式定义的数据结构称为递归数据结构。在递归数据结构定义中包含的递归运算称为基本递归运算。对于二叉树,采用递归数据结构的定义如下

   递归数据结构的定义   

3b30ed03917d8ff12e2df9a72de525b8.gif

采用递归方式定义的数据结构称为递归数据结构。在递归数据结构定义中包含的递归运算称为基本递归运算。

对于二叉树,采用递归数据结构的定义如下:

RD = (D,Op)

其中,D是所有二叉树(含空二叉树)的集合Op= {op1,op2}:

op1(b)=b ->lchild     b为含一个或一个以上节点的二叉树op2(b)=b->rchild       b为含一个或一个以上节点的二叉树

显然,这两个基本的递归数据结构的运算符都是一元运算符,且具有封闭性。

   二叉树的遍历算法设计   

3b30ed03917d8ff12e2df9a72de525b8.gif

二叉树的遍历是指按照一定次序访问树中所有结点,并且每个结点均被访问一次,且仅被访问一次。

由二叉树的递归定义可得:遍历一棵二叉树便要决定对根结点N、左子树L和右子树R的访问顺序。按照先遍历左子树再遍历右子树的原则,常见的遍历次序有先序(NLR)、中序(LNR)、后序(LRN)。

常见的4中递归遍历方法如下:

①先序遍历

②中序遍历

③后序遍历

④层序遍历

1先序遍历先序遍历二叉树的过程如下:访问根结点;先序遍历左子树;先序遍历右子树。先序遍历的递归算法如下:

void PreOrder(BiTree T){ if(T != NULL) { visit(T); //访问根结点 PreOrder(T->lchild); //先序递归访问左子树 PreOrder(T->rchild); //先序递归访问右子树 }}//提示:先序遍历序列中第一个结点是根结点先序遍历的非递归算法如下:

void PreOrder(BiTree T){ InitStack(S); p = T; while(p || !StackEmpty(S)) { if(p) { visit(p->data); push(S,p); p = p->lchild; } else { pop(S,p); p = p->rchild; } } }

提示:先序遍历序列中第一个结点是根结点


2中序遍历

中序遍历二叉树的过程如下:

中序遍历左子树;

访问根结点;

中序遍历右子树。

中序遍历的递归算法如下:

void InOrder(BiTree T){ if(T != NULL) { InOrder(T->lchild); //中序递归访问左子树     visit(T);   //访问根结点  InOrder(T->rchild); //中序递访问右子树 }}中序遍历的非递归算法如下:

void InOrder(BiTree T){ InitStack(S); p = T; while(p || !StackEmpty(S)) { if(p) { push(S,p); p = p->lchild; } else { pop(S,p); visit(p->data); p = p->rchild; } } }

提示:中序遍历序列中,若已知根结点,则其前为左子树的中序遍历序列,其后为右子树的中序遍历序列。


3后序遍历后序遍历二叉树的过程如下:后序遍历左子树;后序遍历右子树;访问根结点。后序遍历的递归算法如下:

void PostOrder(BiTree T){ if(T != NULL) { PostOrder(T->lchild); //中序递归访问左子树    PostOrder(T->rchild);  //中序递访问右子树     visit(T);   //访问根结点  }}

后序遍历的非递归算法如下:

void PostOrder(BiTree T){ InitStack(S); p = T; while(p || !StackEmpty(S)) { if(p) { push(S,p); p = p->lchild; } else { pop(S,p); if(p->rchild && (p->rchild).tag == 0) { push(S,p); p = p->rchild; } else { visit(p->data); p.tag = 1; p = NULL; } } } }

说明:在二叉树的存储结构中每个结点增加一个是否访问的tag域(标记),其初始值为0


4层次遍历

层次遍历的思路和先序遍历、中序遍历、后序遍历的方式都不一样,它是按照层级的方式来进行遍历的。

671b367325874d6d9d8f23d7a90b25b7.png先遍历第一层的所有结点,再遍历第二层的所有结点,依次类推进行遍历。要进行层次遍历,需要借助一个队列。层次遍历的算法过程可以概括为:➤先将二叉树根结点入队,➤然后出队,访问该出队结点,➤若它有左子树,则将左子树根结点入队,➤若它有右子树,则将右子树根结点入队,➤然后出队,访问出队结点......➤如此反复,直到队列为空。

void LevelOrder(BiTree T){ InitQueue(Q); //初始化辅助队列 BiTree p; //p是遍历指针 EnQueue(Q,T); //将根结点入队 while(!isEmpty(Q)) //队列不为空时,循环 { DeQueue(Q,p); //对头元素出队 visit(p); //访问当前p所指向结点 if(p->lchild != NULL) EnQueue(Q,p->lchild); //若左子树不为空,则左子树入队 if(p->rchild != NULL) EnQueue(Q,p->rchild); //若右子树不为空,则右子树入队 } }

提示:层序遍历序列的第一个结点是根结点


 例题1   采用先序遍历递归算法查找值为x的节点。找到后返回其指针,否则返回NULL。

查找节点FindNode(*b,x)

解:其递归模型如下:

c23cc3232d4499a3ce805971e6478693.png

BTNode *FindNode(BTNode *b,ElemType x){ BTNode *p; if(b == NULL) return NULL; else if(b->data == x) return b; else { p = FindNode(b->lchild,x); if(p!=NULL) return p; else return FindNode(b->rchild,x); }}


 例题2   假设二叉树采用二叉链存储结构,设计一个算法输出值为x的结点的所有祖先。

➤解:根据二叉树的中祖先的定义可知:若结点p的左孩子或右孩子是结点q,则结点p是结点q的祖先;若结点p的左孩子或右孩子是q结点的祖先,则结点p也是结点q的祖先。➤设f(b,x)表示结点b是否为值是x的结点的祖先。若结点b是值为x的结点的祖先,f(b,x)返回true;否则返回false。当f(b,x)为true时,输出结点b的值。求值为x的结点的所有祖先的递归模型如下:

c80b26c5de86fd14d4d58e0576c80958.png

bool ancestor(BTNode *b, ElemType x){ if(b == NULL) return false; else if(b->lchild !=NULL && b->lchild->data == x || b->rchild !=NULL && B->rchild->data == x) { printf("%c",b->data); return true; } else if(ancestor(b->lchild,x) || ancestor(b->rchild,x)) { printf("%c",b->data); return true; } else return false; }


例题3   假设二叉树采用二叉链存储结构存储,设计一个算法,求先序遍历序列中第k(1≦k≦二叉树中结点个数)个结点的值。➤解:用一个全局变量n(初值为1)保存先序遍历时访问节点的序号。当二叉树b为空时返回特殊字符‘ ’ (‘ '为空格字符),当k==n时表示找到了满足条件的节点,返回b->data;当k≠n时,在左子树中查找,若找到了返回该值,否则在右子树中查找,并返回其结果。➤对应的递归模型如下:

4d6eda8ba69aa37b117991e7999145cf.png

//递归算法代码如下:int n = 1; //全局变量 ElemType PreNode(BTNode *b, int k) //先序遍历第k个结点值的递归算法 { ElemType ch; if(b == NULL) return ' '; if(n == k) return b->data; ch = PreNode(b->lchild,k); //遍历左子树 if(ch != ' ') return ch; //在左子树中找到返回 ch = PreNode(b->rchild,k); //遍历右子树 return ch; //遍历右子树的结构 } //非递归算法如下:ElemType PreNode(BTNode *b, int k) //先序遍历第k个结点值的非递归算法 { BTNode *St[MaxSize], *p; int top = -1; n = 0; if(b != NULL) { top++; //根结点进栈 St[top] = b; while(top > -1) //栈不为空时循环 { p = St[top]; //退栈并访问该结点 top--; n++; if(n == k) return p->data; if(p->lchild != NULL) //左孩子结点进栈 { top++; St[top] = p->lchild; } if(p->rchild != NULL) //右孩子结点进栈 { top++; St[top] = p->rchild; } } } return ' ';}5e17dc0b03fadff63aefea685ace6392.gif

真题回顾

题1假设二叉树采用二叉链存储结构存储,设计一个算法,求中序遍历序列中第k(1≦k≦二叉树中结点个数)个结点的值。①请写出中序遍历的递归算法:②请写出中序遍历的非递归算法:提示:本题对应的解题方法和例题3类似,只是把先序遍历换成中序遍历,套用中序递归遍历的模型。 习题2 设二叉树T采用二叉链表存储方式,根结点用T指针指示,设计一个算法,求指针p所指结点的双亲结点。提示:先把例题2学会,本题的解题思路和方法可以按照例题2的思路习题3假设二叉树采用二叉链存储结构,设计一个算法把树b的左右子树进行交换。要求算法的空间复杂度为O(1).趣闻:据说这是一道谷歌的算法面试题目

5e17dc0b03fadff63aefea685ace6392.gif

da4133214189dfd8a2400ad8d4902350.gif

 往期推荐 

?链表递归题型大解密,这类题还学不会算我输!

?带你搞定考研二叉树算法(上)

de481b7dcb7df3a5db2d1d86fac3582e.png



推荐阅读
  • 题目编号:2049 [SDOI2008]Cave Exploration。题目描述了一种动态图操作场景,涉及三种基本操作:断开两个节点间的连接(destroy(a,b))、建立两个节点间的连接(connect(a,b))以及查询两节点是否连通(query(a,b))。所有操作均确保图中无环存在。 ... [详细]
  • 洛谷 P4009 汽车加油行驶问题 解析
    探讨了经典算法题目——汽车加油行驶问题,通过网络流和费用流的视角,深入解析了该问题的解决方案。本文将详细阐述如何利用最短路径算法解决这一问题,并提供详细的代码实现。 ... [详细]
  • 题目描述:计算从起点到终点的最小能量消耗。如果下一个单元格的风向与当前单元格相同,则消耗为0,否则为1。共有8个可能的方向。 ... [详细]
  • 本问题涉及在给定的无向图中寻找一个至少包含三个节点的环,该环上的节点不重复,并且环上所有边的长度之和最小。目标是找到并输出这个最小环的具体方案。 ... [详细]
  • Bootstrap Paginator 分页插件详解与应用
    本文深入探讨了Bootstrap Paginator这款流行的JavaScript分页插件,提供了详细的使用指南和示例代码,旨在帮助开发者更好地理解和利用该工具进行高效的数据展示。 ... [详细]
  • 本文详细介绍了在 Python 中如何有效去除浮点数末尾的无意义零及不必要的点,提供多种实现方法,并深入探讨了浮点数在计算机中的表示方式及其可能带来的精度问题。 ... [详细]
  • 如何高效解决Android应用ANR问题?
    本文介绍了ANR(应用程序无响应)的基本概念、常见原因及其解决方案,并提供了实用的工具和技巧帮助开发者快速定位和解决ANR问题,提高应用的用户体验。 ... [详细]
  • 使用C#构建动态图形界面时钟
    本篇文章将详细介绍如何利用C#语言开发一个具有动态显示功能的图形界面时钟。文章中不仅提供了详细的代码示例,还对可能出现的问题进行了深入分析,并给出了解决方案。 ... [详细]
  • mysql数据库json类型数据,sql server json数据类型
    mysql数据库json类型数据,sql server json数据类型 ... [详细]
  • 管理UINavigationController中的手势返回 - Managing Swipe Back Gestures in UINavigationController
    本文介绍了如何在一个简单的闪存卡片应用中实现平滑的手势返回功能,以增强用户体验。 ... [详细]
  • Spring Boot使用AJAX从数据库读取数据异步刷新前端表格
      近期项目需要是实现一个通过筛选选取所需数据刷新表格的功能,因为表格只占页面的一小部分,不希望整个也页面都随之刷新,所以首先想到了使用AJAX来实现。  以下介绍解决方法(请忽视 ... [详细]
  • 在现代Web开发中,HTML5 Canvas常用于图像处理和绘图任务。本文将详细介绍如何将Canvas中的图像导出并上传至服务器,适用于拼图、图片编辑等场景。 ... [详细]
  • 【数据结构】堆的实现(简单易懂,超级详细!!!)
    目录1、堆的概念及结构概念规律2、堆的实现2.1结构设计2.2接口实现2.3初始化2.4堆的向下调整算法主要思想涉及问题代码实现2.5建堆思想代码实现 ... [详细]
  • 在Java开发中,保护代码安全是一个重要的课题。由于Java字节码容易被反编译,因此使用代码混淆工具如ProGuard变得尤为重要。本文将详细介绍如何使用ProGuard进行代码混淆,以及其基本原理和常见问题。 ... [详细]
  • 在Qt框架中,信号与槽机制是一种独特的组件间通信方式。本文探讨了这一机制相较于传统的C风格回调函数所具有的优势,并分析了其潜在的不足之处。 ... [详细]
author-avatar
ruishao520
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有