1. 程式人生 > >學習筆記-二叉樹-先序、中序、後序、層次遍歷的實現(Python)

學習筆記-二叉樹-先序、中序、後序、層次遍歷的實現(Python)

一、二叉樹類的Python實現及其函式:包括統計結點個數,用遞迴實現的先序遍歷,非遞迴實現的先序遍歷,以及非遞迴實現的後序遍歷。

class StackUnderflow(ValueError):   
    pass  
  
class SStack():  
    def __init__(self):  
        self.elems = []  
          
    def is_empty(self):  
        return self.elems == []  
      
    def top(self): #取得棧裡最後壓入的元素,但不刪除  
        if self.elems == []:  
            raise StackUnderflow('in SStack.top()')  
        return self.elems[-1]  
      
    def push(self, elem):  
        self.elems.append(elem)  
          
    def pop(self):  
        if self.elems == []:  
            raise StackUnderflow('in SStack.pop()')  
        return self.elems.pop()
  
class BinTNode:
    def __init__(self, dat, left = None, right = None):
        self.data = dat
        self.left = left
        self.right = right

#統計樹中結點的個數
def count_BinTNodes(t): 
    if t is None:
        return 0
    else:
        return 1 + count_BinTNodes(t.left) + count_BinTNodes(t.right)
    
#假設結點中儲存的是數值,求此時二叉樹裡的所有數值的和
def sum_BinTNodes(t): 
    if t is None:
        return 0
    else:
        return t.data + sum_BinTNodes(t.left) + sum_BinTNodes(t.right)
    
def proc(x):
    print(x, end = '')

#利用遞迴實現的先序遍歷
def pre_order(t): 
    if t is None:
        return
    proc(t.data)
    pre_order(t.left)
    pre_order(t.right)
  
#利用非遞迴實現的先序遍歷
def preorder_nonrec(t):
    s = SStack()
    while t is not None or not s.is_empty():
        while t is not None:
            proc(t.data)
            s.push(t.right) #右分支入棧
            t = t.left     #沿著左分支下行
        t = s.pop()       #遇到空樹,回溯
    
#用帶有括號的形式顯示出樹,^代表空
def print_BinTNodes(t): 
    if t is  None:
        print('^', end = '')
        return
    print('(' + str(t.data), end = '')
    print_BinTNodes(t.left)
    print_BinTNodes(t.right)
    print(')', end = '')
    
#用生成器實現非遞迴先序遍歷;當需要遍歷資料的時候,總應該想到迭代器
def preorder_elemnts(t):
    s = SStack()
    while t is not None or not s.is_empty():
        while t is not None:
            s.push(t.right) #右分支入棧
            yield t.data
            t = t.left
        t = s.pop()
    #非遞迴遍歷演算法的一個重要用途是作為實現迭代器的基礎
        
#利用非遞迴實現的後序遍歷
def postorder_elements(t):
    s = SStack()
    while t is not None or not s.is_empty():
        while t is not None: #下行迴圈,知道到達樹的葉結點
            s.push(t) #將樹壓入棧中
            t = t.left if t.left is not None else t.right #如果左子結點不空就先訪問左子結點,為空就訪問右子結點
            
        t = s.pop() #將棧頂的子樹彈出   
        proc(t.data)
        if not s.is_empty() and s.top().left == t: #如果棧不為空且當前的子樹是現在棧頂的左子結點
            t = s.top().right       #就轉到當前棧頂的右子結點
        else:
            t = None

if __name__=="__main__":
    t = BinTNode(1, BinTNode(2, BinTNode(4), BinTNode(5)), BinTNode(3, BinTNode(6), BinTNode(7)))
    t = BinTNode(1, BinTNode(2,BinTNode(5)), BinTNode(3))
    print(count_BinTNodes(t))
    print(sum_BinTNodes(t))
    preorder_nonrec(t)
    print(pre_order(t))
    print_BinTNodes(t)
    for i in preorder_elements(t):
        print(i)
    postorder_elements(t)

二、下面是不用自己構造的棧類所寫的4種遍歷的實現:

class BinTNode:
    def __init__(self, dat, left = None, right = None):
        self.data = dat
        self.left = left
        self.right = right


# 利用遞迴實現的先序遍歷
def pre_order(t):
    if t == None:
        return
    print(t.data)
    pre_order(t.left)
    pre_order(t.right)


# 利用遞迴實現的中序遍歷
def mid_order(t):
    if t == None:
        return
    mid_order(t.left)
    print(t.data)
    mid_order(t.right)


# 利用遞迴實現的後序遍歷
def post_order(t):
    if t == None:
        return
    post_order(t.left)
    post_order(t.right)
    print(t.data)


# 利用非遞迴實現的先序遍歷
def pre_order_nonrec(t):
    stack = []
    while t != None or stack != []:
        while t != None:
            print(t.data)
            stack.append(t.right)  # 右分支入棧
            t = t.left  # 沿著左分支下行
        t = stack.pop()  # 遇到空樹,回溯


# 利用非遞迴實現的中序遍歷
def mid_order_nonrec(t):
    stack = []
    while t != None or stack != []:  # 最開始時棧為空,但t不為空;t = t.right可能為空,棧不為空;當兩者都為空時,說明已經全部遍歷完成了
        while t != None:
            stack.append(t)
            t = t.left
        t = stack.pop()  # 將棧頂元素彈出
        print(t.data)
        t = t.right   # 將當前結點的右子結點賦給t,讓其在while中繼續壓入棧內


# 利用非遞迴實現的後序遍歷
def post_order_nonrec(t):
    stack = []
    while t != None or stack != []:
        while t != None:  # 下行迴圈,直到到達樹的葉結點
            stack.append(t)  # 將樹壓入棧中
            t = t.left if t.left is not None else t.right  # 如果左子結點不空就先訪問左子結點,為空就訪問右子結點
        t = stack.pop()  # 將棧頂的子樹彈出
        print(t.data)
        if stack != [] and stack[-1].left == t:  # 如果棧不為空且當前的子樹是現在棧頂的左子結點
            t = stack[-1].right  # 就轉到當前棧頂的右子結點
        else:
            t = None    #否則就直接置為None,從棧中彈出下一個元素

#層次遍歷
def level_order(t):
     if t == None:
        return
     lst = []
     lst.append(t)
     while lst:
         current=lst.pop(0)
         print(current.data)
         if current.left!=None:
            lst.append(current.left)
         if current.right!=None:
            lst.append(current.right)

if __name__ == "__main__":
    t = BinTNode(1, BinTNode(2, BinTNode(4), BinTNode(5)), BinTNode(3, BinTNode(6), BinTNode(7)))
    # t = BinTNode(1, BinTNode(2, BinTNode(5)), BinTNode(3))
    pre_order(t)
    pre_order_nonrec(t)

    mid_order(t)
    mid_order_nonrec(t)

    post_order(t)
    post_order_nonrec(t)

    level_order(t)