樹的遍歷和堆排序


1、二叉樹的遍歷

  遍歷,迭代所有的元素以便

  樹的遍歷:對數中所有元素不重復放入訪問一遍,也成為掃描(非線性變成線性結構

  遍歷方式:    

    廣度優先遍歷:

       層序遍歷

    深度優先遍歷:

        前序遍歷

       中序遍歷

       后序遍歷

    遍歷序列:將樹中所有元素遍歷一遍后,得到的勻速的序列,將層次結構轉換為了線性結構。

  2.1 層序遍歷:

    

      遍歷序列:ABCDEFGHI  

  2.2、深度優先遍歷:

     設樹的根結點為D, 左子樹為L,右子樹為R, 且要求L一定在R之前,則:

      前序遍歷:也叫先序遍歷,先根遍歷:DLR

      中序遍歷:中根遍歷:LDR

      后序遍歷:后根遍歷:LRD

    2.2.1:前序遍歷:

        遍歷序列: A BDGH CEIF

    2.2.2 中序遍歷:

          遍歷序列:

              左圖:GDHB A IECF      I 是左子樹

              右圖:GDHB A EICF  I 是右子樹

    2.2.3:后序遍歷:

   

          遍歷序列:GHDB IEFC A

                     

2、堆排序 Heap Sort

  堆Heap

    堆是一個完全二叉樹      

    每個非葉子結點都要大於或者等於其左右孩子結點的值,稱為大頂堆

    每個非葉子結點都要小於或者等於其左右孩子結點的值,稱為小頂堆

    根結點一定是大頂堆中的最大值,一定是小頂堆中的最小值。

  大頂堆:

    完全二叉樹的每一個非葉子結點都要大於或者等於其左右孩子結點的值稱為大頂堆

    根結點一定是大頂堆中的最大值

 

  小頂堆:

   1步:構建完全二叉樹:

      待排序數字為30,20,80,40,50,10,60,70,90

      構建一個完全二叉樹存放數據,並根據性質5(2*i+ 1)對元素編號,放入順序的數據結構總

      構造一個列表為:[0, 30,20,80,40,50,10,60,70,90] #補了一個零,主要是30對應的i 從1 開始!

 

  2步:構建大頂堆------核心算法

      度數為2的結點A ,如果他的左右孩子結點的最大值比他大的,將這個最大值和該結點交換

      度數為1 的結點A,如果他的左孩子的值大於它,則交換

      如果結點A 被交換到新的文職,還要和其孩子結點重復上面的過程。

    起點結點的選擇:

      從完全二叉樹的最后一個節點的額雙親結點開始,即最后一層的最右邊葉子節點的父結點開始

      結點數為n,則其實結點的編號為 n//2

    下一個節點的選擇:

      從其實結點開始想左找其同層結點,到頭后再從上一層的最右邊結點開始繼續向左諸葛查找,直至根結點

    大頂堆的目標:

      確保每個結點的都比左右結點的值大

  3、排序:

    將大頂堆根結點這個最大值和最后一個葉子結點交換, 那么最后一個葉子結點就是最大值,將這個葉子結點排除在待排序結點之外。

    從根結點開始(新的根結點),重新調整為大頂堆后,重復上一步。

  

    堆頂和最后一個節點交換,並排除最后一個節點:

 

 

 代碼實現:

 1 import math
 2 
 3 def print_tree(origin):
 4     index = 2 ** h - 1  # 滿樹的總節點數 15
 5     for i in range(1,h+1):
 6         times = 2 ** (i - 1)
 7         for j in range(times - 1, times * 2 - 1):
 8             if j >= length: break
 9             # print(index)
10             print('{:^{}}'.format(origin[1:][j], index*2),end='  '*1)
11         print()
12         index //=  2
13 
14 # origin = [30, 20, 80, 40, 50, 10, 60, 70, 90]
15 origin = [0,30, 20, 80, 40, 50, 10, 60, 70, 90]
16 length = len(origin)-1  # 節點 9
17 h = math.ceil(math.log(length, 2))  # >3  所以深度為4
18 # print_tree(origin)
19 
20 # 只調了一個元素:90
21 def heap_adjust(origin, length,i):
22     while 2 * i <= length:
23         l_child = 2 * i
24         max_child = l_child
25         if  length > l_child and origin[l_child + 1] > origin[l_child]:
26             max_child = l_child + 1
27 
28         if origin[max_child] > origin[i]:
29             origin[i], origin[max_child] = origin[max_child], origin[i]
30             i = max_child
31         else:
32             break
33     return origin
34 # heap_adjust(origin, length, i = length // 2)
35 # print(origin)
36 # print_tree(origin)
37 
38 # 構建大頂堆
39 def max_heap(length, origin):
40     for i in range(length//2, 0, -1):
41         heap_adjust(origin, length, i)
42         print("********************************")
43         print(origin)
44         print_tree(origin)
45     return origin
46 print_tree(max_heap(length, origin))
47 
48 
49 # 排序:
50 def sort(length, origin):
51     while length > 1 :
52         origin[1],origin[length] = origin[length], origin[1]
53         length  -=  1
54         heap_adjust(origin,length, 1) 
55         # 因為當大頂堆構建完后,事實上,次大值,就在第二層,所以,每次只在一層二層進行比較獲取大頂堆
56     return origin
57 
58 print(sort(length, origin))
代碼實現堆排序

結果截圖:

改進:如果最后剩兩個元素的時候,如果后一個節點比堆頂大,就不用再調整了!!!

 

 總結:

  是利用堆性質的一種選擇排序,在堆頂選出最大值或者最小值

  時間復雜度:

    堆排序的時間復雜度O(nlogn)

    由於堆排序隊員是記錄的排序的狀態並不敏感,因此它無論是最好,最壞,和平均時間復雜度均為O(nlongn))

    

 

   從圖中可以看出比之前的交換,插入排序要好的多的多的

   空間復雜度:將原序列 加了一個0,中間加了一個變量調了一下,新的序列

        只使用了一個交換空間,空間復雜度就是O(1) hash()也是O(1)

         不穩定的排序算法

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM