二叉树的遍历.

Slides:



Advertisements
Similar presentations
第7章 樹與二元樹 (Trees and Binary Trees)
Advertisements

Chapter 06 Tree and binary tree 第六章 树和二叉树
動畫與遊戲設計 Data structure and artificial intelligent
第二次直播 清华大学 殷人昆 中央电大 徐孝凯.
第6章 二叉树和树 前面的章节主要讨论的是线性结构,二叉树和树属于非线性的结构。遍历非线性结构比线性结构要麻烦。
第一章 C语言概述 计算机公共教学部.
计算机软件技术基础 数据结构与算法(4).
数据结构——树和二叉树 1/96.
引入树 线性表、堆栈和队列都是线性结构,它们的共同特点:一对一; 计算机对弈中的一个格局可能有多个后继格局,用线性结构难以描述。
第5章 树( Tree )和二叉树 5.1 树的基本概念 5.2 二叉树 5.3 遍历二叉树和线索二叉树 5.4 树和森林
数据结构 第六章 树与二叉树 深圳大学计算机系 蔡茂国.
第五章 树 东南大学计算机学院 方效林 本课件借鉴了清华大学殷人昆老师 和哈尔滨工业大学张岩老师的课件.
第三章 控制结构.
Chap4 Tree.
Tree(樹) 什麼是「樹」? 「樹」的範例 「樹」的定義 「樹」的表示法.
Linked List Operations
Chapter 5 Tree & Binary Tree
struct 可以在同一個名稱下擁有多種資料型態。使用struct能讓資料的存取和處理更為靈活。
樹狀結構 陳怡芬 2018/11/16 北一女中資訊專題研究.
第11章 查找 主要知识点 查找的基本概念 静态查找表 动态查找表 哈希表.
佇列 (Queue).
Chapter8 Binary and Other Trees
4.1 概述 4.2 类与对象的实现 4.3 对象的初始化和析构 4.4 类的包含 4.5 类模板
Derived Class 前言 衍生類別的定義 單一繼承 public, protected, 和 privated 基底類別
第七章 搜索结构 静态搜索结构 二叉搜索树 AVL树.
·线性表的定义及ADT ·线性表的顺序存储结构 ·线性表的链接存储结构 · 单向循环链表 · 双链表、双向循环链表 · 一元多项式的加法
哈夫曼编码.
Chapter 5 樹(Trees).
第12章 樹狀搜尋結構 (Search Trees)
第六章 继承性和派生类 胡昊 南京大学计算机系软件所.
授课老师:龚涛 信息科学与技术学院 2018年3月 教材: 《Visual C++程序员成长攻略》 《C++ Builder程序员成长攻略》
程序设计期末复习 黎金宁
第三章 C++中的C 面向对象程序设计(C++).
2 C++ 的基本語法和使用環境 親自撰寫和執行程式是學好程式語言的不二法門。本章藉由兩個簡單的程式,介紹C++ 程式的基本結構和開發環境,讓初學者能逐漸建立使用C++ 的信心。
第5章 堆疊(Stacks) 5-1 堆疊的基礎 5-2 堆疊的表示法 5-3 堆疊的應用 - 運算式的計算與轉換
第六章 树和二叉树.
数据结构与算法
五、链 表 1、单链表 2、双向链表 3、链表应用.
樹狀結構 Tree Structure chapter 7 德明科技大學資訊科技系.
親愛的老師您好 感謝您選用本書作為授課教材,博碩文化準備本書精選簡報檔,特別摘錄重點提供給您授課專用。 說明: 博碩文化:
6.3 遍历二叉树和线索二叉树(知识点二) 遍历二叉树 一、问题的提出
二叉树和其他树 (Binary and other trees)
第六章 樹狀結構 T r e e 版權屬作者所有,非經作者 同意不得用於教學以外用途.
樹 2 Michael Tsai 2013/3/26.
第三章 链表 单链表 (Singly Linked List) 循环链表 (Circular List) 多项式及其相加
感謝同學們在加分題建議. 我會好好研讀+反省~
Tree & Binary Tree.
書名 Java於資料結構與演算法之實習應用
自我參考結構 (self-reference – 1)
第三章 链表 单链表 循环链表 多项式及其相加 双向链表 稀疏矩阵.
常宝宝 北京大学计算机科学与技术系 数据结构(三) 常宝宝 北京大学计算机科学与技术系
第五章 递归与广义表 递归的概念 递归过程与递归工作栈 递归与回溯 广义表.
第六章 树和二叉树 £6.1 树 £6.2 二叉树 £6. 3 二叉树的存储结构 £6.4 二叉树的遍历与线索化 £6.1.1 树的定义
第7章 樹與二元樹(Trees and Binary Trees)
第二章 Java基本语法 讲师:复凡.
第四章 栈和队列 栈 ( Stack ) 队列 ( Queue ) 优先队列 (Priority Queue) 小结.
C++语言程序设计 C++语言程序设计 第九章 类的特殊成员 第十一组 C++语言程序设计.
資料結構使用Java 第9章 樹(Tree).
字符串 (String) 字符串是 n (  0 ) 个字符的有限序列, 记作 S = “c1c2c3…cn” 其中,S 是串名字
<编程达人入门课程> 本节内容 为什么要使用变量? 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ:
第二章 Java语法基础.
目标 流程控制 字符串处理 C# 的类和对象 C# 访问修饰符 C# 构造函数和析构函数.
#include <iostream.h>
第二章 Java基本语法 讲师:复凡.
第1章 数据结构基础概论 本章主要介绍以下内容 数据结构研究的主要内容 数据结构中涉及的基本概念 算法的概念、描述方法以及评价标准.
第2章 Java语言基础.
C++语言程序设计 C++语言程序设计 第十一章 异常处理 C++语言程序设计.
第10章 二元搜尋樹 (Binary Search Tree)
第三章 流程控制 程序的运行流程 选择结构语句 循环结构语句 主讲:李祥 时间:2015年10月.
資料結構與C++程式設計進階 C++與資料結構 講師:林業峻 CSIE, NTU 7/ 5, 2010.
Presentation transcript:

二叉树的遍历

二叉树遍历 (Binary Tree Traversal) 所谓树的遍历,就是按某种次序访问树中的结点,要求每个结点访问一次且仅访问一次。 设访问根结点记作 V 遍历根的左子树记作 L 遍历根的右子树记作 R 则可能的遍历次序有 前序 VLR 镜像 VRL 中序 LVR 镜像 RVL 后序 LRV 镜像 RLV

中序遍历 (Inorder Traversal) 中序遍历二叉树算法的框架是: 若二叉树为空,则空操作; 否则 中序遍历左子树 (L); 访问根结点 (V); 中序遍历右子树 (R)。 遍历结果 a + b * c - d - e / f 表达式语法树

二叉树递归的中序遍历算法 template <class Type> void BinaryTree <Type>::InOrder ( ) { InOrder ( root ); } template <class Type> void BinaryTree <Type>:: InOrder ( BinTreeNode <Type> *current ) { if ( current != NULL ) { InOrder ( current→leftChild ); cout << current→data; InOrder ( current→rightChild );

中序遍历二叉树的递归过程图解

前序遍历 (Preorder Traversal) 前序遍历二叉树算法的框架是 若二叉树为空,则空操作; 否则 访问根结点 (V); 前序遍历左子树 (L); 前序遍历右子树 (R)。 遍历结果 - + a * b - c d / e f

二叉树递归的前序遍历算法 template <class Type> void BinaryTree <Type>::PreOrder ( ) { PreOrder ( root ); } template <class Type> void BinaryTree<Type>:: PreOrder ( BinTreeNode <Type> *current ) { if ( current != NULL ) { cout << current→data; PreOrder ( current→leftChild ); PreOrder ( current→rightChild );

后序遍历 (Postorder Traversal) 后序遍历二叉树算法的框架是 若二叉树为空,则空操作; 否则 后序遍历左子树 (L); 后序遍历右子树 (R); 访问根结点 (V)。 遍历结果 a b c d - * + e f / -

二叉树递归的后序遍历算法 template <class Type> void BinaryTree <Type>::PostOrder ( ) { PostOrder ( root ); } template <class Type> void BinaryTree<Type>:: PostOrder ( BinTreeNode <Type> *current ) { if ( current != NULL ) { PostOrder ( current→leftChild ); PostOrder ( current→rightChild ); cout << current→data;

应用二叉树遍历的事例 利用二叉树后序遍历计算二叉树结点个数及二叉树的高度 template <class Type> int BinaryTree<Type> :: Size ( const BinTreeNode <Type> *t ) const { if ( t == NULL ) return 0; else return 1 + Size ( t→leftChild ) + Size ( t→rightChild ); }

template <class Type> int BinaryTree<Type> :: Depth ( const BinTreeNode <Type> *t ) const { if ( t == NULL ) return -1; else return 1 + Max ( Depth ( t→leftChild ), Depth ( t→rightChild ) ); }

二叉树结点定义 传统方法:利用栈的非递归遍历算法 typedef struct BitreeNode { TreeDataType data; struct BitreeNode * leftChild, * rightChild; } BitreeNode, * Bitree;

传统方法:利用栈的前序遍历非递归算法 void PreOrderTraverse ( Bitree T ) { StackType S; BitreeNode * p; S.makeEmpty( ); S.Push(null); p = T; //初始化 while ( p ) { printf ( p→data ); if ( p→rightChild ) S.Push ( p→rightChild ); //预留右子树指针在栈中 if ( p→leftChild ) p = p→leftChild;//进左子树 else { p = S.getTop( ); S.Pop( ); } //进右子树 }

传统方法:利用栈的中序遍历非递归算法 void InOrderTraverse ( Bitree T ) { StackType S; BitreeNode * p; S.makeEmpty( ); p = T; //初始化 do{ while ( p ) { S.Push(p); p = p→leftChild; } if ( !S.IsEmpty( ) ) { //栈非空 p = S.getTop( ); S.Pop( ); //退栈 printf ( p→data); //访问根结点 p = p→rightChild; //向右链走 } } while ( p || !S.IsEmpty( ) );

传统方法:利用栈的后序遍历非递归算法 后序遍历时使用的栈的结点定义 typedef struct StackNode { enum tag{ L, R }; BitreeNode * ptr; } StackNode; void PostOrderTraverse ( Bitree T ) { //后序遍历根为 T 的二叉树, 存储结构为二叉链//表, S 是存储所经过二叉树结点的工作栈。其//中, tag 是结点标记。当 tag=L 时, 表示刚才 //是在左子树中, 从左子树退出时, 还要去遍历 ptr tag (LR)

//右子树。当 tag =R 时, 表示刚才是在右子树//中, 在从右子树中退出时, 去访问位于栈顶的 //结点。 StackType S; BitreeNode * p; StackNode w; S.makeEmpty( ); p = T; //初始化 do { while ( p ) { w.ptr = p; w.tag = L; S.Push(w); p = p→leftChild; } //遍历左子树并把经过结点加左标记进栈 int continue = 1; //继续循环标记

while ( continue && !S.IsEmpty( ) ) { w = S.getTop( ); S.Pop( ); p = w.ptr; switch (w.tag) { //判断栈顶的tag标记 case L : w.tag = R; S.Push(w); continue = 0; //修改栈顶tag p = p→rightChild; break; case R : printf (p→data); break; } } while ( p || !S.IsEmpty( ) );

二叉树遍历的游标类 (Tree Iterator) 二叉树的游标抽象基类 template <class Type> class TreeIterator { public: TreeIterator ( const BinaryTree <Type> & BT ) : T (BT), current (NULL) { } virtual ~TreeIterator ( ) { } virtual void First ( ) = 0; virtual void operator ++ ( ) = 0; int operator +( ) const {return current != NULL; } const Type & operator ( ) ( ) const;

protected: const BinaryTree <Type> & T; const BinTreeNode <Type> * current; private: TreeIterator ( const TreeIterator & ) { } TreeIterator & operator = ( const TreeIterator & ) const ; };

template <class Type> const Type &TreeIterator<Type> :: operator ( ) const { if ( current == NULL ) { cout << "非法访问" << endl; exit (1); } return current→GetData ( ); }

后序游标类 为记忆走过的结点,设置一个工作栈: S.PopTim = 0, 1或2,表示第几次退栈,用以 判断下一步向哪一个方向走。 后序遍历时,每遇到一个结点,先把它推入 栈中,让 S.PopTim = 0。 在遍历其左子树前,改结点的 S.PopTim = 1, 将其左子女推入栈中。 在遍历完左子树后,还不能访问该结点,要 结点地址 *Node 退栈次数 S.PopTim

继续遍历右子树,此时改结点的S.PopTim = 2,并把其右子女推入栈中。在遍历完右子树后,结点才退栈访问。

后序遍历游标类的定义 template <class Type> struct stkNode { //后序遍历使用的递归工作栈 结点定义 const BinTreeNode <Type> *Node; //结点指针 int PopTim; //退栈次数 stkNode ( const BinTreeNode <Type> *N = NULL ) : Node (N), PopTim (0) { } } template <class Type> class PostOrder : public TreeIterator <Type> { public: PostOrder ( const BinaryTree <Type> & BT );

后序游标类成员函数的实现 ~PostOrder ( ) { } void First ( ); //定位到后序次序下第一个结点 void operator ++ ( ); //定位到后序次序下的下一个结点 protected: Stack < StkNode<Type> > st; //工作栈 } 后序游标类成员函数的实现

template <class Type>PostOrder <Type> :: PostOrder ( const BinaryTree <Type> &BT ) : TreeIterator <Type> (BT) { st.Push ( StkNode<Type>( T.GetRoot( ) ) ); } template <class Type> void PostOrder <Type> :: First ( ) { st.MakeEmpty ( ); if ( T.GetRoot ( ) != NULL ) st.Push ( StkNode <Type>( T.GetRoot ( ) ) ); operator ++ ( );

template <class Type> void PostOrder <Type> :: operator ++ ( ) { if ( st.IsEmpty ( ) ) { if ( current == NULL ) { cout << "已经遍历结束" << endl; exit (1); } current = NULL; return; //遍历完成 StkNode <Type> Cnode; for ( ; ; ) { //循环,找后序下的下一个结点 Cnode = st.Pop ( ); if ( ++Cnode.PopTim == 3 ) //从右子树退出 { current = Cnode.Node; return; }

st.Push ( Cnode ); //否则加一进栈 if ( Cnode.PopTim == 1 ) { //左子女进栈 if ( Cnode.Node→GetLeft ( ) != NULL ) st.Push ( StkNode <Type> ( Cnode.Node→GetLeft ( ) ) ); } else { // =2,右子女进栈 if ( Cnode.Node→GetRight ( ) != NULL ) st.Push ( StkNode <Type> ( Cnode.Node→GetRight ( ) ) );

中序游标类 中序遍历与后序遍历走过的路线一样,只是在从左子树退出后立即访问根结点,再遍历右子树。中序遍历也要使用一个递归工作栈 st。 中序游标类的定义 template <class Type> class InOrder : public PostOrder <Type> { public: InOrder ( BinaryTree <Type> & BT ) : PostOrder <Type> ( BT ) { }

中序游标类operator ++( )操作的实现 void First ( ); void operator ++ ( ); }; 中序游标类operator ++( )操作的实现 template <class Type> void InOrder <Type>:: operator ++ ( ) { if ( st.IsEmpty ( ) ) { if ( current == NULL ) { cout << "已经遍历完成" << endl; exit (1); } current = NULL; return; } StkNode <Type> Cnode;

for ( ; ; ) { //循环,找中序下的下一个结点 Cnode = st.Pop ( ); //退栈 if ( ++Cnode.PopTim == 2 ) { //从左子树退出,成为当前结点 current = Cnode.Node; if ( Cnode.Node→GetRight ( ) != NULL ) st.Push ( StkNode <Type> ( Cnode.Node→GetRight ( ) ) ); return; } st.Push ( Cnode ); //否则加一进栈

层次序游标类 if ( Cnode.Node→GetLeft ( ) != NULL ) st.Push ( StkNode <Type> ( //左子女进栈 Cnode.Node→GetLeft ( ) ) ); } 层次序游标类 从根开始逐层访 问,用 FIFO 队列 实现。 遍历顺序

层次序游标类的定义 template <class Type> class LevelOrder : public TreeIterator <Type> { public: LevelOrder ( const BinaryTree <Type> & BT ); ~LevelOrder ( ) { } void First ( ); void operator ++ ( ); protected: Queue < const BinTreeNode <Type> * > qu; };

层次序游标类的operator ++ ( )操作 template <class Type> LevelOrder <Type>:: LevelOrder ( const BinaryTree <Type> & BT ) : TreeIterator <Type> ( BT ) { qu.EnQueue ( T.GetRoot ( ) ); } template <class Type> viod LevelOrder<Type> :: First ( ) { //初始化:只有根结点在队列中 qu.MakeEmpty ( ); if ( T.GetRoot ( ) ) qu.EnQueue ( T.GetRoot ( ) ); operator ++ ( ); }

template <class Type> void LevelOrder<Type> :: operator ++ ( ) { if ( qu.IsEmpty ( ) ) { if ( current == NULL ) { cout << "已经遍历完成" << endl; exit (1);} current = NULL; return; } current = qu.DeQueue ( ); //退队 if ( current→GetLeft ( ) != NULL ) //左子女 qu.EnQueue ( current→GetLeft ( ) ); //进队列 if ( current→GetRight ( ) != NULL ) //右子女 qu.EnQueue ( current→GetRight ( ) ); //进队列