冒泡排序
-
冒泡排序是稳定原地排序算法
-
时间复杂度O(n^2)
-
排序方式
遍历列表并比较相邻的元素对,如果元素顺序错误,则交换它们。重复遍历列表未排序部分的元素,直到完成列表排序
"""
冒泡排序
3 8 2 5 1 4 6 7
"""
def bubble_sort(li):
# 代码第2步: 如果不知道循环几次,则举几个示例来判断
for j in range(0,len(li)-1):
# 代码第1步: 此代码为一波比对,此段代码一定一直循环,一直比对多次至排序完成
for i in range(0,len(li)-j-1):
if li[i] > li[i+1]:
li[i],li[i+1] = li[i+1],li[i]
return li
li = [3,8,2,5,1,4,6,7]
print(bubble_sort(li))
快速排序
- 快速排序是⾮稳定原地排序算法。
- 时间复杂度O(nlogn)。空间复杂度是O(logn)。
- 排序步骤:
- 首先选择一个元素,称为数组的基准元素;
- 将所有小于基准元素的元素移动到基准元素的左侧;将所有大于基准元素的移动到基准元素的右侧
- 递归地将上述两个步骤分别应用于比上一个基准元素值更小和更大的元素的每个子数组
"""
快速排序
1、left找比基准值大的暂停
2、right找比基准值小的暂停
3、交换位置
4、当right<left时,即为基准值的正确位置,最终进行交换
"""
def quick_sort(li, first, last):
if first > last:
return
# 找到基准值的正确位置下表索引
split_pos = part(li, first, last)
# 递归思想,因为基准值正确位置左侧继续快排,基准值正确位置的右侧继续快排
quick_sort(li, first, split_pos-1)
quick_sort(li, split_pos+1, last)
def part(li, first, last):
"""找到基准值的正确位置,返回下标索引"""
# 基准值、左游标、右游标
mid = li[first]
lcursor = first + 1
rcursor = last
sign = False
while not sign:
# 左游标右移 - 遇到比基准值大的停
while lcursor <= rcursor and li[lcursor] <= mid:
lcursor += 1
# 右游标左移 - 遇到比基准值小的停
while lcursor <= rcursor and li[rcursor] >= mid:
rcursor -= 1
# 当左游标 > 右游标时,我们已经找到了基准值的正确位置,不能再移动了
if lcursor > rcursor:
sign = True
# 基准值和右游标交换值
li[first],li[rcursor] = li[rcursor],li[first]
else:
# 左右游标互相交换值
li[lcursor],li[rcursor] = li[rcursor],li[lcursor]
return rcursor
if __name__ == '__main__':
li = [6,5,3,1,8,7,2,4,666,222,888,0,6,5,3]
quick_sort(li, 0, len(li)-1)
print(li)
归并排序
- 归并排序是稳定⾮原地排序算法。
- 时间复杂度O(nlogn)。空间复杂度是O(n)。
- 排序步骤
- 连续划分未排序列表,直到有N个子列表,其中每个子列表有1个"未排序"元素,N是原始数组中的元素数
- 重复合并,即一次将两个子列表合并在一起,生成新的排序子列表,直到所有元素完全合并到一个排序数组中
"""
归并排序
"""
def merge_sort(li):
# 递归出口
if len(li) == 1:
return li
# 第1步:先分
mid = len(li) // 2
left = li[:mid]
right = li[mid:]
# left_li、right_li 为每层合并后的结果,从内到外
left_li = merge_sort(left)
right_li = merge_sort(right)
# 第2步:再合
return merge(left_li,right_li)
# 具体合并的函数
def merge(left_li,right_li):
result = []
while len(left_li)>0 and len(right_li)>0:
if left_li[0] <= right_li[0]:
result.append(left_li.pop(0))
else:
result.append(right_li.pop(0))
# 循环结束,一定有一个列表为空,将剩余的列表元素和result拼接到一起
result += left_li
result += right_li
return result
if __name__ == '__main__':
li = [1,8,3,5,4,6,7,2]
print(merge_sort(li))
堆积树排序法
堆积树排序法算是选择排序法的改进版,它可以减少在选择排序法中的比较次数,进而减少排序时间。
堆积树排序法用到了二叉树的技巧,它是利用堆积树来完成排序的。
最大堆积树
- 它是一个完全二叉树;
- 所有节点的值都大于或等于它左右子节点的值;
- 树根是堆积树中最大的
最小堆积树
- 它是一个完全二叉树;
- 所有节点的值都小于或等于它左右子节点的值;
- 树根时堆积树中最小的。
def heap(data, size):
for i in range(int(size / 2), 0, -1): # 建立堆积树节点
ad_heap(data, i, size - 1)
print()
print('堆积的内容:', end='')
for i in range(1, size): # 原始堆积树的内容
print('[%2d] ' % data[i], end='')
print('\n')
for i in range(size - 2, 0, -1): # 堆积排序
data[i + 1], data[1] = data[1], data[i + 1] # 头尾节点交换
ad_heap(data, 1, i) # 处理剩余节点
print('处理过程为:', end='')
for j in range(1, size):
print('[%2d] ' % data[j], end='')
print()
def ad_heap(data, i, size):
j = 2 * i
tmp = data[i]
post = 0
while j <= size and post == 0:
if j < size:
if data[j] < data[j + 1]: # 找出最大节点
j += 1
if tmp >= data[j]: # 若树根较大,结束比较过程
post = 1
else:
data[int(j / 2)] = data[j] # 若树根较小,则继续比较
j = 2 * j
data[int(j / 2)] = tmp # 指定树根为父节点
def main():
data = [0, 5, 6, 4, 8, 3, 2, 7, 1] # 原始数组的内容
size = 9
print('原始数组为:', end='')
for i in range(1, size):
print('[%2d] ' % data[i], end='')
heap(data, size) # 建立堆积树
print('排序结果为:', end='')
for i in range(1, size):
print('[%2d] ' % data[i], end='')
main()
使用heapq来找出字典或列表的最大或最小的N个数
import heapq
students = [
{'name': 'a', 'score': '95'},
{'name': 'b', 'score': '91'},
{'name': 'c', 'score': '85'},
{'name': 'd', 'score': '98'},
{'name': 'e', 'score': '89'},
]
small = heapq.nsmallest(3, students, key=lambda x: x['score'])
large = heapq.nlargest(3, students, key=lambda x: x['score'])
print(small)
print(large)