在路上---學習篇(一)Python 資料結構和演算法 (5)二分尋找、二叉樹遍曆

來源:互聯網
上載者:User

標籤:小知識點   大於   路徑   search   add   廣度   二分尋找   情況下   bin   

獨白:

  利用演算法進行尋找指定元素,最近學習二分尋找和二叉樹遍曆。二分尋找前提是在有序中進行尋找,二叉樹引入了樹的概念。樹的概念其中有許多小知識點,也是一種新的資料結構。還是之前的感悟,需瞭解其本質才會寫出更好的演算法。

 

 

二分尋找

  二分尋找又稱折半尋找,優點是比較次數少,尋找速度快,平均效能好;其缺點是要求待查表為有序表,且插入刪除困難。因此,折半尋找方法適用於不經常變動而尋找頻繁的有序列表。首先,假設表中元素是按升序排列,將表中間位置記錄的關鍵字與尋找關鍵字比較,如果兩者相等,則尋找成功;否則利用中間位置記錄將表分成前、後兩個子表,如果中間位置記錄的關鍵字大於尋找關鍵字,則進一步尋找前一子表,否則進一步尋找後一子表。重複以上過程,直到找到滿足條件的記錄,使尋找成功,或直到子表不存在為止,此時尋找不成功。

 

‘‘‘二分尋找時間複雜度:O(logn)‘‘‘‘‘‘前提是在一個有序的列表‘‘‘import time## def binary_search(list, item):#     ‘‘‘ 非遞迴實現 ‘‘‘##     first = 0#     last = len(list) - 1#     while first <= last :#         midpoint = ( first + last ) // 2#         if list[midpoint] == item:#             return True#         elif item < list[midpoint]:#             last = midpoint - 1#         else:#             first = midpoint + 1#     return Falsedef binary_search(list, item):    """ 遞迴實現 """    print(list)    if len(list) == 0:        return False    else:        midpoint = len(list) // 2        if list[midpoint] == item:            return True        else:            if list[midpoint] > item:                return binary_search(list[:midpoint], item)            else:                return binary_search(list[midpoint + 1:], item)if __name__ == ‘__main__‘:    # 開始時間    first_time = time.time()    # 建立個有序的列表    lis = [1, 2, 5, 6, 7, 8, 9, 17, 156, 678]    # 列表排序    print(binary_search(lis, 6))    # 結束時間    last_time = time.time()    print("共用時%s" % (last_time - first_time))

 

 

 

樹與樹演算法樹的概念

樹(英語:tree)是一種抽象資料類型(ADT)或是實作這種抽象資料類型的資料結構,用來類比具有樹狀結構性質的資料集合。它是由n(n>=1)個有限節點群組成一個具有層次關係的集合。把它叫做“樹”是因為它看起來像一棵倒掛的樹,也就是說它是根朝上,而葉朝下的。它具有以下的特點: 

  • 每個節點有零個或多個子節點; 
  • 沒有父節點的節點稱為根節點; 
  • 每一個非根節點有且只有一個父節點; 
  • 除了根節點外,每個子節點可以分為多個不相交的子樹;
樹的術語
  • 節點的度:一個節點含有的子樹的個數稱為該節點的度;
  • 樹的度:一棵樹中,最大的節點的度稱為樹的度;
  • 分葉節點或終端節點:度為零的節點;
  • 父親節點或父節點:若一個節點含有子節點,則這個節點稱為其子節點的父節點;
  • 孩子節點或子節點:一個節點含有的子樹的根節點稱為該節點的子節點;
  • 兄弟節點:具有相同父節點的節點互稱為兄弟節點;
  • 節點的層次:從根開始定義起,根為第1層,根的子節點為第2層,以此類推;
  • 樹的高度或深度:樹中節點的最大層次;
  • 堂兄弟節點:父節點在同一層的節點互為堂兄弟;
  • 節點的祖先:從根到該節點所經分支上的所有節點;
  • 子孫:以某節點為根的子樹中任一節點都稱為該節點的子孫。
  • 森林:由m(m>=0)棵互不相交的樹的集合稱為森林;
樹的種類
  • 無序樹:樹中任意節點的子節點之間沒有循序關聯性,這種樹稱為無序樹,也稱為自由樹;
  • 有序樹:樹中任意節點的子節點之間有循序關聯性,這種樹稱為有序樹;
    • 二叉樹:每個節點最多含有兩個子樹的樹稱為二叉樹; 
      • 完全二叉樹:對於一顆二叉樹,假設其深度為d(d>1)。除了第d層外,其它各層的節點數目均已達最大值,且第d層所有節點從左向右連續地緊密排列,這樣的二叉樹被稱為完全二叉樹,其中滿二叉樹的定義是所有分葉節點都在最底層的完全二叉樹; 
      • 平衡二叉樹(AVL樹):若且唯若任何節點的兩棵子樹的高度差不大於1的二叉樹; 
      • 排序二叉樹(二叉尋找樹(英語:Binary Search Tree),也稱二叉搜尋樹、有序二叉樹); 
    • 霍夫曼樹(用於資訊編碼):帶權路徑最短的二叉樹稱為哈夫曼樹或最優二叉樹;
    • B樹:一種對讀寫操作進行最佳化的自平衡的二叉尋找樹,能夠保持資料有序,擁有多餘兩個子樹

 

二叉樹的基本概念

二叉樹是每個節點最多有兩個子樹的樹結構。通常子樹被稱作“左子樹”(left subtree)和“右子樹”(right subtree) 

二叉樹的性質(特性)

性質1: 在二叉樹的第i層上至多有2^(i-1)個結點(i>0)
性質2: 深度為k的二叉樹至多有2^k - 1個結點(k>0)
性質3: 對於任意一棵二叉樹,如果其葉結點數為N0,而度數為2的結點總數為N2,則N0=N2+1;
性質4:具有n個結點的完全二叉樹的深度必為 log2(n+1)
性質5:對完全二叉樹,若從上至下、從左至右編號,則編號為i 的結點,其左孩子編號必為2i,其右孩子編號必為2i+1;其雙親的編號必為i/2(i=1 時為根,除外)

class Node(object):    ‘‘‘節點類‘‘‘    def __init__(self, elem, lchild = None, rchild = None):        self.elem = elem        self.lchild = lchild        self.rchild = rchildclass Tree(object):    ‘‘‘樹類‘‘‘    def __init__(self, root = None):        self.root = root    def add(self, elem):        ‘‘‘為樹添加節點‘‘‘        node = Node(elem)        # 如果是空樹,對根節點進行賦值        if self.root == None:            self.root = node            return        else:            queue = []            queue.append(self.root)            # 對已有節點進行層次遍曆            while queue:                # 彈出隊列的第一個元素                cur = queue.pop(0)                if cur.lchild is None:                    cur.lchild = node                    return                elif cur.rchild is None:                    cur.rchild = node                    return                else:                    # 如果左右節點不為空白,排入佇列繼續判斷                    queue.append(cur.lchild)                    queue.append(cur.rchild)

 

 

二叉樹的遍曆

樹的遍曆是樹的一種重要的運算。所謂遍曆是指對樹中所有結點的資訊的訪問,即依次對樹中每個結點訪問一次且僅訪問一次,我們把這種對所有節點的訪問稱為遍曆(traversal)。那麼樹的兩種重要的遍曆模式是深度優先遍曆和廣度優先遍曆,深度優先一般用遞迴,廣度優先一般用隊列。一般情況下能用遞迴實現的演算法大部分也能用堆棧來實現。

 

深度優先遍曆

對於一顆二叉樹,深度優先搜尋(Depth First Search)是沿著樹的深度遍曆樹的節點,儘可能深的搜尋樹的分支。
那麼深度遍曆有重要的三種方法。這三種方式常被用於訪問樹的節點,它們之間的不同在於訪問每個節點的次序不同。這三種遍曆分別叫做先序遍曆(preorder),中序遍曆(inorder)和後序遍曆(postorder)。我們來給出它們的詳細定義,然後舉例看看它們的應用。

    • 先序遍曆 在先序遍曆中,我們先訪問根節點,然後遞迴使用先序遍曆訪問左子樹,再遞迴使用先序遍曆訪問右子樹
      根節點->左子樹->右子樹

 

def preorder(self, root):    """遞迴實現先序遍曆"""    if root == None:        return    print(root.elem)    self.preorder(root.lchild)    self.preorder(root.rchild)

 

 

    • 中序遍曆 在中序遍曆中,我們遞迴使用中序遍曆訪問左子樹,然後訪問根節點,最後再遞迴使用中序遍曆訪問右子樹                                 左子樹->根節點->右子樹

 

def inorder(self, root):    """遞迴實現中序遍曆"""    if root == None:        return    self.inorder(root.lchild)    print(root.elem)    self.inorder(root.rchild)

 

 

    • 後序遍曆 在後序遍曆中,我們先遞迴使用後序遍曆訪問左子樹和右子樹,最後訪問根節點                                                                               左子樹->右子樹->根節點

 

def postorder(self, root):    """遞迴實現後續遍曆"""    if root == None:        return    self.postorder(root.lchild)    self.postorder(root.rchild)    print (root.elem)

 

 

廣度優先遍曆(層次遍曆)

從樹的root開始,從上到下從從左至右遍曆整個樹的節點

 

def breadth_travel(self, root):    """利用隊列實現樹的層次遍曆"""    if root == None:        return    queue = []    queue.append(root)    while queue:        node = queue.pop(0)        print (node.elem)        if node.lchild != None:            queue.append(node.lchild)        if node.rchild != None:            queue.append(node.rchild)

 

在路上---學習篇(一)Python 資料結構和演算法 (5)二分尋找、二叉樹遍曆

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.