排序算法
冒泡排序(Bubble Sort)
- 比较相邻的元素。若第一个比第二个大(升序),就交换他们。
- 对每一对相邻元素作同样的工作,从开始第一对到最后一对。该步完成后,最后的元素将是最大的数。
- 针对所有元素重复以上步骤,除了最后一个。
- 持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。
def bubble_sort(alist):
n = len(alist)
for k in range(n-1):
count = 0
for i in range(n-1-k):
if alist[i] > alist[i+1]:
alist[i], alist[i+1] = alist[i+1], alist[i]
count += 1
#判断是否发生交换,若为最优序列则退出
if count == 0:
break
alist = [7,5,9,3,22,4,1]
bubble_sort(alist)
print(alist)
时间复杂度: 最优O(n),最劣O(n2),算法稳定
选择排序(Selection Sort)
这是一种简单直观的排序算法。在未排序序列中找到最大(小)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最大(小)元素,然后放到已排序序列的末尾。依次类推,直至所有元素均排序完毕。
def selection_sort(alist):
n = len(alist)
for i in range(n-1):
#记录当前位置为最小值
min_index = i
for j in range(i+1, n):
if alist[min_index] > alist[j]:
min_index = j
#若当前位置不是最小值,则进行交换
if min_index != i:
alist[i], alist[min_index] = alist[min_index], alist[i]
alist = [7,5,9,3,22,4,1]
selection_sort(alist)
print(alist)
时间复杂度: 最优O(n2),最劣O(n2),算法不稳定
插入排序(Intertion Sort)
通过构建有序序列,对于未排序序列,在已排序序列中从后往前扫描,找到相应位置并插入。插入排序在实现上,在从后向前扫描过程中,需要反复把已排序元素逐步向后挪位,为最新元素提供插入空间。
def intertion_sort(alist):
n = len(alist)
for j in range(1,n):
i = j
while i>0:
if alist[i] < alist[i-1]:
alist[i],alist[i-1] = alist[i-1],alist[i]
else:
break
i -= 1
alist = [7,5,9,3,22,4,1]
intertion_sort(alist)
print(alist)
时间复杂度: 最优O(n),最劣O(n2),算法稳定
快速排序(Quicksort)
步骤:
- 设置两个变量low, high, 排序开始时:low = 0, high = N-1;
- 以第一个列表元素作为基准元素,赋值给 mid, 即 mid = A[0];
- 从 high 开始向前搜索,即由后向前搜索(high–),找到第一个小于 mid 的值A[high], 将 A[high] 和 A[low] 的值交换;
- 从 low 开始向后搜索,即由前开始向后搜索(low++),找到第一个大于 mid 的 A[low],将 A[low]和 A[high]的值交换;
- 重复第3、4步,直到 low = high。
def quicksort(alist, start, end):
#递归的退出条件
if start >= end:
return
mid = alist[start]
low = start
high = end
while low < high:
while low < high and alist[high] >= mid:
high -= 1
alist[low] = alist[high]
while low < high and alist[low] < mid:
low += 1
alist[high] = alist[low]
alist[low] = mid
quicksort(alist, start, low-1)
quicksort(alist, low+1, end)
alist = [7,5,9,3,22,4,1]
quicksort(alist, 0 ,len(alist)-1)
print(alist)
时间复杂度: 最优O(nlogn),最劣O(n2),算法不稳定
归并排序(Mergesort)
归并排序的思想就是先递归分解数组,再合并数组。将数组分解最小之后,然后合并两个有序数组,基本思路是比较两个数组的最前面的数,谁小就先取谁,取了后相应的指针就往后移一位。然后再比较, 直至一个数组为空,最后把另一个数组的剩余部分复制过来即可。
def merge_sort(alist):
n = len(alist)
#递归出口:若分解数组至最小,则退出
if n <= 1:
return alist
#二分数组
mid = n//2
#递归分解前次二分后的前后数组
left = merge_sort(alist[:mid])
right = merge_sort(alist[mid:])
#合并操作,将两个有序数组left[]和right[]合并为一个有序大数组
result = []
l, r = 0, 0
while l < len(left) and r < len(right):
if left[l] < right[r]:
result.append(left[l])
l += 1
else:
result.append(right[r])
r += 1
#退出循环,将剩余列表中元素添加至result中
result += left[l:]
result += right[r:]
return result
alist = [54,26,93,17,77,31,44,55]
stored_list = merge_sort(alist)
print(stored_list)
时间复杂度: 最优O(nlogn),最劣O(nlogn),算法稳定
查找算法
顺序查找法(Sequnence Search)
最基本的查找技术,过程:从表中的第一个(或最后一个)记录开始,逐个进行记录的关键字和给定值比较,若某个记录的关键字和给定值相等,则查找成功,找到所查的记录;若直到最后一个(或第一个)记录,其关键字和给定值都不等时,则表示没有查到记录,查找不成功。
def sequence_sort(alist, v):
for i in range(len(alist)):
if alist[i] == v:
return i
return -1
alist = [54,26,93,17,77,31,44]
index = sequence_sort(alist, 44)
if index != -1:
print('Find it:', index)
else:
print('Not find it.')
二分查找法(Binary Search)
二分查找又称折半查找,优点是比较次数少,查找速度快,平均性能好;其缺点是要求 待查表为有序表,且插入删除困难。因此,折半查找方法适用于不经常变动而查找频繁的有 序列表。首先,假设表中元素是按升序排列,将表中间位置记录的关键字与查找关键字比较, 如果两者相等,则查找成功;否则利用中间位置记录将表分成前、后 fp 两个子表,如果中 间位置记录的关键字大于查找关键字,则进一步查找前一子表,否则进一步查找后一子表。 重复以上过程,直到找到满足条件的记录,使查找成功,或直到子表不存在为止,此时查找 不成功。
递归实现
def binary_search(alist,v):
#递归函数出口
if len(alist) == 0:
return False
mid = len(alist)//2
if alist[mid] == v:
return True
elif v < alist[mid] :
return binary_search(alist[:mid],v)
else:
return binary_search(alist[mid+1:],v)
alist = [0, 1, 2, 8, 13, 17, 19, 32, 42]
print(binary_search(alist, 12))
print(binary_search(alist, 13))
循环实现
def binary_search(alist,v):
first = 0
last = len(alist)-1
while first <= last:
mid = (first + last)//2
if alist[mid] == v:
return True
elif v < alist[mid]:
last = mid - 1
else:
first = mid + 1
return False
alist = [0, 1, 2, 8, 13, 17, 19, 32, 42 ]
print(binary_search(alist, 12))
print(binary_search(alist, 13))