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

Slides:



Advertisements
Similar presentations
总结-图 基础知识 基本方法 2017年3月6日 西南石油大学..
Advertisements

Chapter 06 Tree and binary tree 第六章 树和二叉树
動畫與遊戲設計 Data structure and artificial intelligent
第6章 二叉树和树 前面的章节主要讨论的是线性结构,二叉树和树属于非线性的结构。遍历非线性结构比线性结构要麻烦。
第三章 鏈結串列 Linked List.
计算机软件技术基础 数据结构与算法(4).
引入树 线性表、堆栈和队列都是线性结构,它们的共同特点:一对一; 计算机对弈中的一个格局可能有多个后继格局,用线性结构难以描述。
第六章 树和二叉树.
第5章 树( Tree )和二叉树 5.1 树的基本概念 5.2 二叉树 5.3 遍历二叉树和线索二叉树 5.4 树和森林
CH6 树和二叉树 6.1 树的定义和基本术语 6.2 二叉树 6.3 遍历二叉树和线索二叉树 6.4 树和森林
第八章 查找.
数据结构 第六章 树与二叉树 深圳大学计算机系 蔡茂国.
第五章 树 东南大学计算机学院 方效林 本课件借鉴了清华大学殷人昆老师 和哈尔滨工业大学张岩老师的课件.
数据结构 第6章 树和二叉树 什么是树和二叉树?? 二叉树的遍历 数据结构.
資料結構與C++程式設計進階 資料結構概論 講師:林業峻 CSIE, NTU 6/ 7, 2010.
§4 Additional Binary Tree Operations
Chap4 Tree.
Tree(樹) 什麼是「樹」? 「樹」的範例 「樹」的定義 「樹」的表示法.
第4章 鏈結串列(Linked Lists) 4-1 動態記憶體配置-(6) 4-2 鏈結串列的基礎-(7)
Linked List Operations
Chapter 5 Tree & Binary Tree
單向鏈結串列 Singly Linked Lists.
第6章 佇列(Queues) 6-1 佇列的基礎 6-2 佇列的表示法 6-3 環狀佇列 6-4 雙佇列.
程式設計 博碩文化出版發行.
Chap5 Graph.
樹狀結構 陳怡芬 2018/11/16 北一女中資訊專題研究.
Chapter8 Binary and Other Trees
講師:郭育倫 第3章 基本資料結構 講師:郭育倫
第8章 圖形結構(Graphs) 8-1 圖形的基本觀念 8-2 圖形的表示法 8-3 圖形的走訪 8-4 擴張樹
补充内容 结构体 概述 定义结构体类型和定义结构体变量 结构体变量的引用 结构体变量的初始化 指针与结构体 用typedef定义类型的别名.
数 据 结 构 Ch.6 树 计 算 机 学 院 肖明军
第七章 搜索结构 静态搜索结构 二叉搜索树 AVL树.
哈夫曼编码.
Chapter 5 樹(Trees).
第12章 樹狀搜尋結構 (Search Trees)
第六章 二叉树和树 6.1树的基本概念 6.2二叉树 6.3二叉树遍历 6.4线索二叉树 6.5树和森林 6.6树的应用(霍夫曼树及其编码)
演算法與資料結構 製作單位: 高雄市立高雄中學.
第5章 堆疊(Stacks) 5-1 堆疊的基礎 5-2 堆疊的表示法 5-3 堆疊的應用 - 運算式的計算與轉換
第5章 堆疊(Stacks) 5-1 堆疊的基礎 5-2 堆疊的表示法 5-3 堆疊的應用 - 運算式的計算與轉換
进程操作.
第六章 树和二叉树.
第 七 章 樹狀結構 課程名稱:資料結構 授課老師:________ 2019/1/1.
教 师:曾晓东 电 话: E_mail: 计算机软件技术基础 教 师:曾晓东 电 话: E_mail:
陈海明 副教授 信息学院 计算机系 电子信息类非计算机专业选修课 程序设计实践 陈海明 副教授 信息学院 计算机系
樹狀結構 Tree Structure chapter 7 德明科技大學資訊科技系.
親愛的老師您好 感謝您選用本書作為授課教材,博碩文化準備本書精選簡報檔,特別摘錄重點提供給您授課專用。 說明: 博碩文化:
Data Structure.
二叉树和其他树 (Binary and other trees)
第六章 樹狀結構 T r e e 版權屬作者所有,非經作者 同意不得用於教學以外用途.
樹 2 Michael Tsai 2013/3/26.
感謝同學們在加分題建議. 我會好好研讀+反省~
Chap4 Tree.
Tree & Binary Tree.
書名 Java於資料結構與演算法之實習應用
二叉树的遍历.
7.1 广义表的概念 广义表是n(n≥0)个数据元素组成的序列,其中每个数据元素或是单个数据元素(简称原子),或仍然是一个广义表 。
第六章 树和二叉树 £6.1 树 £6.2 二叉树 £6. 3 二叉树的存储结构 £6.4 二叉树的遍历与线索化 £6.1.1 树的定义
第六章 树和二叉树 学习要点 理解树的定义和基本术语,重点了解二叉树的定义、性质、存储结构; 掌握二叉树遍历的递归算法及它的典型运算;
第7章 樹與二元樹(Trees and Binary Trees)
資料結構使用Java 第9章 樹(Tree).
本教學投影片係屬教科書著作之延伸,亦受著作權法之保護。
Chapter 6 樹狀結構.
106二專班第二次作業 2017/11/27.
<编程达人入门课程> 本节内容 为什么要使用变量? 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ:
树和二叉树(一).
第4章 鏈結串列(Linked Lists) 4-1 動態記憶體配置-(6) 4-2 鏈結串列的基礎-(7)
Data Structure.
第10章 二元搜尋樹 (Binary Search Tree)
資料結構與C++程式設計進階 C++與資料結構 講師:林業峻 CSIE, NTU 7/ 5, 2010.
JAVA 程式設計與資料結構 第十七章 Tree.
Presentation transcript:

