首先我们需要一个序列, 通过排序生成一下
# 添加一个标志位,
# 随机生成一个乱序数组
import random
list1 = []
for i in range(15):
list1.append(random.randint(0,100))
print(list1)
一、冒泡算法
原理: 简单描述:从左到右两两比较大小
时间复杂度:O(n^2)
空间复杂度:O(1)
稳定
编:就像可乐的气泡一样,从底部逐渐向上浮出水面
优化思想: 如果当前轮次,列表元素没有发生交换, 那么可以判断是有序的提前结束, 提高效率
import time
class BubbleSort():
# -> 返回类型
def __init__(self, nlist:list) -> list:
self.mylist = nlist
def sortV1(self, length):
#waste time: 0.00010442733764648438
if length < 2:
return
temp = 0 # 交换位
for i in range(length - 1): # -1, 防止越界
if self.mylist[i] > self.mylist[i+1]:
flag = True
temp = self.mylist[i+1]
self.mylist[i+1] = self.mylist[i]
self.mylist[i] = temp
self.sortV1(length=length-1)
# 优化
def sortV2(self, length):
#waste time: 6.580352783203125e-05
if length < 2:
return
temp = 0 # 交换位
flag = False # 标志位,如果没发生交换,则可以提前结束排序
for i in range(length - 1): # -1, 防止越界
if self.mylist[i] > self.mylist[i+1]:
flag = True
temp = self.mylist[i+1]
self.mylist[i+1] = self.mylist[i]
self.mylist[i] = temp
if flag == False:
return
self.sortV2(length=length-1)
def get_list(self):
return self.mylist
if __name__ == '__main__':
start_time = time.time()
list1 = [23, 75, 83, 9, 1, 63, 87, 16, 23, 91, 87, 59, 38, 21, 83]
# list1 = [23]
print(list1)
BS = BubbleSort(nlist=list1)
BS.sortV2(length=len(list1))
print(BS.get_list())
print("waste time: ",time.time()-start_time)
二、选择算法
原理: 简单描述:从头到尾扫描, 找到最小的放到第一个元素. 循环此操作
时间复杂度:O(n^2)
空间复杂度:O(1)
不稳定
编:左小右大一起扫,加速加速加速
# 选择排序
# 选择排序
import time
class ChoiceSort():
# -> 返回类型
def __init__(self, nlist:list) -> list:
self.mylist = nlist
def sortV1(self, length, first=0):
# waste time1: 3.123283386230469e-05
if length < 2:
return
if length - 1 == first:
return
temp = self.mylist[first] # 最小和临时交换位 且 默认第一个是最小位置
sub_min = first # 最小的下标位
# 每次找出一个最小位置
for i in range(sub_min, length):
if self.mylist[i] < temp: # 如果比最小位要小,暂时进入min
# 如果是链表, 即已知原来的序号, 那么可以根据这个来判断谁前谁后, 就会稳定.
temp = self.mylist[i]
sub_min = i
# 交换
self.mylist[sub_min] = self.mylist[first] # 被本轮首位替换
# 本轮最小值换到首位
self.mylist[first] = temp
self.sortV1(length=length,first=first+1)
def sortV2(self, length, first=0):
# waste time2: 1.2636184692382812e-05
if length < 2:
return
if length - 1 == first:
return
flag = False
min = self.mylist[first] # 最小和临时交换位 且 默认第一个是最小位置
max = self.mylist[length-first-1] # 最大和临时交换位 且 默认第一个是最小位置
sub_min = first # 最小的下标位
sub_max = length-first-1 # 最大的下标位
# 每次找出一个最小位置
for i in range(sub_min, sub_max):
if self.mylist[i] < min: # 如果比最小位要小,暂时进入min
# 如果不加等号, 那么这里会报错, 不会进入if线.
# 如果是链表, 即已知原来的序号, 那么可以根据这个来判断, 就会稳定.
min = self.mylist[i]
sub_min = i
flag = True
if self.mylist[length-i-1] > max: # 如果比最小位要小,暂时进入min
# 如果不加等号, 那么这里会报错, 不会进入if线.
# 如果是链表, 即已知原来的序号, 那么可以根据这个来判断, 就会稳定.
max = self.mylist[length-i-1]
sub_max = length-i-1
flag = True
if flag == False:
return
# 最小值交换
self.mylist[sub_min] = self.mylist[first] # 被本轮首位替换
# 本轮最小值换到首位
self.mylist[first] = min
# 最大值交换
self.mylist[sub_max] = self.mylist[length-first-1] # 被本轮首位替换
# 本轮最大值换到尾位
self.mylist[length-first-1] = max
self.sortV2(length=length,first=first+1)
def get_list(self):
return self.mylist
def set_list(self, list_in:list):
self.mylist = list_in
if __name__ == '__main__':
list1 = [23, 75, 83, 9, 1, 63, 87, 16, 23, 91, 87, 59, 38, 21, 83]
# list1 = [23]
print(list1)
BS = ChoiceSort(nlist=list1)
# V1方法
start_time = time.time()
BS.sortV1(length=len(list1), first=0)
print(BS.get_list())
V1_time = time.time()
BS.set_list(list_in=list1)
# V2优化方法
middle_time = time.time()
BS.sortV2(length=len(list1), first=0)
print(BS.get_list())
V2_time = time.time()
print("waste time1: ",V1_time-start_time)
print("waste time2: ",V2_time-middle_time)
三、插入算法
原理: *简单描述:构建另一个有序列表,把无序列表的每一个值从后往前插入有序列表中,就像玩纸牌一样.
时间复杂度:O(n^2)
空间复杂度:O(1)
稳定
不足: 1)寻找插入位置; 2)移动元素
优化: 1)对已经排序好的序列, 采用二分查找
2)携带多个元素
3)数据链表化
4)希尔排序
编:可是我的纸牌每次都排不好
# 选择排序
import time
class InsertSort():
# -> 返回类型
def __init__(self, nlist:list) -> list:
self.mylist = nlist
def sortV1(self, length):
# waste time1: 3.123283386230469e-05
if length < 2:
return
# 先插入一个值
new_list = [self.mylist[0]]
# 按顺序遍历无序列表,把每一个值插入有序列表new_list中
for i in range(1, length):
now_value = self.mylist[i]
# 设立一个flag, 如果已经插入, 就不需要在循环
flag = False
for j in range(len(new_list)):
if flag==True: # 如果flag是true, 就跳出循环
break
# 从后向前遍历, 如果该元素大于某个值,就插入这里的下标
if now_value >= new_list[len(new_list)-j-1]:
new_list.insert(len(new_list)-j, now_value)
flag = True
# 如果遍历到最后一个,且还没有插入, 那就插入第一个地方
if j==len(new_list)-1 and flag == False:
new_list.insert(0, now_value)
flag = True
# 如果不成立, 肯定插入首位
# else:
# new_list.insert(0, now_value)
# flag = True
self.mylist = new_list
def sortV2(self, length, first=0):
#不足: 1)寻找插入位置; 2)移动元素
#优化: 1)对已经排序好的序列, 采用二分查找
# 2)携带多个元素, 插入时,把多个大的元素一起后移,提高效率
# 3)数据链表化, 链表化后,只需要改自身地址
# 4)希尔排序
pass
def get_list(self):
return self.mylist
def set_list(self, list_in:list):
self.mylist = list_in
if __name__ == '__main__':
list1 = [23, 75, 83, 9, 1, 63, 87, 16, 23, 91, 87, 59, 38, 21, 83]
# list1 = [23]
print(list1)
BS = InsertSort(nlist=list1)
# V1方法
start_time = time.time()
BS.sortV1(length=len(list1))
print(BS.get_list())
V1_time = time.time()
BS.set_list(list_in=list1)
# V2优化方法
# middle_time = time.time()
# BS.sortV2(length=len(list1), first=0)
# print(BS.get_list())
# V2_time = time.time()
print("waste time1: ",V1_time-start_time)
# print("waste time2: ",V2_time-middle_time)
四、希尔排序算法
原理: *简单描述:针对插入算法的改进.先分组(隔几个元素分为一组), 每组进行插入排序, 再调整分组方式重复操作, 最后使用一次插入排序.
时间复杂度:O(nlogn)
最坏O(n^2)空间复杂度:O(1)
数组不稳定, 链表稳定
希尔增量问题: 增量就是间隔, 从大到小
*编:这个从几个元素开始分,我是直接默认从一半开始。插入排序记得加flag位跳过有序数列
# 希尔排序
import time
class ShellSort():
# -> 返回类型
def __init__(self, nlist:list) -> list:
self.mylist = nlist
def sortV1(self):
inlist = self.mylist
length_inlist = len(inlist) # 总长度
for idx in range(length_inlist//2):
# idx = 0,1,....,(len//2)
# 以总长度的一半作为最大间隔量
steps = length_inlist//2 - 1 - idx
# 要想不停分组到全部遍历, 起始点要到间隔数为止.
for step in range(steps):
# 等间隔抽取
new_list = inlist[step:length_inlist:steps]
new_list = self.insertsort(new_list, len(new_list))
# 等间隔赋值
inlist[step:length_inlist:steps] = new_list
print("间隔=>{}: ".format(steps), inlist)
self.mylist = inlist
def insertsort(self, list_sort, length):
# waste time1: 3.123283386230469e-05
if length < 2:
return
# 先插入一个值
new_list = [list_sort[0]]
# 按顺序遍历无序列表,把每一个值插入有序列表new_list中
for i in range(1, length):
now_value = list_sort[i]
# 设立一个flag, 如果已经插入, 就不需要在循环
flag = False
for j in range(len(new_list)):
if flag==True: # 如果flag是true, 就跳出循环
break
# 从后向前遍历, 如果该元素大于某个值,就插入这里的下标
if now_value >= new_list[len(new_list)-j-1]:
new_list.insert(len(new_list)-j, now_value)
flag = True
# 如果遍历到最后一个,且还没有插入, 那就插入第一个地方
if j==len(new_list)-1 and flag == False:
new_list.insert(0, now_value)
flag = True
# 如果不成立, 肯定插入首位
# else:
# new_list.insert(0, now_value)
# flag = True
return new_list
def get_list(self):
return self.mylist
def set_list(self, list_in:list):
self.mylist = list_in
if __name__ == '__main__':
list1 = [23, 75, 83, 9, 1, 63, 87, 16, 23, 91, 87, 59, 38, 21, 83]
# list1 = [23]
print(list1)
BS = ShellSort(nlist=list1)
# V1方法
start_time = time.time()
BS.sortV1()
print(BS.get_list())
V1_time = time.time()
# BS.set_list(list_in=list1)
# V2优化方法
# middle_time = time.time()
# BS.sortV2(length=len(list1), first=0)
# print(BS.get_list())
# V2_time = time.time()
print("waste time1: ",V1_time-start_time)
# print("waste time2: ",V2_time-middle_time)
五、快速排序算法(!该部分未完全独立思考,参考了部分网络资料)
原理: *简单描述:取一个基准数,把无序列表中小于它的数放到左区间,大于它的放右区间,然后重复执行直到各区间小于两个元素.
时间复杂度:O(nlogn) 最坏O(n^2)
空间复杂度:O(logn)
不稳定
编:这个标志位的移动真的搞死我了
# 选择排序
import time
class FastSort():
# -> 返回类型
def __init__(self, nlist:list) -> list:
self.mylist = nlist
def sortV1(self):
# 从右标志开始,找小的数放入基准位,然后左标志开始移动,找到大的数放入左标志位
inlist = self.mylist
if len(inlist) < 2:
return
# 栈,存储排序子数组的起始和结束位置
stack = [(0, len(inlist)-1)] # stack = [(0,14)]
# 设置左右下标志位, 分别位于首尾
while stack:
# 弹出栈顶的子数组的起始和结束位置,
low, high = stack.pop() # low=0, high=14
if low >= high:
continue
# 选择最后一个作为基准数
pivot = inlist[high]
print("pivot:",pivot)
i = low - 1 # 初始化时(-1),先保证所有元素都不在i的右侧
# ≤到左侧,>到右侧
for j in range(low, high):
if inlist[j] <= pivot: # 从左往右找小于基准数的元素
i += 1 # 找到了,i+1,i置于这些小于基准数的右侧
inlist[i], inlist[j] = inlist[j], inlist[i] #i,j对换
# 直到if条件不再满足,i不再变化。这里i+1就是基准数该去的位置
# 基准数放入i+1位置,原来的数放入最右
inlist[i+1], inlist[high] = inlist[high], inlist[i+1]
print("=>",inlist)
# 将左右区间的起始和结束位置压入栈中,继续处理左右区间
stack.append((low, i))
stack.append((i+2, high)) # i+2 跳过基础数
self.mylist = inlist
def sortV2(self):
# 等间隔随机抽取一个中间数作为基准数,提高排序效率
new_list = inlist[0:len(inlist):len(inlist)//4]
# 当元素少于10个时,采用插入排序,效率更高。
def get_list(self):
return self.mylist
def set_list(self, list_in:list):
self.mylist = list_in
if __name__ == '__main__':
list1 = [23, 75, 83, 9, 1, 63, 87, 16, 23, 91, 87, 59, 38, 21, 83]
# list1 = [23]
print(list1)
BS = FastSort(nlist=list1)
# V1方法
start_time = time.time()
BS.sortV1()
print(BS.get_list())
V1_time = time.time()
# BS.set_list(list_in=list1)
# # V2优化方法
# middle_time = time.time()
# BS.sortV2(length=len(list1), first=0)
# print(BS.get_list())
# V2_time = time.time()
print("waste time1: ",V1_time-start_time)
# print("waste time2: ",V2_time-middle_time)
六、归并算法
原理: *简单描述:对多个有序子数列进行两两合并,每两个子数列各有一个标志位,比较时,标志位上更小的先进入最终数列.
时间复杂度:O(nlogn)
空间复杂度:O(n)
稳定
编:要考虑合并时任何一个数列没有被合并完的情况
# 归并排序
import time
class MergeSort():
# -> 返回类型
def __init__(self, nlist:list) -> list:
self.mylist = nlist
def sortV1(self):
inlist = self.mylist
if len(inlist) < 2:
return
# 对子列表分别进行合并(不重合的两两合并)
# 如果刚好是偶数
if len(inlist) % 2 != 0:
new_inlist = [inlist[-1]]
else:
new_inlist = []
for k in range(len(inlist)//2):
new_inlist.append(self.merge_two_list(list1=inlist[2*k], list2=inlist[2*k-1]))
self.mylist = new_inlist
print("middle_list:", self.mylist)
# 递归
self.sortV1()
# self.mylist = inlist
def merge_two_list(self, list1, list2):
flag1, flag2 = 0, 0
new_list = []
while flag1 < len(list1) and flag2 < len(list2):
# 小就放入新列表
if list1[flag1] < list2[flag2]:
new_list.append(list1[flag1])
flag1 += 1
# 大则下一个, flag+1
else:
new_list.append(list2[flag2])
flag2 += 1
# 此时还有其他情况
# list2都进入new_list了, list1还有
if flag2 == len(list2):
for j in range(flag1,len(list1)):
new_list.append(list1[j])
# list1都进入new_list了, list2还有
if flag1 == len(list1):
for j in range(flag2,len(list2)):
new_list.append(list2[j])
# 直到循环结束
return new_list
def get_list(self):
return self.mylist
def set_list(self, list_in:list):
self.mylist = list_in
if __name__ == '__main__':
list1 = [23, 75, 83, 9, 1, 63, 87, 16, 23, 91, 87, 59, 38, 21, 83]
# 默认是一个把要合并的列表合在一个列表里的二维列表,实际情况另说
list2 = [[x] for x in list1]
# print(len(list2))
# exit(0)
# list1 = [23]
print(list2)
BS = MergeSort(nlist=list2)
# V1方法
start_time = time.time()
BS.sortV1()
print("getlist:",BS.get_list()[0])
V1_time = time.time()
BS.set_list(list_in=list1)
# V2优化方法
# middle_time = time.time()
# BS.sortV2(length=len(list1), first=0)
# print(BS.get_list())
# V2_time = time.time()
print("waste time1: ",V1_time-start_time)
# print("waste time2: ",V2_time-middle_time)
七、堆(heap)排序算法 (!该部分未完全独立思考,参考了部分网络资料)
简单知识:
- 堆是完全二叉树:从上到下,每一层节点都是满的,最下一层所有的节点都连续集中在最左边
- 堆的节点的值≥左右子节点的值,称为大顶堆;节点的值≤左右子节点的值,称为小顶堆
- 不符合上述要求,就不是堆
- 设i是堆N的下标,N[i]的父节点在(i-1)//2,左子节点是2i+1, 右子节点是2i+2
原理: 简单描述:先将数组排成完全二叉树。在最后一个父节点的位置上,与自己的子节点进行比较排序.逐渐排成大小顶堆,然后弹出第一个父节点,将最后一个子节点放到第一个父节点上,重新进行大小顶堆的排序,然后弹出第一个父节点,以此类推。
时间复杂度:O(nlogn)
空间复杂度:O(1)
不稳定
编:二叉树您怎么又在我的脑子里复活啦
# 堆排序
import time
class HeapSort():
# -> 返回类型
def __init__(self, nlist:list) -> list:
self.mylist = nlist
def sortV1(self):
inlist = self.mylist
n = len(inlist) # 数组长度
# 构建最大堆并开始 初次排序
# 从最后一个非叶子节点(最后一个父节点)的索引开始,依次向上调整每个父节点(数组长度除2并向下取整然后减1,就是最后一个父节点)
for i in range(n//2-1, -1, -1): # start,end,step
inlist = self.heapify(inlist, n, i)
# 初次排序后,逐个提取最大堆的元素
# 将根节点与最后一个节点交换,然后继续构建最大堆,并继续排序
for i in range(n-1, 0, -1):
inlist[i], inlist[0] = inlist[0], inlist[i] # 交换根节点和最后一个子节点
# 由于数组已经基本有序,只需要对第一个父节点做堆排序就行。
inlist = self.heapify(inlist, i, 0)
# 设置最终数组
self.set_list(inlist)
def heapify(self, arr, n, i):
# arr 数组, n 数组长度, i当前节点索引
# 对当前节点进行排序
largest = i # 将当前节点设为最大值的索引
left = 2 * i + 1 # 左子节点的索引
right = 2 * i + 2 # 右子节点的索引
# 检查左子节点是否大于当前节点
if left < n and arr[i] < arr[left]:
largest = left
# 检查右子节点是否大于当前节点
if right < n and arr[i] < arr[right]:
largest = right
# 如果最大值发生变化,则进行交换以保持最大堆性质
if largest != i:
arr[i], arr[largest] = arr[largest], arr[i]
# 继续对子节点的子节点进行排序
self.heapify(arr, n, largest)
return arr
def get_list(self):
return self.mylist
def set_list(self, list_in:list):
self.mylist = list_in
if __name__ == '__main__':
list1 = [23, 75, 83, 9, 1, 63, 87, 16, 23, 91, 87, 59, 38, 21, 83]
print("原始数组: ", list1)
# list1 = [23]
BS = HeapSort(nlist=list1)
# V1方法
start_time = time.time()
BS.sortV1()
print("堆排序数组: ",BS.get_list())
V1_time = time.time()
BS.set_list(list_in=list1)
# V2优化方法
# middle_time = time.time()
# BS.sortV2(length=len(list1), first=0)
# print(BS.get_list())
# V2_time = time.time()
print("waste time1: ",V1_time-start_time)
# print("waste time2: ",V2_time-middle_time)
八、计数排序算法
简单知识:
原理: 简单描述:对每个元素出现的次数进行计数,计数的数值放入拥有从0-max的有序数组中的数值。
优化: 将计数数组长度定为max-min+1,
时间复杂度:数组链表:O(n+m) 其中n是数据规模,m就是(max-min+1)
空间复杂度:O(m)
稳定
编:如果不经过优化,用到最小数很大的数组上,那这个计数数组真的占空间
# 计数排序
import time
class CountSort():
# -> 返回类型
def __init__(self, nlist:list) -> list:
self.mylist = nlist
def sortV1(self):
inlist = self.mylist
n = len(inlist) # 数组长度
# 找出数组的最小值和最大值
min_num, max_num = min(inlist), max(inlist)
# 创建一个长度为max_num-min_num+1的计数数组
count_list = [0]*(max_num-min_num+1)
# 遍历原数组,统计每个元素出现的次数。对于一个元素A,将count_list[A-min_num]的值+1
for i in range(n):
count_list[inlist[i]-min_num] += 1
# 创建一个新数组,一个个放进去
new_list = []
# 遍历计数数组,通过索引与最小值相加的方法,逐个将元素填进去,填进去的数量与索引位对应的值相关。
for j in range(len(count_list)):
if count_list[j] != 0: # 如果索引位值不等于0
for k in range(count_list[j]):
new_list.append(min_num+j)
# 设置最终数组
self.set_list(new_list)
def get_list(self):
return self.mylist
def set_list(self, list_in:list):
self.mylist = list_in
if __name__ == '__main__':
list1 = [23, 75, 83, 9, 1, 63, 87, 16, 23, 91, 87, 59, 38, 21, 83]
print("原始顺序数组: ", list1)
# list1 = [23]
BS = CountSort(nlist=list1)
# V1方法
start_time = time.time()
BS.sortV1()
print("计数排序数组: ",BS.get_list())
V1_time = time.time()
BS.set_list(list_in=list1)
# V2优化方法
# middle_time = time.time()
# BS.sortV2(length=len(list1), first=0)
# print(BS.get_list())
# V2_time = time.time()
print("waste time1: ",V1_time-start_time)
# print("waste time2: ",V2_time-middle_time)
九、【重要】桶排序算法
简单知识:
假设数据分布均匀
的情况下,把数据分到有限数量的桶(不同区间)
里,再对每个桶进行其他排序,最后合并所有桶
桶思想:现实世界,大部分数据分布是均匀的,或者说在设计之处就让他分布均匀,那么就可以应用桶排序了
- 在数据量很大的情况下,桶排序的思想会极大提高效率
原理: 简单描述:设置多个有序的桶,每个桶包含一个数据区间,无序数组的元素按这个区间放入各个桶,最后对桶内进行排序
时间复杂度:最好平均:O(n+m), 最坏:O(n^2)
m是桶的数量空间复杂度:O(n+m)
稳定
编:我更想叫他多区间排序
# 桶排序
import time
class BucketSort():
# -> 返回类型
def __init__(self, nlist:list) -> list:
self.mylist = nlist
def sortV1(self):
inlist = self.mylist
n = len(inlist) # 数组长度
# 找出数组的最大值, 作为桶的数量来源, 桶数=(最大值//区间长度)+1
max_num = max(inlist)
bucket_num = max_num // 20 + 1
# print(bucket_num)
# 给我来bucket_num个桶
# buckets = [[]]*bucket_num 会出bug,使用append方法会同时给所有子列表加值
buckets = []
for bn in range(bucket_num):
buckets.append([])
# print(buckets)
# 遍历原数组,把数据按规则一个个放到桶里
for i in range(n):
now_num = inlist[i] # 当前元素
for j in range(bucket_num):
if now_num >= j*20 and now_num< (j+1)*20:
buckets[j].append(now_num) # 放入指定区间的桶
# print(buckets)
# 设置有序数组
new_list = []
# 调用其他排序算法,对每个桶进行排序
for j in range(bucket_num):
self.BubbleSort(arr=buckets[j], length=len(buckets[j]))
# 每个桶排序结束,就把数据从里面倒出来。
new_list.extend(buckets[j])
# 设置最终数组
self.set_list(new_list)
def BubbleSort(self, arr, length):
if length < 2:
return
temp = 0 # 交换位
flag = False # 标志位,如果没发生交换,则可以提前结束排序
for i in range(length - 1): # -1, 防止越界
if arr[i] > arr[i+1]:
flag = True
temp = arr[i+1]
arr[i+1] = arr[i]
arr[i] = temp
if flag == False:
return
self.BubbleSort(arr=arr, length=length-1)
def get_list(self):
return self.mylist
def set_list(self, list_in:list):
self.mylist = list_in
if __name__ == '__main__':
list1 = [23, 75, 83, 9, 1, 63, 87, 16, 23, 91, 87, 59, 38, 21, 83]
print("原顺序数组: ", list1)
# list1 = [23]
BS = BucketSort(nlist=list1)
# V1方法
start_time = time.time()
BS.sortV1()
print("桶排序数组: ", BS.get_list())
V1_time = time.time()
BS.set_list(list_in=list1)
# V2优化方法
# middle_time = time.time()
# BS.sortV2(length=len(list1), first=0)
# print(BS.get_list())
# V2_time = time.time()
print("waste time1: ",V1_time-start_time)
# print("waste time2: ",V2_time-middle_time)
十、【重要】基数排序算法
简单知识:桶排序从区间分配升级到个位十位百位逐个比较分配。
- 桶排序升级版
原理: 简单描述:先比较个位大小,放入每个桶,然后排序;接着比较十位大小,同理以此类推到结束
时间复杂度:数组链表:O(k*n) 这里的k就是最大值的最高位次,比如千位,k就是3
空间复杂度:O(n+k)
稳定
# 桶排序
import time
class RadixSort():
# -> 返回类型
def __init__(self, nlist:list) -> list:
self.mylist = nlist
def sortV1(self):
inlist = self.mylist
n = len(inlist) # 数组长度
max_num = max(inlist) # 找到最大值,看一下他是几位数,就要比到他的最高位
compare_bit = len(str(max_num))
# 基数排序每次排序桶的数量都是10,编:那肯定的,十进制数
bucket_num = 10
# 最终数组
new_list = []
# 遍历原数组,把数据按规则一个个放到桶里: 这里是按个位(排序一次)->十位(排序一次)->百位(排序一次)这样比较下去...
# 从个位开始遍历
for bitdx in range(1, compare_bit+1):
# 每一次遍历都要更新桶
# buckets = [[]]*bucket_num 会出bug,使用append方法会同时给所有子列表加值
buckets = []
for bn in range(bucket_num):
buckets.append([])
# 遍历原数组
for i in range(n):
# 如果遍历到的元素没有bitdx位<==>就不需要排序
if len(str(inlist[i])) < bitdx:
new_list.append(inlist[i]) # 进入最终数组然后直接跳过当前循环
continue # 跳过这个元素
else:
now_num = int(str(inlist[i])[-bitdx]) # 取出当前元素的bitdx位
buckets[now_num].append(inlist[i]) # 放入指定区间的桶
print(bitdx, "==>", buckets)
# 设置有序数组
inlist = []
for j in range(bucket_num):
# 每个桶排序结束,就把数据从里面倒出来。
inlist.extend(buckets[j])
# 最后做一次倒桶
for j in range(bucket_num):
new_list.extend(buckets[j])
# 设置数组
self.set_list(new_list)
def get_list(self):
return self.mylist
def set_list(self, list_in:list):
self.mylist = list_in
if __name__ == '__main__':
list1 = [23, 75, 83, 9, 1, 63, 87, 16, 23, 91, 87, 59, 38, 21, 83]
print("原顺序数组: ", list1)
# list1 = [23]
BS = RadixSort(nlist=list1)
# V1方法
start_time = time.time()
BS.sortV1()
print("桶排序数组: ", BS.get_list())
V1_time = time.time()
BS.set_list(list_in=list1)
# V2优化方法
# middle_time = time.time()
# BS.sortV2(length=len(list1), first=0)
# print(BS.get_list())
# V2_time = time.time()
print("waste time1: ",V1_time-start_time)
# print("waste time2: ",V2_time-middle_time)
总结:终于写完了,花了三天,再花点时间理解一下空间复杂度和时间复杂度
更新等: