數據結構-python

1 概念node

1.1 時間複雜度python

假設存在函數g,使得算法A處理規模爲n的問題示例所用時間爲T(n)=O(g(n))則稱T(n)爲算法A的漸近時間複雜度,簡稱時間複雜度。算法

g(n)則稱爲一個時間複雜度的大O表示法。數組

漸近函數定義:考慮一個函數  ,咱們須要瞭解當  變得很是大的時候  的性質。令  ,在 特別大的時候,第二項 數據結構

                            

比起第一項  要小不少。因而對於這個函數,有以下斷言:    的狀況下與  漸近等價」,記做  app

最壞時間複雜度:算法完成工做最多須要多少基本操做。函數

時間複雜度的基本計算規則:post

  1. 基本操做,即只有常數項,認爲其時間複雜度爲O(1)
  2. 順序結構,時間複雜度按加法進行計算
  3. 循環結構,時間複雜度按乘法進行計算
  4. 分支結構,時間複雜度取最大值
  5. 判斷一個算法的效率時,每每只須要關注操做數量的最高次項,其它次要項和常數項能夠忽略

常見時間複雜度:性能

執行次數函數舉例 非正式術語
12 O(1) 常數階
2n+3 O(n) 線性階
3n^2+2n+1 O(n^2) 平方階
5log2n+20 O(logn) 對數階
2n+3nlog2n+19 O(nlogn) nlogn階
6n^3+2n^2+3n+4 O(n^3) 立方階
2^n O(2^n) 指數階

常見時間複雜度之間的關係:測試

所消耗的時間從小到大:O(1) < O(logn) < O(n) < O(nlogn) < O(n^2) < O(n^3) < O(2^n) < O(n!) < O(n^n)

1.2 timeit模塊(python內置模塊分析性能)

class timeit.Timer(stmt='代碼', setup='運行代碼的設置', timer=<定時器函數>)

timeit.Timer.timeit(number=1000000):Timer類中測試語句執行速度的對象方法。number參數是測試代碼時的測試次數。

def cal():
    for a in range(1001):
        for b in range(1001-a):
            c = 1000-a-b
            if  a**2 + b**2 == c**2 :
                return a,b,c

t = timeit.Timer('cal()','from __main__ import cal')
print(t.timeit(number=1000))

1.3 數據結構

數據結構只是靜態的描述了數據元素之間的關係。Python的內置數據結構:列表、元組、字典。

程序 = 數據結構 + 算法 

抽象數據類型(ADT):一個數學模型以及定義在此數學模型上的一組操做。

經常使用數據運算:插入、刪除、修改、查找、排序。

2 線性表

  • 順序表,將元素順序地存放在一塊連續的存儲區裏,元素間的順序關係由它們的存儲順序天然表示。
  • 鏈表,將元素存放在經過連接構造起來的一系列存儲塊中。

2.1 順序表

eg.python中list爲線性表。

eg.int類型在32位計算機中,存儲空間爲4個字節(8位),在內存中按照連續存儲單元(1個字節)進行存儲。

     一、連續存儲元素信息   二、連續存儲地址信息

2.1.1 線性表結構

線性表的空間是固定的,若要進行擴充:一、增長固定數目  二、每次擴充容量加倍

頭部插入數據時間複雜度爲O(1),中間插入和尾部插入時間複雜度爲O(n)。

list內置操做的時間複雜度:

dict內置操做的時間複雜度:

2.2 鏈表

在每個節點(數據存儲單元)裏存放下一個節點的位置信息(即地址)。鏈表須要額外開銷存儲位置信息,可是在內存中是分散存儲的,因此能夠充分離散的內存空間。

2.2.1 單向鏈表

 

class SingleNode(object):
    '''節點'''
    def __init__(self,item):
        self.elem = item
        self.next = None