第7章 樹與二元樹 (Trees and Binary Trees) 7-1 樹的基本觀念 7-2 二元樹的基礎 7-3 二元樹的表示法 7-4 二元樹的走訪 7-5 二元搜尋樹 7-6 引線二元樹 7-7 樹的二元樹表示法 7-8 二元樹的應用 - 運算式處理

7-1 樹的基本觀念-說明 「樹」(Trees)是一種模擬現實生活中樹幹和樹枝的資料結構,屬於一種階層架構的非線性資料結構,例如:家族族譜,如下圖所示:

7-1 樹的基本觀念-架構1 樹的樹根稱為「根節點」(Root),在根節點之下是樹的樹枝,擁有0到n個「子節點」(Children),即樹的「分支」(Branch),節點A是樹的根節點,B、C、D….和H是節點A的子節點,即樹枝,如下圖所示:

7-1 樹的基本觀念-架構2 在樹枝下還可以擁有下一層樹枝,I和J是B的子節點,K、L和M是E的子節點,節點B是I和J的「父節點」(Parent),節點E是K、L和M的父節點,節點I和J擁有共同父節點,稱為「兄弟節點」(Siblings),K、L和M 是兄弟節點,B、C…和H節點也是兄弟節點,如下圖所示:

7-1 樹的基本觀念-定義 定義 7.1:樹的節點個數是一或多個有限集合,且: (1) 存在一個節點稱為根節點。 (2) 在根節點下的節點分成n >= 0 個沒有交集的多個子集合t1、t2…, tn,每一個子集合也是一棵樹,而這些樹稱為根節點的「子樹」(Subtree)。 樹在各節點之間不可以有迴圈,或不連結的左、右子樹,如下圖所示:

