-
算法總結
01、算法分類
- 比較類排序:通過比較來決定元素間的相對次序,由於其時間複雜度不能突破O(nlogn),因此也稱爲非線性時間比較類排序。
- 非比較類排序:不通過比較來決定元素間的相對次序,它可以突破基於比較排序的時間下界,以線性時間運行,因此也稱爲線性時間非比較類排序。
- 內部排序:所有排序操作都在內存中完成。
- 外部排序:由於數據太大,因此把數據放在磁盤中,而排序通過磁盤和內存的數據傳輸才能進行。
一、冒泡排序
思想:兩兩比較相鄰記錄的關鍵字,如果反序則交換,直到沒有反序記錄爲止。
時間複雜度O(n^2)
def sortDate(self, num):
length = len(num)
for i in range(0, length):
for j in range(0, length - i - 1):
if num[j] > num[j+1]:
num[j], num[j+1] = num[j+1], num[j]
return num
冒泡排序改進算法, 設置flag,當一輪比較中未發生交換動作,則說明後面的元素其實已經有序排列了。 對於比較規整的元素集合,可提高一定的排序效率。
def sortDate(self, num):
length = len(num)
i = 0
flag = True
while i < length and flag:
flag = False
for j in range(0, length - i - 1):
if num[j] > num[j + 1]:
num[j], num[j+1] = num[j+1], num[j]
flag = True
i += 1
return num
二、快速排序
思想:通過一趟排序將待排記錄分割成獨立的兩部分,其中一部分記錄的關鍵字均比另一部分記錄的關鍵字小,然後分別對這兩部分繼續進行排序,以達到整個記錄集合的排序目的。時間複雜度O(nlog(n))。
一趟快速排序的算法是:
1)設置兩個變量i、j,排序開始的時候:i=0,j=N-1;
2)以第一個數組元素作爲關鍵數據,賦值給key,即key=A[0];
3)從j開始向前搜索,即由後開始向前搜索(j--),找到第一個小於key的值A[j],將A[j]和A[i]互換;
4)從i開始向後搜索,即由前開始向後搜索(i++),找到第一個大於key的A[i],將A[i]和A[j]互換;
5)重複第3、4步,直到i=j; (3,4步中,沒找到符合條件的值,即3中A[j]不小於key,4中A[i]不大於key的時候改變j、i的值,使得j=j-1,i=i+1,直至找到爲止。找到符合條件的值,進行交換的時候i, j指針位置不變。另外,i==j這一過程一定正好是i+或j-完成的時候,此時令循環結束)。
# -*- coding: utf-8 -*-
def partion(nums, left, right):
key = nums[left]
while left < right:
while left < right and nums[right] >= key:
right -= 1
if left < right:
nums[left], nums[right] = nums[right], nums[left]
else:
break
while left < right and nums[left] < key:
left += 1
if left < right:
nums[left], nums[right] = nums[right], nums[left]
else:
break
return right
def quick_sort_standord(nums, left, right):
if left < right:
key_index = partion(nums, left, right)
quick_sort_standord(nums, left, key_index - 1)
quick_sort_standord(nums, key_index + 1, right)
三、簡單選擇排序
思想:通過n-i次關鍵字之間的比較,從n-i+1個記錄中選出關鍵字最小的記錄,並和第i(1<=i<=n)個記錄進行交換。
def selectSort(nums):
for i in range(0, len(nums)):
minIndex = i
for j in range(i+1, len(nums)):
if nums[j] < nums[minIndex]:
minIndex = j
if nums[i] != nums[minIndex]:
nums[i], nums[minIndex] = nums[minIndex], nums[i]
四、插入排序(Insertion-Sort)
思想:插入排序的算法描述是一種簡單直觀的排序算法。它的工作原理是通過構建有序序列,對於未排序數據,在已排序序列中從後向前掃描,找到相應位置並插入。
def insertSort(nums):
for i in range(1, len(nums)):
fg = i
tp = nums[i]
while fg > 0:
if nums[fg-1] < tp:
break
else:
nums[fg] = nums[fg-1]
fg -= 1
nums[fg] = tp
return nums
五、希爾排序
先將整個待排序的記錄序列分割成爲若干子序列分別進行直接插入排序,具體算法描述:
- 選擇一個增量序列t1,t2,…,tk,其中ti>tj,tk=1;
- 按增量序列個數k,對序列進行k 趟排序;
- 每趟排序,根據對應的增量ti,將待排序列分割成若干長度爲m 的子序列,分別對各子表進行直接插入排序。僅增量因子爲1 時,整個序列作爲一個表來處理,表長度即爲整個序列的長度。
def shellSort(nums):
step = len(nums)/2
while step > 0:
for i in range(step, len(nums)):
while i >= step and nums[i] < nums[i - step]:
nums[i],nums[i-step] = nums[i-step], nums[i]
i -= step
step = step / 2
return nums
六、堆排序
堆排序思想:建立大根堆,把根節點和最後一個葉節點交換得到最後一個元素有序,然後調整剩餘序列爲大根堆,把根節點和倒數第二個元素交換得到最後兩個元素有序,依次循環進行直到整個序列有序。
-*- coding: utf-8 -*-
from collections import deque
def heap_adjust(L, start, end):
#調整子樹爲大根堆
i = start
j = 2 * i
temp = L[start]
while j <= end:
if j < end and L[j] < L[j+1]:# 先比較兩個子節點大小,選擇最大的
j += 1
if L[j] > temp:
L[i] = L[j]
i = j
j = 2 * i
else:
break
L[i ] = temp
def heap_sort(L):
length = len(L) - 1
start = length / 2
for i in range(start):
#從length/2(最後一個父節點)向前一依次調整子樹爲大根堆,得到最終序列爲大根堆
heap_adjust(L, start - i, length)
for i in range(length - 1):
#把堆頂元素和堆尾元素交換,然後把剩下的元素調整爲大根堆
L[1], L[length - i] = L[length - i], L[1]
heap_adjust(L, 1, length - i - 1)
return [L[i] for i in range(1,len(L))]
L = deque([5, 9, 30, 8, 6, 10, 2, 4, 70])
L.appendleft(0)
print heap_sort(L)
七、歸併排序
歸併排序(MERGE-SORT)是建立在歸併操作上的一種有效的排序算法,該算法是採用分治法(Divide and Conquer)的一個非常典型的應用。將已有序的子序列合併,得到完全有序的序列;即先使每個子序列有序,再使子序列段間有序。若將兩個有序表合併成一個有序表,稱爲二路歸併。
def merge(a, b):
#將兩個有序列表合併成一個列表返回
c = []
i = j = 0
while i < len(a) and j < len(b):
if a[i] < b[j]:
c.append(a[i])
i += 1
else:
c.append(b[j])
j += 1
if i == len(a):
c += b[j:]
else:
c += a[i:]
return c
def merge_sort(nums):
if len(nums) <= 1:
return nums
mid = len(nums) / 2
left = merge_sort(nums[:mid])
right = merge_sort(nums[mid:])
return merge(left, right)