一. 冒泡排序(Bubble Sort)
def bubble_sort(arr):
for i in range(len(arr)-1): # 循环第 i 趟
for j in range(len(arr)-i-1): # j 为下标
if arr[j] > arr[j+1]: # 如果这个数大于后面的数就交换两者的位置
arr[j], arr[j+1] = arr[j+1], arr[j]
print(arr) # 每一趟比较完了就打印一次
arr = [3, 44, 38, 5, 47, 15, 36, 26, 27, 2, 46, 4, 19, 50, 48]
bubble_sort(arr)
二、选择排序(Selection Sort)
def selection_sort(arr):
for i in range(len(arr)-1): # 循环第 i 趟
min_index = i # 记录最小数的下标
for j in range(i+1, len(arr)): # j 为下标
if arr[j] < arr[min_index]: # 如果这个数小于记录的最小数,则更新最小数的下标
min_index = j
arr[i], arr[min_index] = arr[min_index], arr[i] # 将 i 位置的数(已排序序列的末尾的数)和最小数进行交换
print(arr) # 每一趟比较完了就打印一次
arr = [3, 44, 38, 5, 47, 15, 36, 26, 27, 2, 46, 4, 19, 50, 48]
selection_sort(arr)
三、插入排序(Insertion Sort)
def insertion_sort(arr):
for i in range(1, len(arr)): # 将 i 看做摸到的牌的下标
tmp = arr[i] # 将摸到的牌储存到 tmp
j = i-1 # 将 j 看做手里的牌的下标
while j >= 0 and arr[j] > tmp: # 如果手里的牌大于摸到的牌
arr[j+1] = arr[j] # 将手里的牌往右移一个位置(将手里的牌赋值给下一个位置)
j -= 1 # 将手里的牌的下标减 1,再次准备与摸到的牌进行比较
arr[j+1] = tmp # 将摸到的牌插入到 j+1 位置
print(arr) # 每一趟比较完了就打印一次
arr = [0, 9, 8, 7, 1, 2, 3, 4, 5, 6]
insertion_sort(arr)
四、希尔排序(Shell Sort)
##第一种
def insertion_sort_gap(arr, gap): # 将 gap 看做隔 gap 个距离摸一张牌,而不是依次按照顺序摸牌
for i in range(gap, len(arr)): # 将 i 看做摸到的牌的下标
tmp = arr[i] # 将摸到的牌储存到 tmp
j = i-gap # 将 j 看做手里的牌的下标
while j >= 0 and arr[j] > tmp: # 如果手里的牌大于摸到的牌
arr[j+gap] = arr[j] # 将手里的牌往右移一个位置(将手里的牌赋值给下一个位置)
j -= gap # 将手里的牌的下标减 gap,再次准备与摸到的牌进行比较
arr[j+gap] = tmp # 将摸到的牌插入到 j+gap 位置
def shell_sort(arr):
d = len(arr) // 2 # 第一次分组
while d >= 1:
insertion_sort_gap(arr, d) # 调用插入排序
print(arr) # 每一轮排序后打印一次
d //= 2 # 整除 2 后再次分组
arr = [5, 7, 4, 6, 3, 1, 2, 9, 8]
shell_sort(arr)
#第二种
def shell_sort(arr):
d = len(arr) // 2 # 第一次分组
while d >= 1: # 将 d 看做隔 d 个距离摸一张牌,而不是依次按照顺序摸牌
for i in range(d, len(arr)): # 将 i 看做摸到的牌的下标
tmp = arr[i] # 将摸到的牌储存到 tmp
j = i - d # 将 j 看做手里的牌的下标
while j >= 0 and arr[j] > tmp: # 如果手里的牌大于摸到的牌
arr[j + d] = arr[j] # 将手里的牌往右移一个位置(将手里的牌赋值给下一个位置)
j -= d # 将手里的牌的下标减 d,再次准备与摸到的牌进行比较
arr[j + d] = tmp # 将摸到的牌插入到 j+d 位置
print(arr) # 每一轮排序后打印一次
d //= 2 # 整除 2 后再次分组
arr = [5, 7, 4, 6, 3, 1, 2, 9, 8]
shell_sort(arr)
五、归并排序(Merge Sort)
def merge(arr, low, mid, high):
# low 和 high 为整个数组的第一个和最后一个位置索引,mid 为中间位置索引
# i 和 j 为指针,最初位置分别为两个有序序列的起始位置
# ltmp 用来存放合并后的序列
i = low
j = mid+1
ltmp = []
while i <= mid and j <= high: # 只要左右两边都有数
if arr[i] < arr[j]: # 当左边的数小于右边的数
ltmp.append(arr[i]) # 将左边的数存入 ltmp
i += 1 # 左边的指针往右移一位
else: # 当右边的数小于左边的数
ltmp.append(arr[j]) # 将右边的数存入 ltmp
j += 1 # 右边的指针往右移一位
# 上面的 while 语句执行完后,左边或者右边没有数了
while i <= mid: # 当左边还有数的时候
ltmp.append(arr[i]) # 将左边剩下的数全部存入 ltmp
i += 1
while j <= high: # 当右边还有数的时候
ltmp.append(arr[j]) # 将右边剩下的数全部存入 ltmp
j += 1
arr[low:high+1] = ltmp # 将排序后的数组写回原数组
def merge_sort(arr, low, high): # low 和 high 为整个数组的第一个和最后一个位置索引
if low < high: # 至少有两个元素
mid = (low + high) // 2
merge_sort(arr, low, mid) # 把左边递归分解
merge_sort(arr, mid+1, high) # 把右边递归分解
merge(arr, low, mid, high) # 做归并
print(arr) # 每一次归并打印一次
arr = [7, 1, 3, 2, 6, 9, 4]
merge_sort(arr, 0, len(arr)-1)
六、快速排序(Quick Sort)
def partition(arr, left, right):
# 归位操作,left,right 分别为数组左边和右边的位置索引
tmp = arr[left]
while left < right:
while left < right and arr[right] >= tmp: # 从右边找比 tmp 小的数,如果比 tmp 大,则移动指针
right -= 1 # 将指针左移一个位置
arr[left] = arr[right] # 将右边的值写到左边的空位上
while left < right and arr[left] <= tmp: # 从左边找比 tmp 大的数,如果比 tmp 小,则移动指针
left += 1 # 将指针右移一个位置
arr[right] = arr[left] # 将左边的值写到右边的空位上
arr[left] = tmp # 把 tmp 归位
return left # 返回 left,right 都可以,目的是便于后面的递归操作对左右两部分进行排序
def quick_sort(arr, left, right):
if left < right:
mid = partition(arr, left, right)
print(arr) # 每次归位后打印一次
quick_sort(arr, left, mid-1) # 对左半部分进行归位操作
quick_sort(arr, mid+1, right) # 对右半部分进行归位操作
arr = [5, 7, 4, 6, 3, 1, 2, 9, 8]
quick_sort(arr, 0, len(arr)-1)
七、堆排序(Heap Sort)
def sift(arr, low, high):
"""
:param li: 列表
:param low: 堆的根节点位置
:param high: 堆的最后一个元素的位置
"""
i = low # i最开始指向根节点
j = 2 * i + 1 # j开始是左孩子
tmp = arr[low] # 把堆顶存起来
while j <= high: # 只要j位置有数
if j + 1 <= high and arr[j+1] > arr[j]: # 如果右孩子有并且比较大
j = j + 1 # j指向右孩子
if arr[j] > tmp:
arr[i] = arr[j]
i = j # 往下看一层
j = 2 * i + 1
else: # tmp更大,把tmp放到i的位置上
arr[i] = tmp # 把tmp放到某一级领导位置上
break
else:
arr[i] = tmp # 把tmp放到叶子节点上
def heap_sort(arr):
n = len(arr)
print('建堆过程:')
print(arr)
for i in range((n-2)//2, -1, -1): # i表示建堆的时候调整的部分的根的下标
sift(arr, i, n-1)
print(arr)
# 建堆完成
print('堆排序过程:')
print(arr)
for i in range(n-1, -1, -1): # i 指向当前堆的最后一个元素
arr[0], arr[i] = arr[i], arr[0]
sift(arr, 0, i - 1) # i-1是新的high
print(arr)
arr = [2, 7, 26, 25, 19, 17, 1, 90, 3, 36]
heap_sort(arr)
八、计数排序(Counting Sort)
def count_sort(arr):
if len(arr) < 2: # 如果数组长度小于 2 则直接返回
return arr
max_num = max(arr)
count = [0 for _ in range(max_num+1)] # 开辟一个计数列表
for val in arr:
count[val] += 1
arr.clear() # 原数组清空
for ind, val in enumerate(count): # 遍历值和下标(值的数量)
for i in range(val):
arr.append(ind)
return arr
arr = [2, 3, 8, 7, 1, 2, 2, 2, 7, 3, 9, 8, 2, 1, 4, 2, 4, 6, 9, 2]
sorted_arr = count_sort(arr)
print(sorted_arr)
九、桶排序(Bucket Sort)
def bucket_sort(arr):
max_num = max(arr)
n = len(arr)
buckets = [[] for _ in range(n)] # 创建桶
for var in arr:
i = min(var // (max_num // n), n-1) # i 表示 var 放到几号桶里
buckets[i].append(var) # 把 var 加到桶里边
# 保持桶内的顺序
for j in range(len(buckets[i])-1, 0, -1):
if buckets[i][j] < buckets[i][j-1]:
buckets[i][j], buckets[i][j-1] = buckets[i][j-1], buckets[i][j]
else:
break
sorted_arr = []
for buc in buckets:
sorted_arr.extend(buc)
return sorted_arr
arr = [7, 12, 56, 23, 19, 33, 35, 42, 42, 2, 8, 22, 39, 26, 17]
sorted_arr = bucket_sort(arr)
print(sorted_arr)
十、基数排序(Radix Sort)
def radix_sort(li):
max_num = max(li) # 最大值 9->1次循环, 99->2次循环, 888->3次循环, 10000->5次循环
it = 0
while 10 ** it <= max_num:
buckets = [[] for _ in range(10)]
for var in li:
# var=987, it=1, 987//10->98, 98%10->8; it=2, 987//100->9, 9%10=9
digit = (var // 10 ** it) % 10 # 依次取一位数
buckets[digit].append(var)
# 分桶完成
li.clear()
for buc in buckets:
li.extend(buc)
it += 1 # 把数重新写回 li
return arr
arr = [3221, 1, 10, 9680, 577, 9420, 7, 5622, 4793, 2030, 3138, 82, 2599, 743, 4127]
sorted_arr = radix_sort(arr)
print(sorted_arr)