7-1 樹的基本觀念-相關術語1 n元樹:樹的一個節點最多擁有n個子節點。 二元樹(Binary Trees):樹的節點最多只有兩個子節點。 根節點(Root):沒有父節點的節點是根節點。例如:節點A。 葉節點(Leaf):節點沒有子節點的節點稱為葉節點。例如:節點I、J、C、D、K、L、M、F、G和H。 祖先節點(Ancenstors):指某節點到根節點之間所經過的所有節點,都是此節點的祖先節點。

7-1 樹的基本觀念-相關術語2 非終端節點(Non-terminal Nodes):除了葉節點之外的其它節點稱為非終端節點。例如:節點A、B和E是非終端節點。 分支度(Dregree):指每個節點擁有的子節點數。例如:節點B的分支度是2,節點E的分支度是3。 階層(Level):如果樹根是1,其子節點是2,依序可以計算出樹的階層數。例如:上述圖例的節點A階層是1,B、C到H是階層2,I、J到M是階層3。 樹高(Height):樹高又稱為樹深(Depth),指樹的最大階層數。例如:上述圖例的樹高是3。

7-2 二元樹的基礎-定義 樹依不同分支度可以區分成很多種,在資料結構中最廣泛使用的樹狀結構是「二元樹」(Binary Trees),二元樹是指樹中的每一個「節點」(Nodes)最多只能擁有2個子節點,即分支度小於或等於2。 二元樹的定義如下所示: 定義 7.2:二元樹的節點個數是一個有限集合,或是沒有節點的空集合。二元樹的節點可以分成兩個沒有交集的子樹,稱為「左子樹」(Left Subtree)和「右子樹」(Right Subtree)。

7-2 二元樹的基礎-圖例 二元樹 左子樹 右子樹

7-2 二元樹的基礎-歪斜樹 左邊這棵樹沒有右子樹,右邊這棵樹沒有左子樹,雖然擁有相同節點,但是這是兩棵不同的二元樹,因為所有節點都是向左子樹或右子樹歪斜,稱為「歪斜樹」(Skewed Tree),如下圖所示:

7-2 二元樹的基礎- 完滿二元樹(說明) 若二元樹的樹高是h且二元樹的節點數是2h-1,滿足此條件的樹稱為「完滿二元樹」(Full Binary Tree),如下圖所示:

7-2 二元樹的基礎- 完滿二元樹(節點數) 因為二元樹的每一個節點有2個子節點,二元樹樹高是3,也就是有3個階層(Level),各階層的節點數,如下所示: 第1階:1 = 2 (1-1) = 20 = 1 第2階:第1階節點數的2倍,1*2 = 2 (2-1) = 2 第3階:第2階節點數的2倍,2*2 = 2 (3-1) = 4 以此類推,可以得到每一階層的最大節點數是:2 (l-1),l是階層數,整棵二元樹的節點數一共是:20+21+22 = 7個,即23-1,可以得到: 20+21+22+….+2 (h-1) = 2h-1,h是樹高

7-2 二元樹的基礎-完整二元樹 若二元樹的節點不是葉節點,一定擁有2個子節點,不過節點總數不足2h-1,其中h是樹高,而且其節點編號是對應相同高度完滿二元樹的1至2h-1的節點編號,滿足此條件稱為完整二元樹(Complete Binary Tree),如下圖所示:

7-3 二元樹的表示法 7-3-1 二元樹陣列表示法 7-3-2二元樹結構陣列表示法 7-3-3 二元樹鏈結表示法

7-3 二元樹的表示法 二元樹在實作上有多種方法可以建立二元樹,常用的方法有三種,如下所示: 二元樹陣列表示法。 二元樹結構陣列表示法。 二元樹鏈結表示法。

7-3-1 二元樹陣列表示法-說明1 完滿二元樹是一棵樹高h擁有2h-1個節點的二元樹,這是二元樹在樹高h所能擁有的最大節點數,換句話說,只需配置2h-1個元素,我們就可以儲存樹高h的二元樹,如下圖所示:

7-3-1 二元樹陣列表示法-說明2 二元樹的節點編號擁有循序性,根節點1的子節點是節點2和節點3,節點2是4和5,依此類推可以得到節點編號的規則,如下所示: 左子樹是父節點編號乘以2。 右子樹是父節點編號乘以2加1。

7-3-1 二元樹陣列表示法-標頭檔 01: /* 程式範例: Ch7-3-1.h */ 02: #define MAX_LENGTH 16 /* 最大陣列尺寸 */ 03: int btree[MAX_LENGTH]; /* 二元樹陣列宣告 */ 04: /* 抽象資料型態的操作函數宣告 */ 05: extern void createBTree(int len, int *array); 06: extern void printBTree();

7-3-1 二元樹陣列表示法-建立二元樹(規則) 函數createBTree()讀取一維陣列的元素建立二元樹,其建立的規則,如下所示: 將第1個陣列元素插入成為二元樹的根節點。 將陣列元素值與二元樹的節點值比較,如果元素值大於節點值,將元素值插入成為節點的右子節點,如果右子節點不是空的,重覆比較節點值,直到找到插入位置後,將元素值插入二元樹。 如果元素值小於節點值,將元素值插入成為節點的左子節點,如果左子節點不是空的,繼續重覆比較,以便將元素值插入二元樹。

7-3-1 二元樹陣列表示法-建立二元樹(圖例) 二元樹陣列表示法圖例的索引值0並沒有使用,整個二元樹在16個陣列元素中使用的元素一共有9個,括號內是陣列的索引值,如下圖所示:

7-3-1 二元樹陣列表示法-顯示二元樹 函數printBTree():顯示二元樹 函數printBTree()走訪btree[]陣列,將元素值不是-1的元素都顯示出來。

7-3-1 二元樹陣列表示法-問題 一棵歪斜樹的二元樹陣列表示法使用不到三分之一的陣列元素4/16,因為二元樹的節點是以循序方式儲存在陣列中,如果需要插入或刪除節點,都需要在陣列中搬移大量元素,如下圖所示:

7-3-2二元樹結構陣列表示法-說明 在二元樹的每一個節點可以使用C語言的結構來儲存,整棵二元樹使用一個結構陣列,每一個結構是一個節點,使用結構陣列儲存整棵二元樹,data是節點資料,使用left和right成員變數的索引值指向子節點的索引值,如為-1表示沒有子節點,如下圖所示:

7-3-2二元樹結構陣列表示法-標頭檔 01: /* 程式範例: Ch7-3-2.h */ 02: #define MAX_LENGTH 16 /* 最大陣列尺寸 */ 03: struct Node { /* 二元樹的結構宣告 */ 04: int data; /* 節點資料 */ 05: int left; /* 指向左子樹的位置 */ 06: int right; /* 指向右子樹的位置 */ 07: }; 08: typedef struct Node TreeNode; /* 樹的節點新型態 */ 09: TreeNode btree[MAX_LENGTH]; 10: /* 抽象資料型態的操作函數宣告 */ 11: extern void createBTree(int len, int *array); 12: extern void printBTree();

7-3-2二元樹結構陣列表示法-圖例 例如:一棵二元樹和其結構陣列表示法,如下圖所示:

7-3-3 二元樹鏈結表示法-說明 二元樹鏈結表示法是使用動態記憶體配置來建立二元樹,類似結構陣列表示法的節點結構,只是成員變數改成兩個指向左和右子樹的指標,如下圖所示:

7-3-3 二元樹鏈結表示法-標頭檔 01: /* 程式範例: Ch7-3-3.h */ 02: struct Node { /* 二元樹的節點宣告 */ 03: int data; /* 儲存節點資料 */ 04: struct Node *left; /* 指向左子樹的指標 */ 05: struct Node *right; /* 指向右子樹的指標 */ 06: }; 07: typedef struct Node TNode; /* 二元樹節點的新型態 */ 08: typedef TNode *BTree; /* 二元樹鏈結的新型態 */ 09: BTree head = NULL; /* 二元樹根節點的指標 */ 10: /* 抽象資料型態的操作函數宣告 */ 11: extern void createBTree(int len, int *array); 12: extern void insertBTreeNode(int d); 13: extern int isBTreeEmpty(); 14: extern void printBTree(); 15: extern void inOrder(BTree ptr); 16: extern void printInOrder(); 17: extern void preOrder(BTree ptr); 18: extern void printPreOrder(); 19: extern void postOrder(BTree ptr); 20: extern void printPostOrder();

7-3-3 二元樹鏈結表示法-建立二元樹1 函數createBTree()使用for迴圈走訪參數的陣列元素,依序呼叫insertBTreeNode()函數將一個一個陣列元素的節點插入二元樹。首先是二元樹的根節點5,left和right指標指向NULL,如下圖所示:

7-3-3 二元樹鏈結表示法-建立二元樹2 第二次呼叫insertBTreeNode()函數插入元素6,鏈結至右子樹。第三次呼叫插入元素4成為左子樹。等到執行完createBTree()函數的for迴圈後,建立的二元樹,如下圖所示:

7-3-3 二元樹鏈結表示法-顯示二元樹 函數printBTree():顯示二元樹 函數printBTree()使用while迴圈分別走訪二元樹的左右分支,不過這個函數並沒有辦法顯示二元樹的全部節點資料。

7-4 二元樹的走訪 7-4-1 中序走訪方式 7-4-2 前序走訪方式 7-4-3 後序走訪方式

7-4 二元樹的走訪-說明 陣列和單向鏈結串列都只能從頭至尾或從尾至頭執行單向「走訪」(Traverse),不過二元樹的每一個節點都擁有指向左和右2個子節點的指標,所以走訪可以有兩條路徑。例如:一棵二元樹,如下圖所示:

7-4 二元樹的走訪-種類 二元樹的走訪過程是持續決定向左或向右走,直到沒路可走。很明顯的!二元樹的走訪是一種遞迴走訪,依照遞迴函數中呼叫的排列順序不同,可以分成三種走訪方式,如下所示: 中序走訪方式(Inorder Traversal)。 前序走訪方式(Preorder Traversal)。 後序走訪方式(Postorder Traversal)。

7-4-1 中序走訪方式-說明 中序走訪是沿著二元樹的左方往下走,直到無法繼續前進後,顯示節點,退回到父節點顯示父節點,然後繼續往右走,如果右方都無法前進,顯示節點,再退回到上一層。依照中序走訪第7-4節的二元樹,其顯示的節點順序,如下所示: 1,2,3,4,5,6,7,8,9 在上述中序走訪節點順序中,可以看出根節點5是位在正中間,之前都是左子樹的節點,之後都是右子樹的節點。

7-4-1 中序走訪方式-演算法 中序走訪的遞迴函數inOrder()使用二元樹指標ptr進行走訪,中序走訪的步驟,如下所示: Step 1:檢查是否可以繼續前進,即指標ptr不等於NULL。 Step 2:如果可以前進,其處理方式如下所示: (1) 遞迴呼叫inOrder(ptr->left)向左走。 (2) 處理目前的節點,顯示節點資料。 (3) 遞迴呼叫inOrder(ptr->right)向右走。

7-4-1 中序走訪方式-遞迴呼叫

7-4-2 前序走訪方式-說明 前序走訪方式是走訪到的二元樹節點,就立刻顯示節點資料,走訪的順序是先向樹的左方走直到無法前進後,才轉往右方走。依照前序走訪第7-4節的二元樹,其顯示的節點順序,如下所示: 5,4,2,1,3,6,8,7,9 在上述前序走訪節點順序中,可以看出根節點5一定是第1個,左右子樹的根節點一定在其它節點之前。

