二叉樹應用樣本:運算式的處理
電腦求解算術運算式,一種自然的方法是採用運算式樹狀架構。
運算式樹狀架構是一種二叉樹,它的結點包含兩種類型的對象:操作符和終值。
操作符是擁有運算元的對象,而終值是沒有運算元的對象。
運算式樹狀架構的思想:儲存在父結點中的操作符,其運算元由其子結點延伸出來的子樹組成。運算元也可能就是終值,或者它們本身也可能是其他的運算式。運算式在子樹中展開,終值駐留在葉子結點中。
這種組織方式的好處是通過運算式樹狀架構可以使我們非常容易的將一個運算式轉換為3種常見的表示形式:首碼、中綴和尾碼。
要獲得這些表示形式,我們只需要按照前序、中序或者後序的遍曆方式周遊運算式樹狀架構的結點即可。
,按照前序的方式遍曆樹,得到的首碼運算式為:X / - 74 10 32 + 23 17。
要計算一個首碼運算式,我們將每個操作符和緊跟在後面的兩個運算元用圓括弧括起來。因此這個首碼運算式可轉化為:
( X ( / ( - 74 10) 32 ) ( + 23 17 )) = 80
中綴運算式是我們在數學中學到的最為熟悉的表達方式,但它們並不適合用電腦來處理。 如果我們把圖中的樹按照中序遍曆的方式遍曆,我們可以得到中綴運算式:74 - 10 / 32 X 23 + 17 。
注意中綴運算式的一個問題在於它們不能標識出計算的順序,而首碼運算式和尾碼運算式都可以做到。但是,我們可以在遍曆樹的過程中通過將每一部分的運算式都加上圓括弧來修正這個問題。全部加完括弧後,這個中綴運算式可以轉化為:
(((74-10)/32 X (23+17)) = 80
尾碼運算式非常適合於用電腦來處理。如果把圖中的樹按照後序遍曆的方式遍曆,就可以得到尾碼運算式:74 10 - 32 / 23 17 + X。
要計算一個後序運算式,將每個操作符與緊接在其前面的兩個運算元用圓括弧括起。這樣,尾碼運算式將轉化為:
(((74 10 -) 32 / ) ( 23 17 +) X) = 80
尾碼運算式適合於電腦處理的一個原因是它們能夠非常容易通過 抽象棧狀態機器(abstract stack machine)的方式來進行計算。按照抽象狀態機器的方式來處理一個尾碼運算式,將採用如下步驟:首先,從左至右遍曆運算式,將值壓入棧中直到遇到一個操作符為止。然後,該操作符所需要的運算元被彈出棧,將操作符施加於運算元上並將結果重新壓入棧中。這個過程將一直重複直到整個運算式都處理完畢。到那時,運算式的最終結果就是唯一還留在棧中的元素(如所示)。
程式碼範例1說明 了如何通過運算式樹狀架構中儲存的表達 式產生首碼、中綴和尾碼運算式。基於這一目的,提供了3個函數:preorder、inorder、postorder。它們分別採用前序、中序、後序的方式來遍曆運算式樹狀架構。每個函數都接受兩個參數node和list。
開始遍曆時,將參數node設定為希望進行遍曆的運算式樹狀架構的根結點。連續的遞迴調用會將node設定為將要子樹的根結點。初次每個函數調用時,還會把一個經過list_init初始化過的空鏈表傳給參數list。對於每次的遍曆,按照訪問結點的順序把它們加入鏈表list中。當首個遞迴調用最終返回時,list就分別包含按照前序、中序、後序方式遍曆的結點。
樣本1:遍曆二叉樹的實現函數
/*traverse.c*/
#include "list.h"
#include "traverse.h"
/*preorder 前序走訪*/
int perorder(const BiTreeNode *node,Lis list)
{
/*載入列表與樹的前序列表*/
if(!bitree_is_eob(node))
{
if(list_ins_next(list,list_tail(list),bitree_data(node)) != 0)
return -1;
if(!bitree_is_eob(bitree_left(node)))
if(preorder(bitree_left(node),list) !=0 )
return -1;
if(!bitree_is_eob(bitree_right(node))
if(preorder(bitree_right(node),list) !=0 )
return -1;
}
return 0;
}
/*inorder 中序遍曆*/
int inorder(const BiTreeNode *node,List *list)
{
/*載入列表與樹的中序列表*/
if(!bitree_is_eob(node))
{
if(!bitree_is_ebo(bitree_left(node)))
if(inorder(bitree_left(node),list) != 0 )
return -1;
if(list_ins_next(list,list_tail(list),bitree_data(node))!=0)
return -1;
if(!bitree_is_eob(bitree_right(node)))
if(inorder(bitree_right(node),list) !=0 )
return -1;
}
return 0;
}
/*postorder 後序遍曆*/
int postorder(const BiTreeNode *node,List *list)
{
/*載入列表與樹的後序列表*/
if(!bitree_is_eob(node))
{
if(!bitree_is_eob(bitree_left(node))
if(postorder(bitree_left(node),list)!=0)
return -1;
if(!bitree_is_eob(bitree_right(node))
if(postorder(bitree_right(node),list)!=0)
return -1;
if(list_ins_next(list,list_tail(list),bitree_data(node))!=0)
return -1;
}
return 0;
}
本文永久更新連結地址:https://www.bkjia.com/Linux/2018-03/151316.htm