前言
本文为7月13日Python数据结构与算法学习笔记,分为四个章节:
- 希尔排序(Shell Sort);
- 快速排序(Quick Sort);
- 归并排序(Merge Sort);
- 二分法查找(Binary Search)。
一、希尔排序(Shell Sort)
基本思想: 将数组列在一个表中并对列分别进行插入排序,重复这过程,不过每次用更长的列(步长更长了,列数更少了)来进行。
代码如下:
def shell_sort(alist):
''' 希尔排序 '''
n = len(alist)
gap = n // 2
while gap >= 1: # 控制 gap 的步长
for j in range(gap, n):
# j = [gap, gap+1, gap+2, ……, n-1]
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 # 缩短 gap 步长
if __name__ == "__main__":
li = [54, 26, 93, 17, 77, 31, 44, 55, 20]
print(li)
shell_sort(li)
print(li)
>>> [54, 26, 93, 17, 77, 31, 44, 55, 20]
>>> [17, 20, 26, 31, 44, 54, 55, 77, 93]
二、快速排序(Quick Sort)
步骤为:
- 从数列中挑出一个元素,称为"基准"(pivot);
- 重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区结束之后,该基准就处于数列的中间位置;
- 递归地把小于基准值元素的子数列和大于基准值元素的子数列排序。
代码如下:
def quick_sort(alist, first, last):
''' 快速排序 '''
if first >= last:
return
n = len(alist)
mid_value = alist[first]
low = first
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)
if __name__ == "__main__":
li = [54, 26, 93, 17, 77, 31, 44, 55, 20]
print(li)
quick_sort(li, 0, len(li)-1)
print(li)
>>> [54, 26, 93, 17, 77, 31, 44, 55, 20]
>>> [17, 20, 26, 31, 44, 54, 55, 77, 93]
三、归并排序(Merge Sort)
思想: 先递归分解数组,再合并数组。将数组分解最小之后,然后合并两个有序数组,基本思路是比较两个数组的最前面的数,谁小就先取谁,取了后相应的指针就往后移一位。然后再比较,直至一个数组为空,最后把另一个数组的剩余部分复制过来即可。
代码如下:
def merge_sort(alist):
n = len(alist)
if n <= 1:
return alist
mid = n // 2
left_li = merge_sort(alist[: mid]) # 拆分后的新列表
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)
sorted_li = merge_sort(li)
print(li)
print(sorted_li)
>>> [54, 26, 93, 17, 77, 31, 44, 55, 20]
>>> [54, 26, 93, 17, 77, 31, 44, 55, 20]
>>> [17, 20, 26, 31, 44, 54, 55, 77, 93]
四、二分法查找(Binary Search)
优点:
- 比较次数少;
- 查找速度快;
- 平均性能好。
缺点:
- 要求待查表为有序表;
- 且插入删除困难。
适用于不经常变动而查找频繁的有序列表。将表中间位置记录的关键字与查找关键字比较,如果两者相等,则查找成功;否则利用中间位置记录将表分成前、后两个子表,如果中间位置记录的关键字大于查找关键字,则进一步查找前一子表,否则进一步查找后一子表。重复以上过程,直到找到满足条件的记录,使查找成功,或直到子表不存在为止,此时查找不成功。
代码如下:
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+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 item < alist[mid]:
last = mid - 1
else:
first = 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))
>>> True
>>> False