7-4-2 前序走訪方式-演算法 前序走訪的遞迴函數preOrder()使用二元樹指標ptr進行走訪,前序走訪的步驟,如下所示: Step 1:先檢查是否已經到達葉節點,也就是指標ptr等於NULL。 Step 2:如果不是葉節點表示可以繼續走,其處理方式如下所示: (1) 處理目前的節點,顯示節點資料。 (2) 遞迴呼叫preOrder(ptr->left)向左走。 (3) 遞迴呼叫preOrder(ptr->right)向右走。

7-4-2 前序走訪方式-遞迴呼叫

7-4-3 後序走訪方式-說明 後序走訪方式剛好和前序走訪相反,它是等到節點的2個子節點都走訪過後才執行處理,顯示節點資料。依照後序走訪第7-4節的二元樹,其顯示的節點順序,如下所示: 1,3,2,4,7,9,8,6,5 在上述後序走訪節點順序中,可以看出根節點5是最後1個,而且左右子樹的根節點一定在其它節點之後。

7-4-3 後序走訪方式-演算法 後序走訪的遞迴函數postOrder()使用二元樹指標ptr進行走訪,後序走訪的步驟,如下所示: Step 1:先檢查是否已經到達葉節點,就是指標ptr等於NULL。 Step 2:如果不是葉節點表示可以繼續走,其處理方式如下所示: (1) 遞迴呼叫postOrder(ptr->left)向左走。 (2) 遞迴呼叫postOrder(ptr->right)向右走。 (3) 處理目前的節點,顯示節點資料。

7-4-3 後序走訪方式-遞迴呼叫

7-5 二元搜尋樹 7-5-1 二元搜尋樹的節點搜尋 7-5-2 二元搜尋樹的節點刪除

7-5 二元搜尋樹-說明 「二元搜尋樹」(Binary Search Trees)是一種二元樹,其節點資料的排列擁有一些特性,如下所示: 二元樹的每一個節點值都不相同,在整棵二元樹中的每一個節點都擁有不同值。 每一個節點的資料大於左子節點(如果有的話)的資料,但是小於右子節點(如果有的話)的資料。 節點的左、右子樹也是一棵二元搜尋樹。

7-5 二元搜尋樹-說明 例如:在第7-3節建立的二元樹就是一棵二元搜尋樹,如下圖所示:

7-5-1 二元搜尋樹的節點搜尋-說明 二元搜尋樹的節點搜尋十分簡單,因為右子節點的值一定大於左子節點,所以只需從根節點開始比較,就知道搜尋值是位在右子樹或左子樹,繼續往子節點進行比較,就可以找出是否擁有指定的節點值。 例如:在第7-5節的二元搜尋樹找尋節點資料8,第一步與樹根5比較,因為比較大,所以節點在右子樹,接著和右子樹的節點6比較,還是比較大,所以繼續向右子樹走,然後是節點8,只需三次比較就可以找到搜尋值。

7-5-1 二元搜尋樹的節點搜尋-實作 在C程式是使用while迴圈配合ptr指標(指向根節點head)進行各子節點資料的比較,以便執行二元搜尋樹的搜尋,如下所示: while ( ptr != NULL ) { if ( ptr->data == d ) return ptr; else if ( ptr->data > d ) ptr = ptr->left; else ptr = ptr->right; } 上述while迴圈的if條件判斷是否找到,如果節點值比搜尋值大,ptr = ptr->left向左子樹找,否則,ptr = ptr->right向右子樹找。

7-5-2 二元搜尋樹的節點刪除-情況1 情況1:刪除葉節點 葉節點是指沒有左和右子節點的節點,例如:刪除二元搜尋樹的葉節點1和9,如下圖所示: if ( parent->left == ptr ) parent->left = NULL; else parent->right = NULL;

7-5-2 二元搜尋樹的節點刪除-情況2(根節點) 情況2:刪除節點沒有左子樹 根節點:刪除根節點5,只需將根節點指標指向其右子樹節點,如下圖所示: head = head->right;

7-5-2 二元搜尋樹的節點刪除-情況2(中間節點) 中間節點:如果刪除的是中間節點2和6,這兩個節點都沒有左子樹,此時是將刪除節點的父節點指向其右子節點即可,如下圖所示: if ( parent->left == ptr ) parent->left = ptr->right; else parent->right = ptr->right;

7-5-2 二元搜尋樹的節點刪除-情況3 情況3:刪除節點沒有右子樹 如果節點沒有右子樹,在此情況刪除節點,依節點的位置一樣可以分成二種:根節點和中間節點,節點刪除和情況2相似,只是左指標和右指標的交換。

7-5-2 二元搜尋樹的節點刪除-情況4(說明1) 情況4:刪除節點擁有左子樹和右子樹 刪除節點如果擁有左子樹和右子樹,其處理方式並不會因刪除節點的位置而不同。例如:一棵二元搜尋樹,如下圖所示:

7-5-2 二元搜尋樹的節點刪除-情況4(說明2) 在二元搜尋樹刪除節點6,它是父節點9的左子樹,如果可以找到節點位在節點2和節點8之間,將它取代成刪除節點的位置,如此並不需要搬移太多節點,就可以完成節點刪除。 例如:刪除節點6事實上是刪除原來的葉節點5,因為刪除操作是交換這兩個節點來完成。 從二元搜尋樹的特性可以看出符合條件的交換節點有兩個,如下所示: 節點5:從節點6的左子節點2一直從右子樹走到的葉節點 節點7:從節點6的右子節點8一直往左子樹走到的葉節點。

7-5-2 二元搜尋樹的節點刪除-情況4(實作) 筆者使用第一種方式找出符合條件的節點,即節點5,程式碼如下所示: parent = ptr; child = ptr->left; while ( child->right!=NULL ) { parent = child; child = child->right; } 上述parent是父節點,ptr是刪除節點,child是子節點,在先走到左子節點後,使用while迴圈往右子節點走,直到葉節點。

7-6 引線二元樹-說明 二元樹鏈結表示法如果擁有n個節點,因為每個節點有左、右2個指標,所以整棵二元樹有2*n個指標,其中指向NULL的比指向節點的還多。換句話說,善用這些NULL指標,就可以幫助我們走訪二元樹。 「引線二元樹」(Threaded Binary Trees)是將一些原來指向NULL的指標改為指向其他節點,以便提供協助來進行中序走訪二元樹。

7-6 引線二元樹-圖例

7-6 引線二元樹-建立(說明) 右引線二元搜尋樹(Right Threaded Binary Search Trees)是一種常用的引線二元樹,我們可以在只增加一個欄位的情況下,以右指標的引線來幫助我們中序走訪二元搜尋樹,如下圖所示:

7-6 引線二元樹-建立(節點結構) 在節點結構除了原二元樹欄位外,為了區分引線和指標,額外增加欄位來標示指標的用途,如下所示: struct TNode { int data; struct TNode *left; struct TNode *right; int isThread; }; typedef struct TNode RTNode; typedef RTNode *RTBTree;

7-6 引線二元樹-建立(新增左子節點) 當插入的新節點是左子節點時,只需將右引線指向其父節點parent,如下圖所示: parent->left->right = parent; parent->left->isThread = 1;

7-6 引線二元樹-建立(新增右子節點) 當插入的新節點是右子節點時,插入新節點newnode的右引線指向其父節點parent右引線原來所指的節點,如下所示: newnode->right = parent->right; newnode->isThread = 1; parent->right = newnode; parent->isThread = 0;

7-6 引線二元樹-中序走訪 首先從根節點開始,沿著左子樹的路徑往下走到葉節點,即中序走訪的開始節點,然後使用右指標是引線或指標來進行中序走訪,如下所示: 任何節點的右指標不是引線,需要從右子節點為起點,沿著左子樹的路徑往下走直到左指標為NULL為止。例如:節點6的右指標不是引線,由其右子節點8開始,沿著左子樹方向走,走到節點7時,符合左指標為NULL,找到的是中序走訪的節點7。 如果任何節點的右指標是引線,引線所指的節點是下一個中序走訪的節點。例如:節點1的右指標是引線,所以下一個中序走訪的節點是節點2。 請重覆上述操作直到右指標為NULL為止,就完成右引線二元搜尋樹的中序走訪。

7-7 樹的二元樹表示法-說明 二元樹在樹狀結構佔有十分重要的地位,這是因為所有樹都可以經過轉換,將它轉換成二元樹。例如:n元樹狀結構的每個節點擁有n個分支,處理不同數分支的節點都需要設計不同表示方法的程式碼,例如:二元樹需要2個指標,三個分支需要3個指標,以此類推。 不只如此,n元樹的NULL指標問題比二元樹更加嚴重,因為葉節點將擁有分支數個數的NULL指標,所以我們可以將樹先轉換成二元樹,直接使用二元樹表示法來建立樹狀結構。

7-7 樹的二元樹表示法-過程1 例如:一棵樹,如下圖所示:

7-7 樹的二元樹表示法-過程2 將樹轉換成二元樹,也就是將n個分支變成2個分支,只需把每個擁有同一個父節點的兄弟節點,將這些兄弟節點鏈結起來,保留最左邊的父子鏈結,將其它父子鏈結都打斷,就可以產生一棵二元樹,如下圖所示:

7-7 樹的二元樹表示法-過程3 接著將鏈結方向調整一下,就可以得到一棵二元樹,如下圖所示:

7-8 二元樹的應用 - 運算式處理(說明) 從樹的觀念而言,樹可以處理各種階層關係的問題,例如:賽程表和家族族譜等,如果將資料建立成二元搜尋樹,就成為一種很好的資料搜尋方法。 運算式處理可以使用堆疊執行轉換和求值,現在我們可以改為二元樹來處理運算式,建立運算式二元樹。

7-8 二元樹的應用 - 運算式處理(建立運算式二元樹1) 例如:將中序運算式轉換成二元樹,如下所示: 5*6+4*3 上述中序運算式的運算元是二元樹的葉節點,運算子是非終端節點,因為考量運算子的優先順序,乘號大於加號,所以前後兩個乘號運算子先處理,可以建立成二棵二元樹,如下圖所示:

7-8 二元樹的應用 - 運算式處理(建立運算式二元樹2) 接著處理低優先順序的加號,就完成運算式二元樹,如下圖所示:

7-8 二元樹的應用 - 運算式處理(建立運算式二元樹3) 一棵沒有依據算子優先順序建立的運算式二元樹,如下圖所示:

7-8 二元樹的應用 - 運算式處理(運算式二元樹的計算) 運算式二元樹只需從葉節點開始計算各子節點的值,然後依序往上就可以計算出整棵運算式二元樹的值,如下所示: 有優先順序的二元樹:42 5*6 = 30 4*3 = 12 30+12 = 42 不考慮優先順序的二元樹:150 6+4 = 10 5*10 = 50 50 *3 = 150

7-8 二元樹的應用 - 運算式處理(運算式二元樹的走訪) 使用中序走訪運算式二元樹,可以得到中序運算式,如下所示: 有優先順序的二元樹:5*6+4*3 不考慮優先順序的二元樹:5*6+4*3 使用前序走訪這兩棵二元樹,可以得到前序運算式,如下所示: 有優先順序的二元樹:+*56*43 不考慮優先順序的二元樹:**5+643 後序走訪的結果,如下所示: 有優先順序的二元樹:56*43+ 不考慮優先順序的二元樹:564+*3*