排序算法
排序算法的稳定性:让原本相等的键值维持的纪录维持相对次序
冒泡排序(BUbble Sort)
从头往后走,每次比较相邻的两个数字,一次循环将最大(最小)的数字放在最后,经过n-1次冒泡完成排序。
冒泡:每次将最大的值往后移到相应的位置(第一次最大,第二次次大,依次往后)
#关键代码
for i in range(n-1):
flag = 0
for j in range(n-1-j):
if bubble[j] > bubble[j+1]:
bubble[j], bubble[j+1] = bubble[j+1], bubble[j]
flag = 1
if flag == 0: #该序列不需要进行排序
return bubble
时间复杂度:O(n2)
稳定性:稳定
选择排序
从未排序的序列中选择一个次小的让前面去放
#关键代码
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[j], alist[min_index] = alist[min_index], alist[j]
时间复杂度:O(n2)
稳定性:不稳定
插入算法
把后面序列的数字插入到前面序列合适的位置
#关键代码
for i in range(1, n):
while i > 0:
if alist[i] < alist[i-1]:
alist[i], alist[i-1] = alist[i-1], alist[i]
i -= 1
else:
break
时间复杂度:O(n2)
稳定性:稳定
希尔排序
对插入算法的改进。其基本思想是:先比较距离远的元素,而不是像简单交换排序算法那样先比较相邻的元素,这样可以快速减少大量的无序情况,从而减轻后续的工作。被比较的元素之间的距离逐步减少,直到减少为1,这时的排序变成了相邻元素的互换。
#关键代码实现
def shell_sort(alist):
"""希尔排序"""
n = len(alist)
gap = n//2
while gap > 0:
for j in range(gap, n):
i = j
while i > 0:
if alist[i] < alist[i-gap]:
alist[i], alist[i-gap] = alist[i-gap], alist[i]
i -= gap
else:
break
gap //= 2
最坏时间复杂度:O(n2)
稳定性:不稳定
快速排序
基本思想:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。
#关键代码
def quick_sort(alist, first, last):
if first == last:
return
mid_value = alist[0]
low = firsst
high = last
while low < high:
#high左移
while low < high and alist[high] >= mid_value:
high -= 1
alist[low] = alist[high]
while low < high and alist[low] < mid_value:
low += 1
alist[high] = alist[low]
#从循环退出,low==high
alist[low] = mid_value
#对low左边进行快速排序
quick_sort(alist, first, low-1)
#对low右边的列表进行快速排序
quick_sort(alist, low+1, last)
最优时间复杂度: O(nlogn) (经过多少次对半折分可以拆到1,nlog2n)
最坏时间复杂度:O(n2)
稳定性:不稳定
归并算法
基本思想:先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,即二路归并
#关键代码
def merge_sort(alist):
"""归并排序"""
n = len(alist)
if n <= 1
return alist
mid == n//2
# left采用归并排序后形成的有序的新的列表
left_li = merge_sort(alist[:mid])
# right采用归并排序后形成的有序的新的列表
right_li = merge_sort(alist[mid:])
left_pointer, right_pointer = 0, 0
result = []
while left_pointer < len(left_li) and right_pointer < len(right_li):
if left_li[left_pointer] <= right_li[right_pointer]:
result.append(left_li[left_pointer])
left_pointer += 1
elif:
result.append(right_li[right_pointer])
right_pointer += 1
result += left_li[left_pointer:]
result += right_li[right_pointer:]
return result
最优时间复杂度:O(nlogn) (理解:纵向是logn级序列拆分,横向进行n次比较)
最坏时间复杂度:O(nlogn)
稳定性:稳定
时间上是最小的,但是空间上,需要额外的开销,前面的算法是在原有的列表上进行排序的。
搜索算法——二分查找
二分查找,又称为折半查找。查找对象:有序的顺序表。
def binary_search(alist, item):
"""二分查找"""
n = len(alist)
if n > 0:
mid = n//2
if alist[mid] == item:
return True
elif item < alist[mid]:
return binary_search(alist[:mid], item)
else:
return binary_search(alist[mid:], item)
return False
# 非递归
def binary_search(alist, item):
"""二分查找,非递归"""
n = len(alist)
first = 0
last = n-1
while first <= last:
mid = (first + last)//2
if alist[mid] == item:
return True
elif alist[mid] > item:
last = mid -1
else:
first = mid + 1
return False
最坏时间复杂度:O(logn) (普通遍历查找时间复杂度是O(n))
最优时间复杂度:O(1)