2020年10月27日 星期二

Algorithm_Sort_Heap srot

Algorithm_Sort_Heap srot

tags: Algorithms Sort python
def heapify(input_array, index, bound):
    """將資料結構化為heap
    parameters:
        input_array: 輸入的未排序陣列
        index: 要排序的root
        bound: 比較邊界,如果某個root的左、右索引已超過陣列長度就不處理
        
    假設,root的index=n,那其節點索引為
        root: n
        root_left_node: 2n + 1
        root_right_node: 2n + 2
        
    
    舉例來說,[0, 1, 2, 3, 4, 5, 6]
          0
        1   2
       3 4 5 6
    0為root,左邊節點為1,右邊則為2
    1為root,左邊節點為3,右邊則為4
    
    heap sort的一半是最後的節點,因此只會比較到陣列一半取上高斯
    其餘皆會是最終節點,不需要再比較,所以3456本身是不需要比較的
    我們會從2開始比,也就是7/2 = 3 - 1 = 2(因為python的索引初始值為0)
        
    要記得,python的索引是由0開始
    
    root永遠是三個節點中最大的(或最小的),但節點不考慮大小      
      5            5
    1   2        2   1 左邊兩種情況都可以
    """
    # 先預設最大值為root index
    largest_idx = index
    # print(f'init_array: {input_array}')
    # print(f'init_larget_idx: {largest_idx}, value: {input_array[largest_idx]}')
    left_idx = index * 2 + 1
    # print(f'left_idx: {left_idx}')
    right_idx = index * 2 + 2 
    # print(f'right_idx: {right_idx}')
    # 下面的比較,因為我們只關心root是最大的,因此不需要再比較左右兩邊
    # 注意到與陣列長度的比較條件必需在前面,不然會引發索引異常
    if  left_idx < bound  and input_array[largest_idx] < input_array[left_idx]:
        largest_idx = left_idx
        # print(f'l_larget_idx: {largest_idx}, value: {input_array[largest_idx]}')
    
    if right_idx < bound  and input_array[largest_idx] < input_array[right_idx]:        
        largest_idx = right_idx
        # print(f'r_larget_idx: {largest_idx}, value: {input_array[largest_idx]}')
    
    # 比較之後,如果最大值的異動,那就調整array的順序
    if largest_idx != index:        
        input_array[index], input_array[largest_idx] = input_array[largest_idx], input_array[index]
        # print(f'new array: {input_array}')
        # 遞迴處理heapify
        heapify(input_array, largest_idx, bound)
        
 def heap_sort(input_array):
    """heap sort"""
    array_size = len(input_array)
    # heap sort會從底層開始排序上來
    # 而且並不會所有的元素都排序,因為n//2 + 1之後的節點都是最終節點
    # 只有n//2 + 1之前是root,因此只做這邊的迴圈比較
    # 這邊只是做heap的結構
    for i in range(array_size // 2 - 1, -1, -1):        
        heapify(input_array, i, array_size)
    
    # 處理排序
    # 我們知道,經過heap過的結構,最大的一定是在最上面(假設是max heap)
    # 因此,實作上會將root的部份跟最後的結點做交換,再將n-1做一次heap
    for i in range(array_size - 1, 0, -1):
        # 每次heap之後都做頭尾的交換
        # print(f'heap_sort: {input_array}')
        input_array[0], input_array[i] = input_array[i], input_array[0]
        # 特別注意到,每一次迭代都會減少一個,因此這邊給的是迴圈中的i,而不是array_size
        heapify(input_array, 0, i)
    return input_array   

下面給出五個資料集在不同資料量下的結果,其中

  • l1: 已經排序好的,由小到大
  • l2: 已經排序好的,但是逆排序,由大到小
  • l3: 亂數生成
  • l4: 亂數生成
  • l5: 亂數生成
Heap Sort 20000 40000 60000 80000 100000
l1 416 ms 606 ms 864 ms 1.23 s 1.51 s
l2 255 ms 721 ms 876 ms 1.15 s 1.64 s
l3 265 ms 603 ms 923 ms 1.23 s 1.8 s
l4 297 ms 562 ms 946 m 1.16 s 1.59 s
l5 279 ms 553 ms 966 ms 1.22 s 1.66 s

沒有留言:

張貼留言