python 中 列表就是一个顺序表
有序顺序表 比 普通顺序表 查找速度快一点,但是时间复杂度还是O(n)
二分查找法
可以大大减少查找的数据项, 时间复杂度是O(log(n))
# 循环版本的二分查找
my_list = [1, 2, 19, 23, 53, 68, 79]
def binary_search(a_list, item):
first = 0
last = len(a_list) - 1
found = False
while first <= last and not found:
mid = (first + last) // 2
if a_list[mid] == item:
found = True
else:
if a_list[mid] > item:
last = mid - 1
else:
first = mid + 1
return found
print(binary_search(my_list, 19))
# 二分查找的递归方法
my_list = [1, 2, 19, 23, 53, 88, 99]
# 注意,不用列表切片的原因是,列表切片的复杂度是O(n)
def binary_search(a_list, item, first, end):
# 结束条件
if first > end:
return False
mid = (first + end) // 2
if a_list[mid] == item:
return True
# 缩小规模
elif a_list[mid] > item:
# 调用自身
return binary_search(a_list, item, first, mid - 1)
else:
# 调用自身
return binary_search(a_list, item, mid + 1, end)
print(binary_search(my_list, 19, 0, len(my_list) - 1))
缺点: 虽然二分查找的速度要快于顺序查找,但是二分查找的条件是列表是有序排列的。 得到有序排列的列表也是需要消耗很多计算资源的。所以,如果列表的内容经常变化,则不建议使用二分查找。
冒泡排序
# 冒泡排序
# 总需要n-1趟,随着趟数的增加,比对次数逐步从n-1减少到1,并包括可能发生的n次数据项交换。
# 第一趟,对比n-1次,第二趟,对比n-2次,第n-1趟,对比1次。
# 最大时间复杂度O(n^2),效率很差,有个优点是无序额外的存储空间开销
def bubble_sort(a_list):
for compare_times in range(len(a_list) - 1, 0, -1): # 从len(alist)-1 到 1
for i in range(compare_times):
if a_list[i] > a_list[i + 1]:
a_list[i], a_list[i + 1] = a_list[i + 1], a_list[i]
def bubble_sort_optimization(a_list):
for compare_times in range(len(a_list) - 1, 0, -1): # 从len(alist)-1 到 1
exchange = False # 优化
for i in range(compare_times):
if a_list[i] > a_list[i + 1]:
exchange = True # 优化
a_list[i], a_list[i + 1] = a_list[i + 1], a_list[i]
if not exchange: # 优化
break
my_list = [4, 3, 2, 1]
bubble_sort(my_list)
print(my_list)
选择排序
# 选择排序对交换进行了削减,相比起冒泡排序进行多次交换,每趟仅进行1次交换,记录最大项的所在位置,最后再跟本趟最后一项交换
def select_sort(a_list):
for pass_num in range(len(a_list) - 1, 0, -1):
max_value_index = 0
for i in range(1, pass_num+1):
if a_list[max_value_index] < a_list[i]:
max_value_index = i
a_list[max_value_index], a_list[pass_num] = a_list[pass_num], a_list[max_value_index]
my_list = [12, 34, 5, 2, 3, 5, 672, 34, 2, 1]
select_sort(my_list)
print(my_list)
插入排序
就和打牌的时候排序一样
# 插入排序 写法一
def insert_sort(a_list):
for index in range(1, len(a_list)):
current_value = a_list[index] # 新项/插入项
position = index
while position >= 1 and a_list[position - 1] > current_value:
# 比对移动
a_list[position] = a_list[position - 1]
position = position - 1
a_list[position] = current_value # 插入新项
my_list = [34, 5, 5, 1, 23, 4, 7, 4, 34, 45, 6, 47, 98, 3, 2, 57, 46]
insert_sort(my_list)
print(my_list)
# 插入排序 写法二
def insert_sort(lst):
for i in range(1, len(lst)):
for j in range(i, 0, -1):
if lst[j-1] > lst[j]:
lst[j-1], lst[j] = lst[j], lst[j-1]
else:
break
a_list = [54, 26, 93, 17, 77, 31, 44, 55, 20]
insert_sort(a_list)
print(a_list)
谢尔排序(shell排序)
# 谢尔排序
def shell_sort(a_list):
sub_list_count = len(a_list) // 2
while sub_list_count > 0:
for start_position in range(sub_list_count):
gap_insert_sort(a_list, start_position, sub_list_count)
print("After increaments of size", sub_list_count, "The list is", a_list)
sub_list_count = sub_list_count // 2
def gap_insert_sort(a_list, start, gap):
for i in range(start + gap, len(a_list), gap):
current_value = a_list[i]
position = i
while position >= gap and a_list[position - gap] > current_value:
a_list[position] = a_list[position - gap]
position = position - gap
a_list[position] = current_value
my_list = [3, 123, 2, 4, 123, 2, 52, 45, 45, 6, 2, 3.45, 3, 342, 13, 2134, 1234, 12]
shell_sort(my_list)
#After increaments of size 9 The list is [3, 2, 2, 3, 123, 2, 52, 45, 12, 6, 123, 3.45, 4, 342, 13, 2134, 1234, 45]
#After increaments of size 4 The list is [3, 2, 2, 3, 4, 2, 13, 3.45, 12, 6, 52, 45, 123, 45, 123, 2134, 1234, 342]
#After increaments of size 2 The list is [2, 2, 3, 2, 4, 3, 12, 3.45, 13, 6, 52, 45, 123, 45, 123, 342, 1234, 2134]
#After increaments of size 1 The list is [2, 2, 2, 3, 3, 3.45, 4, 6, 12, 13, 45, 45, 52, 123, 123, 342, 1234, 2134]
# shell 排序2
def shell_sort(lst):
n = len(lst)
gap = n // 2
while gap > 0:
for i in range(gap, n):
j = i
while j >= gap and lst[j - gap] > lst[j]:
lst[j - gap], lst[j] = lst[j], lst[j - gap]
j -= gap
gap = gap // 2
a_list = [54, 26, 93, 17, 77, 31, 44, 55, 20]
shell_sort(a_list)
print(a_list)
归并排序
注意到归并排序算法使用了额外1倍的存储空间用于归并, 这个特性在对特大数据集进行排序的时候,要考虑进去
时间复杂度比前面几个好一点,前面的都是O(n^2) , 归并排序是O(nlog(n))
# 归并排序
def merge_sort(lst):
# 结束条件
# 调用自身
# 减小规模
if len(lst) <= 1:
return lst
middle = len(lst) // 2
left = merge_sort(lst[:middle]) # 左半部分排好序
right = merge_sort(lst[middle:]) # 右半部分排好序
# 合并左右部分,完成排序
merged = []
while left and right:
if left[0] <= right[0]:
merged.append(left.pop(0))
else:
merged.append(right.pop(0))
merged.extend(right if right else left)
return merged
my_list = [34, 5, 5, 1, 23, 3, 2, 4, 34, 45, 6, 47, 98, 4, 7, 57, 46]
print(merge_sort(my_list))
快速排序
依据一个“中值”数据项来把数据表分成两半: 小于中值的一半和大于中值的一半,然后每部分分别进行快速排序(递归)
def quick_sort(alist, start, end):
"""快速排序"""
# 递归的退出条件
if start >= end:
return
# 设定起始元素为要寻找位置的基准元素
mid = alist[start]
# low为序列左边的由左向右移动的游标
low = start
# high为序列右边的由右向左移动的游标
high = end
while low < high:
# 如果low与high未重合,high指向的元素不比基准元素小,则high向左移动
while low < high and alist[high] >= mid:
high -= 1
# 将high指向的元素放到low的位置上
alist[low] = alist[high]
# 如果low与high未重合,low指向的元素比基准元素小,则low向右移动
while low < high and alist[low] < mid:
low += 1
# 将low指向的元素放到high的位置上
alist[high] = alist[low]
# 退出循环后,low与high重合,此时所指位置为基准元素的正确位置
# 将基准元素放到该位置
alist[low] = mid
# 对基准元素左边的子序列进行快速排序
quick_sort(alist, start, low - 1)
# 对基准元素右边的子序列进行快速排序
quick_sort(alist, low + 1, end)
alist = [54, 26, 93, 17, 77, 31, 44, 55, 20]
quick_sort(alist, 0, len(alist) - 1)
print(alist)
散列:
什么是散列?
散列数据结构, 可以将数据查找的次数降低到常数级。 也就是由数据项的值来确定其存放的位置!
散列表, 又称哈希表,是一种数据集,其中数据项的存储方式尤其有利于将来快速的查找定为
散列表中的每一个存储位置,称为槽slot, 可以用来保存数据项, 每个槽有一个唯一个名词
python 自带散列函数库hashlib
# 对单字符串(小的数据项)进行散列计算
import hashlib
print(hashlib.md5("hello world!".encode()).hexdigest())
print(hashlib.sha1("hello world!".encode()).hexdigest())
# 对数据量很大的数据进行哈希计算的时候(比如电影视频),可以分部分计算
import hashlib
m = hashlib.md5()
m.update("hello world!".encode())
m.update("this is part #2".encode())
m.update("this is part #3".encode())
print(m.hexdigest())