class SingleLink(object):
    def __init__(self):
        self.__head =None

    def is_empty(self):
        '''鏈表是否爲空'''
        return self.__head ==None

    def length(self):
        '''鏈表長度'''
        #cur遊標,用來移動遍歷節點
        cur = self.__head
        count = 0
        while cur != None:
            count +=1
            cur = cur.next
        return count

    def travel(self):
        '''遍歷整個鏈表'''
        cur = self.__head
        while cur != None:
            print(cur.elem,end= '')
            cur = cur.next

    def add(self,item):
        '''鏈表頭部添加元素'''
        # 先建立一個保存item值的節點
        node = SingleNode(item)
        node.next = self.__head
        self.__head = node

    def append(self,item):
        '''鏈表尾部添加元素'''
        node = SingleNode(item)
        if self.__head == None:
            self.__head = node
        else:
            cur = self.__head
            while cur.next != None:
                cur = cur.next
            cur.next = node

    def insert(self,pos,item):
        '''指定位置添加元素'''
        node = SingleNode(item)
        cur = self.__head
        if pos ==0:
            node.next = cur
            self.__head = node
        elif self.length()-1< pos:
            while cur != None:
                cur = cur.next
            cur.next =item
        else:
            count = 0
            while count != pos-1:
                count +=1
                cur = cur.next
            node.next = cur.next
            cur.next = node

    def remove(self,item):
        '''指定元素刪除節點'''
        node = SingleNode(item)
        cur = self.__head
        pre = None
        while cur!= None:
            if cur.elem == node.elem:
                # 若是第一個就是刪除的節點
                if not pre:
                    self.__head = cur.next
                else:
                    pre.next = cur.next
                break
            else:
                pre = cur
                cur = cur.next

    def search(self,item):
        '''查找節點是否存在'''
        cur = self.__head
        node = SingleNode(item)
        while cur !=None:
            if cur.elem == node.elem:
                return True
            else:
                cur = cur.next
        return False

if __name__ == '__main__':
    l = SingleLink()
    print(l.is_empty())
    l.add(1)
    l.add(2)
    l.append(0)
    l.insert(0,3)
    l.insert(2, 0)
    l.remove(0)
    l.remove(4)
    print(l.is_empty())
    print(l.search(4))
    print(l.search(0))
    print(l.length())
    l.travel()

2.2.2 雙向鏈表

 

class DoubleNode(object):
    def __init__(self,item):
        self.elem = item
        self.pre = None
        self.next = None

class DoubleLink(object):
    def __init__(self):
        self.__head = None

    def is_empty(self):
        return  self.__head == None

    def length(self):
        cur = self.__head
        count = 0
        while cur!=None:
            count +=1
            cur= cur.next
        return count

    def travel(self):
        cur = self.__head
        if self.__head ==None:
            return
        else:
            while cur!=None:
                print(cur.elem,end="")
                cur = cur.next
            print("")

    def add(self,item):
        node = DoubleNode(item)
        if self.__head ==None:
            self.__head = node
        else:
            node.next =self.__head
            self.__head.pre = node
            self.__head = node

    def append(self,item):
        node =DoubleNode(item)
        if self.__head ==None:
            self.__head = node
        else:
            cur = self.__head
            while cur.next!=None:
                cur = cur.next
            node.pre = cur
            cur.next = node

    def insert(self,pos,item):
        node = DoubleNode(item)
        if pos <=0:
            self.add(item)
        elif pos >= self.length():
            self.append(item)
        else:
            count = 0
            cur = self.__head
            if count != pos:
                count +=1
                cur = cur.next
            node.next = cur
            node.pre = cur.pre
            cur.pre.next = node
            cur.pre = node

    def remove(self,item):
        node = DoubleNode(item)
        if self.__head ==None:
            return
        else:
            cur = self.__head
            if cur.elem == item:
                # 若是首節點的元素便是要刪除的元素
                if cur.next == None:
                    # 若是鏈表只有這一個節點
                    self.__head = None
                else:
                    # 將第二個節點的prev設置爲None
                    cur.next.pre = None
                    # 將_head指向第二個節點
                    self.__head = cur.next
                return
            while cur.next!= None:
                if cur.elem == item:
                    # 將cur的前一個節點的next指向cur的後一個節點
                    cur.pre.next = cur.next
                    # 將cur的後一個節點的prev指向cur的前一個節點
                    cur.next.pre = cur.pre
                    break
                cur = cur.next
            #刪除的是最後一個
            if cur.elem ==item:
                cur.pre.next = None
            else:
                return

    def search(self,item):
        node = DoubleNode(item)
        cur = self.__head
        while cur !=None:
            if cur.elem != node.elem:
                cur =cur.next
            else:
                return True
        return False

2.2.3 單向循環列表

 

class SingleCircleNode(object):
    def __init__(self,item):
        self.elem = item
        self.node =None

