归并排序
归并排序是采用分治法的一个非常典型的应用。归并排序的思想就是先递归分解数组,再合并数组。
将数组分解最小之后,然后合并两个有序数组,基本思路是比较两个数组的最前面的数,谁小就先取谁,取了后相应的指针就往后移一位。然后再比较,直至一个数组为空,最后把另一个数组的剩余部分复制过来即可。
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:])
# 将两个有序的子序列合并为一个新的整体
# merge(left,right)
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
else:
result.append(right_li[right_pointer])
right_pointer += 1
result += left_li[left_pointer:] #这里需要额外注意
result += right_li[right_pointer:]
return result
if __name__ == '__main__':
li = [54,26,93,17,77,31,44,55,20]
print(li)
print(merge_sort(li))
输出为
[54, 26, 93, 17, 77, 31, 44, 55, 20]
[17, 20, 26, 31, 44, 54, 55, 77, 93]
时间复杂度
- 最优时间复杂度:O(nlogn)
- 最坏时间复杂度:O(nlogn)
- 稳定性:稳定
常见排序算法效率比较
排序方法 | 平均情况 | 最好情况 | 最坏情况 | 辅助空间 | 稳定性 |
---|---|---|---|---|---|
冒泡排序 | O( n 2 n^2 n2) | O(n) | O( n 2 n^2 n2) | O(1) | 稳定 |
选择排序 | O( n 2 n^2 n2) | O( n 2 n^2 n2) | O( n 2 n^2 n2) | O(1) | 不稳定 |
插入排序 | O( n 2 n^2 n2) | O(n) | O( n 2 n^2 n2) | O(1) | 稳定 |
希尔排序 | O(nlogn)~O( n 2 n^2 n2) | O( n 1.3 n^{1.3} n1.3) | O( n 2 n^2 n2) | O(1) | 不稳定 |
堆排序 | O(nlogn) | O(nlogn) | O(nlogn) | O(1) | 不稳定 |
归并排序 | O(nlogn) | O(nlogn) | O(nlogn) | O(n) | 稳定 |
快速排序 | O(nlogn) | O(nlogn) | O( n 2 n^2 n2) | O(nlogn) ~ O(n) | 不稳定 |
搜索
搜索是在一个项目集合中找到一个特定项目的算法过程。搜索通常的答案是真的或假的,因为该项目是否存在。搜索的集中常见方法:顺序查找、二分法查找、二叉树查找、哈希查找
二分法查找
二分查找又称折半查找,优点是比较次数少,查找速度快,平均性能好;其缺点是要求待查表为有序表,且插入删除困呐。因此,这般查找方法适用于不经常变动而查找频繁的有序列表。首先,假设表中元素是按升序排列,将表中间位置记录的关键字与查找关键字比较,如果两者相等,则查找成功;否则利用中间位置记录将表分成前后两个子表,如果中间位置记录的关键字大于查找关键字,则进一步查找前一子表,否则进一步查找后一子表。重复以上过程,直到找到满足条件的记录,使查找成功,或直到子表不存在为止,此时查找不成功。
# 递归版
def binary_search(alist, item):
'''二分查找'''
n = len(alist)
if n > 0:
mid = n // 2
if alist[mid] == item:
return True
elif alist[mid] > item:
return binary_search(alist[:mid], item)
else:
return binary_search((alist[mid + 1:]), item)
return False
# 非递归版
def binary_search_2(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:
first = mid + 1
else:
last = mid - 1
return False
if __name__ == '__main__':
li = [17, 20, 26, 31, 44, 54, 55, 77, 93]
print(binary_search(li, 55))
print(binary_search(li, 100))
print(binary_search_2(li, 55))
print(binary_search_2(li, 100))
输出
True
False
True
False
时间复杂度
- 最优时间复杂度:O(1)
- 最坏时间复杂度:O(nlogn)