之前整理過(guò)非遞歸方式遍歷二叉樹(shù)的后序遍歷的方式,先簡(jiǎn)單回顧一下:
第一種思路:對(duì)于任一結(jié)點(diǎn)P,將其入棧,然后沿其左子樹(shù)一直往下搜索,直到搜索到?jīng)]有左孩子的結(jié)點(diǎn),此時(shí)該結(jié)點(diǎn)出現(xiàn)在棧頂,但是此時(shí)不能將其出棧并訪問(wèn),因此其右孩子還為被訪問(wèn)。所以接下來(lái)按照相同的規(guī)則對(duì)其右子樹(shù)進(jìn)行相同的處理,當(dāng)訪問(wèn)完其右孩子時(shí),該結(jié)點(diǎn)又出現(xiàn)在棧頂,此時(shí)可以將其出棧并訪問(wèn)。這樣就保證了正確的訪問(wèn)順序。可以看出,在這個(gè)過(guò)程中,每個(gè)結(jié)點(diǎn)都兩次出現(xiàn)在棧頂,只有在第二次出現(xiàn)在棧頂時(shí),才能訪問(wèn)它。因此需要多設(shè)置一個(gè)變量標(biāo)識(shí)該結(jié)點(diǎn)是否是第一次出現(xiàn)在棧頂。
第二種思路:要保證根結(jié)點(diǎn)在左孩子和右孩子訪問(wèn)之后才能訪問(wèn),因此對(duì)于任一結(jié)點(diǎn)P,先將其入棧。如果P不存在左孩子和右孩子,則可以直接訪問(wèn)它;或者P存在左孩子或者右孩子,但是其左孩子和右孩子都已被訪問(wèn)過(guò)了,則同樣可以直接訪問(wèn)該結(jié)點(diǎn)。若非上述兩種情況,則將P的右孩子和左孩子依次入棧,這樣就保證了每次取棧頂元素的時(shí)候,左孩子在右孩子前面被訪問(wèn),左孩子和右孩子都在根結(jié)點(diǎn)前面被訪問(wèn)。
由于接下來(lái)會(huì)用到先序遍歷,所以,我們順便回憶一下先序遍歷的非遞歸算法:
對(duì)于任一結(jié)點(diǎn)P:
(1)訪問(wèn)結(jié)點(diǎn)P,并將結(jié)點(diǎn)P入棧;
(2)判斷結(jié)點(diǎn)P的左孩子是否為空,若為空,則取棧頂結(jié)點(diǎn)并進(jìn)行出棧操作,并將棧頂結(jié)點(diǎn)的右孩子置為當(dāng)前的結(jié)點(diǎn)P,循環(huán)至1);若不為空,則將P的左孩子置為當(dāng)前的結(jié)點(diǎn)P;
(3)直到P為NULL并且棧為空,則遍歷結(jié)束。
不過(guò)現(xiàn)在看考研書,書中提供了一種新的思路,之前完全沒(méi)有想到:
對(duì)于上面的二叉樹(shù),我們可以寫出它的前序遍歷方式:
A,B ,D,G,C,E,F
其后序遍歷方式為:
G,D,B,E,F,C,A
如果我們把后序遍歷逆序:
A,C,F,E,B,D,G
仔細(xì)看一看,我想你一定已經(jīng)發(fā)現(xiàn)規(guī)律了,如果我們把后序遍歷逆序后的結(jié)果稱為逆后序遍歷,那么逆后序遍歷只不過(guò)是先序遍歷過(guò)程中對(duì)左右子樹(shù)遍歷順序交換所得到的結(jié)果。
因此,只需要將先序遍歷的非遞歸算法中對(duì)左右子樹(shù)的遍歷順序交換就可以得到逆后序遍歷的序列,然后再將逆后序遍歷的結(jié)果逆序就得到了后序遍歷的結(jié)果,因此我們需要兩個(gè)棧,一個(gè)棧stack1用于輔助做逆后序遍歷,并將遍歷結(jié)果序列壓入另一個(gè)棧stack2,然后將stack2的元素全部出棧,所得到的序列就是后序遍歷的結(jié)果。