class SingleCircleLink(object):
    def __init__(self):
        self.__head = None

    def is_empty(self):
        return  self.__head == None

    def length(self):
        if self.__head == None:
            return 0
        else:
            count = 1
            cur = self.__head
            while cur.next != self.__head:
                count +=1
                cur = cur.next
            return count

    def travel(self):
        if self.__head == None:
            return
        else:
            cur = self.__head
            while cur.next !=self.__head:
                print(cur.elem,end="")
                cur = cur.next
            print(cur.elem)

    def add(self,item):
        node = SingleCircleNode(item)
        if self.__head == None:
            self.__head = node
            node.next = self.__head
        else:
            cur = self.__head
            while cur.next !=self.__head:
                cur = cur.next
            node.next = self.__head
            self.__head = node
            cur.next = self.__head

    def append(self,item):
        node = SingleCircleNode(item)
        if self.__head ==None:
            self.__head = node
            node.next = self.__head
        else:
            cur = self.__head
            while cur.next !=self.__head:
                cur =cur.next
            node.next = self.__head
            cur.next = node


    def insert(self,pos,item):
        node = SingleCircleNode(item)
        if pos <=0:
            self.add(item)
        elif pos >= self.length():
            self.append(item)
        else:
            count =1
            cur = self.__head
            while pos !=count:
                count +=1
                cur = cur.next
            node.next = cur.next
            cur.next = node

    def remove(self,item):
        """刪除一個節點"""
        # 若鏈表爲空,則直接返回
        if self.is_empty():
            return
        # 將cur指向頭節點
        cur = self.__head
        pre = None
        # 若頭節點的元素就是要查找的元素item
        if cur.elem == item:
            # 若是鏈表不止一個節點
            if cur.next != self.__head:
                # 先找到尾節點,將尾節點的next指向第二個節點
                while cur.next != self.__head:
                    cur = cur.next
                # cur指向了尾節點
                cur.next = self.__head.next
                self.__head = self.__head.next
            else:
                # 鏈表只有一個節點
                self.__head = None
        else:
            pre = self.__head
            # 第一個節點不是要刪除的
            while cur.next != self.__head:
                # 找到了要刪除的元素
                if cur.elem == item:
                    # 刪除
                    pre.next = cur.next
                    return
                else:
                    pre = cur
                    cur = cur.next
            # cur 指向尾節點
            if cur.elem == item:
                # 尾部刪除
                pre.next = cur.next

        # node = SingleCircleNode(item)
        # if self.__head == None:
        #     return
        # cur = self.__head
        # pre = None
        # while cur.next != self.__head:
        #     if cur.elem == node.elem:
        #         if pre is None:
        #             rear = self.__head
        #             while rear.next != self.__head:
        #                 rear = rear.next
        #             self.__head = cur.next
        #             rear.next = self.__head
        #         else:
        #             pre.next = cur.next
        #         break
        #     else:
        #         pre = cur
        #         cur = cur.next
        # if cur.elem == node.elem:
        #     #匹配只有一個元素且是第一個元素
        #     if pre is None:
        #         self.__head ==None
        #     #匹配最後一個元素
        #     else:
        #         pre.next = self.__head
        # else:
        #     return

        # else:
        #     cur = self.__head
        #     pre = None
        #     if cur.elem == node.elem:
        #         if cur.next == None:
        #             self.__head = None
        #         else:
        #             node.next = cur.next
        #             self.__head = node
        #     while cur.next != self.__head:
        #         if cur.elem == node.elem:
        #             pre.next = cur.next
        #         else:
        #             pre = cur
        #             cur = cur.next
        #         break
        #     if cur.elem == node.elem:
        #         pre.next = self.__head
        #     else:
        #         return

    def search(self,item):
        if self.__head ==None:
            return False
        else:
            cur = self.__head
            while cur.next != self.__head:
                if cur.elem == item:
                    return True
                else:
                    cur =cur.next
            if cur.next == item:
                return True
            else:
                return False

3 棧(stack)

也稱堆棧,是一種容器,可存入數據元素、訪問元素、刪除元素。因爲棧數據結構只容許在一端進行操做,於是按照後進先出(LIFO, Last In First Out)的原理運做。

class Stack(object):
    def __init__(self):
        self.items = []

    def is_empty(self):
        '''判斷棧是否爲空'''
        return self.items ==[]

    def size(self):
        '''返回棧的元素個數'''
        return len(self.items)

    def push(self,item):
        '''添加一個新的元素item到棧頂'''
        self.items.append(item)

    def pop(self):
        '''彈出棧頂元素'''
        return self.items.pop()

    def peek(self):
        '''返回棧頂元素'''
        return self.items[len(self.items)-1]

