# -*- coding: utf-8 -*-
# 参考各位大佬的写法整理了一下,便于自己对简单排序算法的理解
# 算法不仅仅是算法,更是一种思想
import threading
import time
def bubble_sort(input_list):
"""冒泡排序"""
length = len(input_list)
if length < 2:
return input_list
for i in range(length):
for j in range(length - 1 - i):
if input_list[j + 1] < input_list[j]:
input_list[j + 1], input_list[j] = input_list[j], input_list[j + 1]
return input_list
def select_sort(input_list):
"""选择排序"""
length = len(input_list)
if length < 2:
return input_list
for i in range(length):
minIndex = i # 初始默认minIndex为未排序列中最小元素对应的索引
for j in range(i + 1, length):
if input_list[j] < input_list[minIndex]: # 如果找到更小元素,进行交换
input_list[j], input_list[minIndex] = input_list[minIndex], input_list[j]
return input_list
def quick_sort1(input_list, left, right):
"""快速排序"""
# 直接在原列表上进行操作
def partition(input_list, left, right):
# 主要目的是将比基准数小的放到基准数左边,比基准数大的放到基准数右边
key = left # 划分参考数索引,默认为第一个数为基准数,可优化
while left < right:
# 如果列表后边的数,比基准数大或相等,则前移一位直到有比基准数小的数出现
while left < right and input_list[right] >= input_list[key]:
right -= 1
# 如果列表前边的数,比基准数小或相等,则后移一位直到有比基准数大的数出现
while left < right and input_list[left] <= input_list[key]:
left += 1
# 此时已找到一个比基准大的数,和一个比基准小的数,将他们互换位置
(input_list[left], input_list[right]) = (input_list[right], input_list[left])
# 当从两边分别逼近,直到两个位置相等时结束,将对应位置的数同基准数进行互换
(input_list[left], input_list[key]) = (input_list[key], input_list[left])
# 返回目前基准数所在位置的索引
return left
if left >= right: # 如果已经不能分区,开始结束递归调用(递归调用结束的判定)
return
# 从基准开始分区
mid = partition(input_list, left, right)
# 递归调用
quick_sort1(input_list, left, mid - 1)
quick_sort1(input_list, mid + 1, right)
return input_list
def quick_sort2(input_list):
"""快速排序"""
# 这个递归的快排会更好理解一些,缺点在于不是在原列表上进行操作
if len(input_list) >= 2:
mid = input_list[len(input_list) // 2] # 基准数可从待排序列任选
left, right = [], []
input_list.remove(mid)
for num in input_list:
if num >= mid:
right.append(num)
else:
left.append(num)
return quick_sort2(left) + [mid] + quick_sort2(right)
else:
return input_list
def merge_sort(input_list): # 分治法
"""归并排序"""
def merge(left, right): # left和right都是有序的
merge_result = []
i = j = 0
while i < len(left) and j < len(right):
if left[i] < right[j]:
merge_result.append(left[i])
i += 1
else:
merge_result.append(right[j])
j += 1
if i == len(left): # 如果left已经追加完毕,将right剩下的元素直接追加到末尾
merge_result.extend(right[j:])
else: # 如果right已经追加完毕,将left剩下的元素直接追加到末尾
merge_result.extend(left[i:])
return merge_result
if len(input_list) < 2:
return input_list
middle = len(input_list) // 2
left = merge_sort(input_list[:middle]) # 递归调用归并排序
right = merge_sort(input_list[middle:])
return merge(left, right)
def insert_sort(input_list):
"""插入排序"""
length = len(input_list)
if length < 2:
return input_list
for i in range(1, length):
j = i
target = input_list[i] # target要进行插入的元素
while j > 0 and target < input_list[j - 1]: # 寻找插入位置
input_list[j] = input_list[j - 1]
j = j - 1
input_list[j] = target
return input_list
def shell_sort(input_list):
"""希尔排序"""
def shell_insert(input_list, gap): # gap为组内元素的索引间隔(步长),代码部分参考“插入排序”,很像
for i in range(gap, length): # 当gap为1的时候,就是等同于插入排序insert_sort
j = i
target = input_list[i] # 记录要插入的数,因为input_list[i]的值会被覆盖,所以必须提前记录
while j > 0 and target < input_list[j - gap]: # 对步长为gap的同组数据进行插入排序
# 从后往前,直到找到比target小的数的位置
input_list[j] = input_list[j - gap] # 向后挪动
j -= gap # 未找到之前,继续往前一个
input_list[j] = target # 将target插入目标位置
length = len(input_list)
if length < 2:
return input_list
gap = length // 2
while gap >= 1:
shell_insert(input_list, gap)
gap = gap // 2
return input_list
def heap_sort(input_list):
"""堆排序"""
def sift_down(input_list, father, end): # 让父节点始终比左右子节点(如果右节点存在的话)的值要大
while True:
# 交换之后可能造成被交换的孩子节点作为父节点不再满足堆的性质,因此需要重新对交换的孩子节点进行堆初始化
left_child = 2 * father + 1 # 父节点左孩子节点下标
if left_child > end: # 孩子节点不一定还有孩子节点
break
# 如果节点的右孩子存在且大于左孩子时,此时,右孩子为孩子节点中的最大,交换时此右节点与父节点交换
# 否则,父节点只有左孩子或者左孩子比右孩子要小,此时,左孩子是孩子节点中最大的,交换时此左节点与父节点交换
if left_child + 1 <= end and input_list[left_child + 1] > input_list[left_child]:
left_child = left_child + 1
# 若上一个if语句执行,则以下代码是右子节点与父节点交换,否则,为左子节点与父节点交换
if input_list[left_child] > input_list[father]:
input_list[left_child], input_list[father] = input_list[father], input_list[left_child]
father = left_child # 被调换的子节点重新作为父节点进行调整操作
else:
break
length = len(input_list)
first = length // 2 - 1 # 最后一个有孩子的节点的下标
for i in range(first, -1, -1): # 从最后一个有子节点的节点开始往上调整最大堆
sift_down(input_list, i, length - 1)
for head_end in range(length - 1, 0, -1):
input_list[head_end], input_list[0] = input_list[0], input_list[head_end] # 头尾对调,同时堆开始变小
sift_down(input_list, 0, head_end - 1) # father=0, 表示交换以后从根节点开始往下调整
return input_list
def count_sort(input_list):
"""计数排序"""
length = len(input_list)
if length < 2:
return input_list
max_num = max(input_list)
count = [0] * (max_num + 1)
for element in input_list:
count[element] += 1 # 间接使用索引来存储数
input_list.clear()
for i in range(max_num + 1): # 元素[0, 1, 2, ..., max_num]
# input_list.extend([i] * count[i]) # 下面两条语句可以用这条语句替代
for j in range(count[i]): # count[i]表示元素i出现的次数,如果有多次,重复追加
input_list.append(i)
return input_list
# 下面这种代码思想也可以达到相同的目的,只不过中间涉及到元素间的比较,与计数排序的思想稍有差异。
# count = [0] * length
# for i in range(length):
# p = 0
# q = 0
# for j in range(length):
# # 全表查找比input_list[i]小的元素个数p;q是为了保证相同元素重复出现时仍然能够正常排序
# # 这块的元素比较使得它算不上真正意义上的计数排序,不过思想倒是已经很不错。
# if input_list[j] < input_list[i]:
# p += 1
# elif input_list[j] == input_list[i]:
# q += 1
# # count[p] = input_list[i]
# for k in range(p, p + q): # 如果没有重复元素,最终可得q=1,这里其实就可以写成 count[p] = input_list[i] 了
# count[k] = input_list[i]
# return count
def bucket_sort(input_list):
"""桶排序"""
big = max(input_list)
num = big // 10 + 1 # 以10为等差计算桶的数目
buckets = [[] for i in range(0, num)] # 初始化桶
for i in input_list:
buckets[i // 10].append(i) # 划分桶
for i in buckets: # 桶内排序(桶内快速排序)
quick_sort1(i, 0, len(i) - 1) # 对原列表进行修改,所以无需返回新的排序后的列表
# bucket = quick_sort2(i) # 返回新的列表,不是在原列表上修改
# buckets[buckets.index(i)] = bucket # 根据桶的划分,每个桶是不一样的,所以我这儿用index函数查找每个桶的索引位置
output_list = []
for i in buckets:
output_list.extend(i)
# for j in i:
# output_list.append(j)
return output_list
def radix_sort(input_list, radix=10):
"""基数排序"""
# import math
# K = math.ceil(math.log(max(input_list), radix)) # 用K位数可表示任意整数
K = 1 # 也可不用 import math 模块, 毕竟简单算法,能不用已有的库就不用
for element in input_list:
while True:
if element >= radix ** K:
K += 1
else:
break
# K表示最大数的位数,比如最大数为897,则K=3
bucket = [[] for i in range(radix)] # 不能用 [[]]*radix (看完下面几条语句你就会明白为什么)
# bucket = [[]] * radix # [[], [], [], [], [], [], [], [], [], []]
# >>> aa = [[]] * 10 # 一改具改
# >>> bb = [[] for i in range(10)]
# >>> aa == bb # 尽管有
# True
# >>> aa[0] is aa[1]
# True
# >>> bb[0] is bb[1] # 但是
# False
# [3, 44, 38, 5, 47, 15, 36, 26, 27, 2, 46, 4, 19, 50, 48]
# [[50], [], [2], [3], [44, 4], [5, 15], [36, 26, 46], [47, 27], [38, 48], [19]]
# [50, 2, 3, 44, 4, 5, 15, 36, 26, 46, 47, 27, 38, 48, 19]
# [[2, 3, 4, 5], [15, 19], [26, 27], [36, 38], [44, 46, 47, 48], [50], [], [], [], []]
# [2, 3, 4, 5, 15, 19, 26, 27, 36, 38, 44, 46, 47, 48, 50]
for i in range(K): # K次循环
for val in input_list:
bucket_index = val % (radix ** (i + 1)) // (radix ** i) # 把val放到bucket_index对应的这个桶
# example 4789 % 10**3 // 10**2 == 7
bucket[bucket_index].append(val) # 析取整数第K位数字 (从低到高, 个十百千...)
input_list.clear()
for each in bucket:
input_list.extend(each) # 桶合并
bucket = [[] for i in range(radix)]
return input_list
def sleep_sort(input_list): # 哈哈,调皮一下,顺便学学join和守护线程的用法,如果max(input_list)比较大的话,建议放弃尝试
"""睡眠排序"""
output_list = []
thread_list = []
def do_sleep(i):
# 统一乘了一个系数,总不能让我真的等i秒
time.sleep(i / 100) # 只要sleep时间不会过于短,在毫秒级别以上,应该都是可以分出先后的,再短就悬了
output_list.append(i)
for i in input_list:
t = threading.Thread(target=do_sleep, args=(i,))
thread_list.append(t)
for t in thread_list: # 对每个线程设置守护并开启
t.setDaemon(True)
t.start()
for t in thread_list: # join所完成的工作就是线程同步,避免主线程提前结束以后直接终止掉了子线程
t.join() # 即主线程任务结束之后,进入阻塞状态,一直等待其他的子线程执行结束之后才继续
# t.join(timeout=0.02) # 主线程将会累计等待timeout*len(input_list)这么多秒,时间一到,强行终止,返回当前已排序结果
return output_list
# 示例:(为什么每次调用我都把input_list重新赋值一遍?我乐意?非也!因为大部分排序算法是直接在input_list上进行修改)
if __name__ == '__main__':
input_list = [3, 44, 38, 5, 47, 15, 36, 26, 27, 2, 46, 4, 19, 50, 48]
print("冒泡排序 :", bubble_sort(input_list))
input_list = [3, 44, 38, 5, 47, 15, 36, 26, 27, 2, 46, 4, 19, 50, 48]
print("选择排序 :", select_sort(input_list))
input_list = [3, 44, 38, 5, 47, 15, 36, 26, 27, 2, 46, 4, 19, 50, 48]
print("快速排序1:", quick_sort1(input_list, 0, len(input_list) - 1))
input_list = [3, 44, 38, 5, 47, 15, 36, 26, 27, 2, 46, 4, 19, 50, 48]
print("快速排序2:", quick_sort2(input_list))
input_list = [3, 44, 38, 5, 47, 15, 36, 26, 27, 2, 46, 4, 19, 50, 48]
print("归并排序 :", merge_sort(input_list))
input_list = [3, 44, 38, 5, 47, 15, 36, 26, 27, 2, 46, 4, 19, 50, 48]
print("插入排序 :", insert_sort(input_list))
input_list = [3, 44, 38, 5, 47, 15, 36, 26, 27, 2, 46, 4, 19, 50, 48]
print("希尔排序 :", shell_sort(input_list))
input_list = [3, 44, 38, 5, 47, 15, 36, 26, 27, 2, 46, 4, 19, 50, 48]
print(" 堆排序 :", heap_sort(input_list))
input_list = [3, 44, 38, 5, 47, 15, 36, 26, 27, 2, 46, 4, 19, 50, 48]
print("计数排序 :", count_sort(input_list))
input_list = [3, 44, 38, 5, 47, 15, 36, 26, 27, 2, 46, 4, 19, 50, 48]
print(" 桶排序 :", bucket_sort(input_list))
input_list = [3, 44, 38, 5, 47, 15, 36, 26, 27, 2, 46, 4, 19, 50, 48]
print("基数排序 :", radix_sort(input_list))
input_list = [3, 44, 38, 5, 47, 15, 36, 26, 27, 2, 46, 4, 19, 50, 48]
print("睡眠排序 :", sleep_sort(input_list))
"D:\Program Files\Python36\python3.exe" D:/MyProject/Python/workspace/sorting_algorithm.py
冒泡排序 : [2, 3, 4, 5, 15, 19, 26, 27, 36, 38, 44, 46, 47, 48, 50]
选择排序 : [2, 3, 4, 5, 15, 19, 26, 27, 36, 38, 44, 46, 47, 48, 50]
快速排序1: [2, 3, 4, 5, 15, 19, 26, 27, 36, 38, 44, 46, 47, 48, 50]
快速排序2: [2, 3, 4, 5, 15, 19, 26, 27, 36, 38, 44, 46, 47, 48, 50]
归并排序 : [2, 3, 4, 5, 15, 19, 26, 27, 36, 38, 44, 46, 47, 48, 50]
插入排序 : [2, 3, 4, 5, 15, 19, 26, 27, 36, 38, 44, 46, 47, 48, 50]
希尔排序 : [2, 3, 4, 5, 15, 19, 26, 27, 36, 38, 44, 46, 47, 48, 50]
堆排序 : [2, 3, 4, 5, 15, 19, 26, 27, 36, 38, 44, 46, 47, 48, 50]
计数排序 : [2, 3, 4, 5, 15, 19, 26, 27, 36, 38, 44, 46, 47, 48, 50]
桶排序 : [2, 3, 4, 5, 15, 19, 26, 27, 36, 38, 44, 46, 47, 48, 50]
基数排序 : [2, 3, 4, 5, 15, 19, 26, 27, 36, 38, 44, 46, 47, 48, 50]
睡眠排序 : [2, 3, 4, 5, 15, 19, 26, 27, 36, 38, 44, 46, 47, 48, 50]
Process finished with exit code 0