<資料結構>常見的資料結構和演算法
阿新 • • 發佈:2020-07-28
001.二分查詢
# 二分查詢 ''' 1.end問題 2.44對應的end<start 找不到情況 3.返回值遞迴的情況 4,611,aim太大的情況 ''' l = [2, 3, 5, 10, 15, 16, 18, 22, 26, 30, 32, 35, 41, 42, 43, 55, 56, 66, 67, 69, 72, 76, 82, 83, 88] def find(l, aim, start=0, end=None): end = len(l) if end is None else end Mid_index = (end - start) // 2 + start if aim <= l[len(l) - 1]: if end >= start: if l[Mid_index] > aim: return find(l, aim, start=start, end=Mid_index - 1) elif l[Mid_index] < aim: return find(l, aim, start=Mid_index + 1, end=end) elif l[Mid_index] == aim: return Mid_index else: return '找不到!' else: return '比列表最大數都大,找不到!' l = [2, 3, 5, 10, 15, 16, 18, 22, 26, 30, 32, 35, 41, 42, 43, 55, 56, 66, 67, 69, 72, 76, 82, 83, 88] ret = find(l, 411) ret1 = find(l, 44) ret2 = find(l, 66) ret3 = find(l, 67) print(ret, ret1, ret2, ret3) #比列表最大數都大,找不到! 找不到! 17 18
002.氣泡排序
import random import cProfile ''' 氣泡排序:比較相鄰元素,順序錯誤就交換順序 最優時間複雜度:O(n) (表示遍歷一次發現沒有任何可以交換的元素,排序結束。) 最壞時間複雜度:O(n2) 2次迴圈 穩定性:穩定 ''' # 氣泡排序1 def bubble_sort1(nums): for i in range(len(nums) - 1): for j in range(len(nums) - 1 - i): if nums[j] > nums[j + 1]: nums[j], nums[j + 1] = nums[j + 1], nums[j] return nums # 氣泡排序2 def bubble_sort2(alist): for j in range(len(alist) - 1, 0, -1): # j表示每次遍歷需要比較的次數,是逐漸減小的 for i in range(j): if alist[i] > alist[i + 1]: alist[i], alist[i + 1] = alist[i + 1], alist[i] return nums nums = [random.randint(0, 10000) for i in range(10000)] print(bubble_sort1(nums)) print(bubble_sort2(nums)) cProfile.run('bubble_sort1(nums)') # 4.881 cProfile.run('bubble_sort2(nums)') # 4.919
003.選擇排序---稍微減少執行時間,是氣泡排序的改進版
import random import cProfile ''' 選擇排序:選擇最小的,以此類推 最優時間複雜度:O(n2) 最壞時間複雜度:O(n2) 穩定性:不穩定(考慮升序每次選擇最大的情況) ''' # 選擇排序1 def select_sort(nums): for i in range(len(nums) - 1): for j in range(i + 1, len(nums)): if nums[i] > nums[j]: # max = nums[i] # nums[i] = nums[j] # nums[j] = max # python有更好的寫法 nums[i], nums[j] = nums[j], nums[i] return nums # 選擇排序2 def selection_sort(alist): n = len(alist) # 需要進行n-1次選擇操作 for i in range(n - 1): # 記錄最小位置 min_index = i # 從i+1位置到末尾選擇出最小資料 for j in range(i + 1, n): if alist[j] < alist[min_index]: min_index = j # 如果選擇出的資料不在正確位置,進行交換 if min_index != i: alist[i], alist[min_index] = alist[min_index], alist[i] return nums nums = [random.randint(0, 10000) for i in range(10000)] print(select_sort(nums)) print(selection_sort(nums)) cProfile.run('select_sort(nums)') # 3.172 cProfile.run('selection_sort(nums)') # 3.298
004.插入排序
import random import cProfile ''' 插入排序:假設元素左側全部有序,找到自己的位置插入 最優時間複雜度:O(n) (升序排列,序列已經處於升序狀態) 最壞時間複雜度:O(n2) 穩定性:穩定 ''' def insert_sort(alist): # 從第二個位置,即下標為1的元素開始向前插入 for i in range(1, len(alist)): # 從第i個元素開始向前比較,如果小於前一個元素,交換位置 for j in range(i, 0, -1): if alist[j] < alist[j - 1]: alist[j], alist[j - 1] = alist[j - 1], alist[j] return nums nums = [random.randint(0, 10000) for i in range(10000)] print(insert_sort(nums)) cProfile.run('insert_sort(nums)') # 5.043
005.快速排序
''' 快速排序: 又稱劃分交換排序(partition-exchange sort), 通過一趟排序將要排序的資料分割成獨立的兩部分, 其中一部分的所有資料都比另外一部分的所有資料都要小, 然後再按此方法對這兩部分資料分別進行快速排序, 整個排序過程可以遞迴進行,以此達到整個資料變成有序序列。 1.從數列中挑出一個元素,稱為"基準"(pivot), 2.重新排序數列,所有元素比基準值小的擺放在基準前面,所有元素比基準值大的擺在基準的後面(相同的數可以到任一邊)。在這個分割槽結束之後,該基準就處於數列的中間位置。這個稱為分割槽(partition)操作。 3.遞迴地(recursive)把小於基準值元素的子數列和大於基準值元素的子數列排序。 最優時間複雜度:O(nlogn) 最壞時間複雜度:O(n2) 穩定性:不穩定 ''' import cProfile import random import time import sys sys.setrecursionlimit(10000) # 設定最大遞迴深度為3000 start_time = time.time() def quick_sort(alist, start, end): """快速排序""" # 遞迴的退出條件 if start >= end: return # 設定起始元素為要尋找位置的基準元素 mid = alist[start] # low為序列左邊的由左向右移動的遊標 low = start # high為序列右邊的由右向左移動的遊標 high = end while low < high: # 如果low與high未重合,high指向的元素不比基準元素小,則high向左移動 while low < high and alist[high] >= mid: high -= 1 # 將high指向的元素放到low的位置上 alist[low] = alist[high] # 如果low與high未重合,low指向的元素比基準元素小,則low向右移動 while low < high and alist[low] < mid: low += 1 # 將low指向的元素放到high的位置上 alist[high] = alist[low] # 退出迴圈後,low與high重合,此時所指位置為基準元素的正確位置 # 將基準元素放到該位置 alist[low] = mid # 對基準元素左邊的子序列進行快速排序 quick_sort(alist, start, low - 1) # 對基準元素右邊的子序列進行快速排序 quick_sort(alist, low + 1, end) return nums nums = [random.randint(0, 10000) for i in range(10000)] print(quick_sort(nums, 0, len(nums) - 1)) end_time = time.time() print(end_time - start_time) # 0.045 # 堆疊溢位 cProfile.run('quick_sort(nums, 0, len(nums) - 1)')
006.歸併排序
''' 歸併排序:分而治之,一分為二進行排序--我一直以為是快排(看我部落格的sorry了) 歸併排序的思想就是先遞迴分解陣列,再合併陣列。 最優時間複雜度:O(nlogn) 最壞時間複雜度:O(nlogn) 穩定性:穩定 ''' import cProfile import random def merge_sort(nums): if len(nums) <= 1: return nums s_nums = [] l_nums = [] # 小於nums[0]放左邊 for i in nums[1:]: if i < nums[0]: s_nums.append(i) else: # #大於nums[0]放右邊 l_nums.append(i) # nums[0:1]是列表[],nums[0]是int數字 # 連線左右列表加num[0:1] return merge_sort(s_nums) + nums[0:1] + merge_sort(l_nums) nums = [random.randint(0, 10000) for i in range(10000)] print(merge_sort(nums)) cProfile.run('merge_sort(nums)') # 0.045
007.桶排序
''' 桶排序:最快最簡單的排序 缺點:最佔記憶體 型別:分散式排序 ''' import cProfile import random def bucketSort(nums): #選出最大的數 max_num = max(nums) #建立一個元素全是0的列表,當桶 bucket = [0]*(max_num+1) #把所有元素放入桶中,即把對應元素個數加1 for i in nums: bucket[i] = bucket[i] + 1 sort_nums = [] #取出桶中的元素 for j in range(len(bucket)): if bucket[j] != 0 : for y in range(bucket[j]): sort_nums.append(j) return sort_nums nums = [random.randint(0,10000) for i in range(10000)] print(bucketSort(nums)) cProfile.run('bucketSort(nums)') # 0.005