if __name__ == '__main__':
    s = Stack()
    s.push(1)
    s.push(2)
    print(s.pop())
    print(s.peek())

4 隊列(queue)

class Queue(object):
    def __init__(self):
        self.items = []

    def is_empty(self):
        '''判斷一個隊列是否爲空'''
        return self.items == []

    def size(self):
        '''返回隊列的大小'''
        return len(self.items)

    def enqueue(self,item):
        '''往隊列中添加一個item元素'''
        self.items.append(item)

    def dequeue(self):
        '''從隊列頭部刪除一個元素'''
        return self.items.pop(0)

4.1 雙端隊列

雙端隊列(deque,全名double-ended queue),是一種具備隊列和棧的性質的數據結構。

雙端隊列中的元素能夠從兩端彈出,其限定插入和刪除操做在表的兩端進行。雙端隊列能夠在隊列任意一端入隊和出隊。

class Deque(object):
    '''建立一個空的雙端隊列'''
    def __init__(self):
        self.items = []

    def is_empty(self):
        '''判斷雙端隊列是否爲空'''
        return self.items == []

    def size(self):
        '''返回隊列的大小'''
        return len(self.items)

    def add_front(self,item):
        '''從隊頭加入一個item元素'''
        self.items.insert(0,item)

    def add_rear(self,item):
        '''從隊尾加入一個item元素'''
        self.items.append(item)

    def remove_front(self):
        '''從隊頭刪除一個item元素'''
        return self.items.pop(0)

    def remove_rear(self):
        '''從隊尾刪除一個item元素'''
        return self.items.pop()

5 排序與算法

算法的穩定性:穩定性:穩定排序算法會讓本來有相等鍵值的紀錄維持相對次序。

5.1 冒泡排序(Bubble Sort)

冒泡排序算法以下:

  • 比較相鄰的元素。若是第一個比第二個大(升序),就交換他們兩個。
  • 對每一對相鄰元素做一樣的工做,從開始第一對到結尾的最後一對。這步作完後,最後的元素會是最大的數。
  • 針對全部的元素重複以上的步驟,除了最後一個。
  • 持續每次對愈來愈少的元素重複上面的步驟,直到沒有任何一對數字須要比較。

 時間複雜度:

  • 最優時間複雜度:O(n) (表示遍歷一次發現沒有任何能夠交換的元素,排序結束。)
  • 最壞時間複雜度:O(n2)
  • 穩定性:穩定
def BubbleSort(alist):

    n = len(alist)
count =0
for j in range(n-1): for i in range(n-1-j): if alist[i] > alist[i+1]: alist[i],alist[i+1] = alist[i+1],alist[i]
count +=1
if count ==0
return
if __name__ == '__main__': alist = [7,2,5,7,1,9,0,3,4] BubbleSort(alist) print(alist)

5.2 選擇排序(Selection sort)

  • 在未排序序列中找到最小(大)元素,存放到排序序列的起始位置
  • 再從剩餘未排序元素中繼續尋找最小(大)元素,放到已排序序列的末尾
  • 以此類推,直到全部元素均排序完畢

時間複雜度:

  • 最優時間複雜度:O(n2)
  • 最壞時間複雜度:O(n2)
  • 穩定性:不穩定(考慮升序每次選擇最大的狀況)
def SelectionSort(alist):

    n = len(alist)
    for j in range(n-1):
        min_index = j
        for i in range(j+1,n):
            if alist[min_index] > alist[i]:
                min_index=i
        alist[min_index],alist[j] = alist[j],alist[min_index]

if __name__ == '__main__':
    alist = [7,2,5,7,1,9,0,3,4]
    SelectionSort(alist)
    print(alist)

5.3 插入排序(Insertion Sort)

經過構建有序序列,對於未排序數據,在已排序序列中從後向前掃描,找到相應位置並插入。在從後向前掃描過程當中,須要反覆把已排序元素逐步向後挪位,爲最新元素提供插入空間。 

時間複雜度:

  • 最優時間複雜度:O(n) (升序排列,序列已經處於升序狀態)
  • 最壞時間複雜度:O(n2)
  • 穩定性:穩定
def InsertionSort(alist):
    n = len(alist)
    for i in range(n):
        while i>0:
            if alist[i] < alist[i-1]:
                alist[i],alist[i-1]=alist[i-1],alist[i]
            i -=1

if __name__ == '__main__':
    alist = [7,2,5,7,1,9,0,3,4]
    InsertionSort(alist)
    print(alist)

5.4 希爾排序(Shell Sort)

也稱縮小增量排序,是直接插入排序算法的一種更高效的改進版本。

時間複雜度:

  • 最優時間複雜度:根據步長序列的不一樣而不一樣
  • 最壞時間複雜度:O(n2)
  • 穩定想:不穩定
def ShellSort(alist):

    n = len(alist)
    gap = n//2
    while gap >0:
        for i in range(gap,n):
            while i>0:
                if alist[i] < alist[i-gap]:
                    alist[i],alist[i-gap]= alist[i-gap],alist[i]
                i -=gap
        gap = gap//2

if __name__ == '__main__':
    alist = [7,2,5,7,1,9,0,3,4]
    ShellSort(alist)
    print(alist)

5.5 快速排序(Quick Sort)

也稱劃分交換排序(partition-exchange sort)

快速排序步驟爲:

  1. 從數列中挑出一個元素,稱爲"基準"(pivot);
  2. 從新排序數列,全部元素比基準值小的擺放在基準前面,全部元素比基準值大的擺在基準的後面(相同的數能夠到任一邊)。在這個分區結束以後,該基準就處於數列的中間位置。這個稱爲分區(partition)操做;
  3. 遞歸地(recursive)把小於基準值元素的子數列和大於基準值元素的子數列排序,遞歸的最底部情形,是數列的大小是零或一。

時間複雜度:

  • 最優時間複雜度:O(nlogn)
  • 最壞時間複雜度:O(n2)
  • 穩定性:不穩定
def QuickSort(alist,first,last):

    if first >= last:
        return
    mid = alist[first]
    low = first
    high = last
    while low<high:
        while low<high and alist[high]>=mid:
            high -=1
        alist[high],alist[low]=alist[low],alist[high]
        while low <high and alist[low]<mid:
            low +=1
        alist[low],alist[high]=alist[high],alist[low]
    alist[low]=mid
    QuickSort(alist,first,low-1)
    QuickSort(alist,low+1,last)

if __name__ == '__main__':
    alist = [7,2,5,7,1,9,0,3,4]
    QuickSort(alist,0,len(alist)-1)
    print(alist)

5.6 歸併排序

歸併排序的思想就是先遞歸分解數組,再合併數組。

將數組分解最小以後,比較兩個數組的最前面的數,誰小就先取誰,取了後相應的指針就日後移一位。而後再比較,直至一個數組爲空,最後把另外一個數組的剩餘部分複製過來便可。

時間複雜度:

  • 最優時間複雜度:O(nlogn)
  • 最壞時間複雜度:O(nlogn)
  • 穩定性:穩定
def MergeSort(alist):

    n = len(alist)
    if n <=1:
        return alist
    mid = n//2
    left_list = MergeSort(alist[:mid])
    right_list = MergeSort(alist[mid:])
    left_point,right_point = 0,0
    result = []
    while left_point<len(left_list) and right_point<len(right_list):
        if left_list[left_point] <= right_list[right_point]:
            result.append(left_list[left_point])
            left_point +=1
        else:
            result.append(right_list[right_point])
            right_point+=1
    #將循環剩下的的元素添加到列表的最後
    result += left_list[left_point:]
    result += right_list[right_point:]
    return result

if __name__ == '__main__':
    alist = [7,2,5,7,1,9,0,3,4]
    l = MergeSort(alist)
    print(l)

5.7 算法效率比較

5.8 搜索

搜索的幾種常見方法:順序查找、二分法查找、二叉樹查找、哈希查找

二分查找:做用於有序的線性表。

時間複雜度:

  • 最優時間複雜度:O(1)
  • 最壞時間複雜度:O(logn)
def BinarySearch(alist,item):

    if len(alist) == 0:
        return False
    else:
        mid = len(alist)//2
        if alist[mid] == item:
            return True
        elif alist[mid] > item:
            return  BinarySearch(alist[:mid-1],item)
        else:
            return  BinarySearch(alist[mid+1:],item)

if __name__ =='__main__':

    print(BinarySearch([4,6,7,8],4))

6 樹與樹的算法

樹的概念:樹(tree)是一種抽象數據類型(ADT)或是實做這種抽象數據類型的數據結構。

特色:

  • 每一個節點有零個或多個子節點;
  • 沒有父節點的節點稱爲根節點;
  • 每個非根節點有且只有一個父節點;
  • 除了根節點外,每一個子節點能夠分爲多個不相交的子樹。

術語:

  • 節點的度:一個節點含有的子樹的個數稱爲該節點的度;
  • 樹的度:一棵樹中,最大的節點的度稱爲樹的度;
  • 葉節點或終端節點:度爲零的節點;
  • 父親節點或父節點:若一個節點含有子節點,則這個節點稱爲其子節點的父節點;
  • 孩子節點或子節點:一個節點含有的子樹的根節點稱爲該節點的子節點;
  • 兄弟節點:具備相同父節點的節點互稱爲兄弟節點;
  • 節點的層次:從根開始定義起,根爲第1層,根的子節點爲第2層,以此類推;
  • 樹的高度或深度:樹中節點的最大層次;
  • 堂兄弟節點:父節點在同一層的節點互爲堂兄弟;
  • 節點的祖先:從根到該節點所經分支上的全部節點;
  • 子孫:以某節點爲根的子樹中任一節點都稱爲該節點的子孫。
  • 森林:由m(m>=0)棵互不相交的樹的集合稱爲森林。

種類:

  • 無序樹:樹中任意節點的子節點之間沒有順序關係,這種樹稱爲無序樹,也稱爲自由樹;
  • 有序樹:樹中任意節點的子節點之間有順序關係,這種樹稱爲有序樹;
    • 二叉樹:每一個節點最多含有兩個子樹的樹稱爲二叉樹;
      • 徹底二叉樹:對於一顆二叉樹,假設其深度爲d(d>1)。除了第d層外,其它各層的節點數目均已達最大值,且第d層全部節點從左向右連續地緊密排列,這樣的二叉樹被稱爲徹底二叉樹,其中滿二叉樹的定義是全部葉節點都在最底層的徹底二叉樹;
      • 平衡二叉樹(AVL樹):當且僅當任何節點的兩棵子樹的高度差不大於1的二叉樹;
      • 排序二叉樹(二叉查找樹(英語:Binary Search Tree),也稱二叉搜索樹、有序二叉樹);
    • 霍夫曼樹(用於信息編碼):帶權路徑最短的二叉樹稱爲哈夫曼樹或最優二叉樹;
    • B樹:一種對讀寫操做進行優化的自平衡的二叉查找樹,可以保持數據有序,擁有多餘兩個子樹。

存儲:順序存儲和鏈式存儲(經過lchild和rchild指針)。

class Node(object):

    def __init__(self,item,lchild=None,rchild=None):
        self.root = item
        self.lchild = lchild
        self.rchild = rchild

class Tree(object):

    def __init__(self,root=None):
        self.root = root

    def add(self,elem):
        node = Node(elem)
        if self.root ==Node:
            self.root = node
        #若是根節點不爲空
        else:
            queue = []
            queue.append(self.root)
            while queue:
                cur = queue.pop(0)
                if cur.lchild == Node:
                    cur.lchild ==node
                    return 
                elif cur.rchild ==None:
                    cur.rchild ==node
                    return 
                else:
                    queue.append(cur.lchild)
                    queue.append(cur.rchild)

6.1 二叉樹

二叉樹是每一個節點最多有兩個子樹的樹結構。一般子樹被稱做「左子樹」(left subtree)和「右子樹」(right subtree)。

性質:

  • 在二叉樹的第i層上至多有2^(i-1)個結點(i>0)
  • 深度爲k的二叉樹至多有2^k - 1個結點(k>0)
  • 對於任意一棵二叉樹,若是其葉結點數爲N0,而度數爲2的結點總數爲N2,則N0=N2+1;
  • 具備n個結點的徹底二叉樹的深度必爲 log2(n+1)
  • 對徹底二叉樹,若從上至下、從左至右編號,則編號爲i 的結點,其左孩子編號必爲2i,其右孩子編號必爲2i+1;其雙親的編號必爲i/2(i=1 時爲根除外)

6.2 二叉樹的遍歷

深度優先遍歷和廣度優先遍歷,深度優先通常用遞歸,廣度優先通常用隊列。

6.2.1 廣度遍歷(層次遍歷)

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)

6.2.2 先序遍歷歷(preorder)

根節點->左子樹->右子樹

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

6.2.3 中序遍歷(inorder)

左子樹->根節點->右子樹

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

6.2.4 後序遍歷(postorder)

左子樹->右子樹->根節點

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

ps.有中序遍歷和先序遍歷或後序遍歷能夠肯定一棵樹。

相關文章
相關標籤/搜索