已知数据结构中有多种算法,现在参考比较多方来源,总结出python版的排序算法的实现,一方面是为了总结,另外一方面也是温故知新。
具体参考:1.《漫画算法--小灰的算法之旅》
2. CSDN博客:《八大排序算法》
下面首先来看下本文中所列出的几种算法的时间空间复杂度和稳定性
排序算法 | 平均时间复杂度 | 最坏时间复杂度 | 空间复杂度 | 稳定性 |
冒泡排序 | 稳定 | |||
鸡尾酒排序 | 稳定 | |||
快速排序 | 不稳定 | |||
堆排序 | 不稳定 | |||
桶排序 | 稳定 |
下面分别来看
class Sort(object):
def __init__(self,li=[]):
self.li = li
# 首先要判断列表非为空
if len(self.li) == 0:
raise Exception("Please add some elements in the array.")
def bubble_sort(self):
'''
冒泡排序法,思想是逐个比较,算法复杂度为O(n^2),空间复杂度O(1),稳定
'''
blist = self.li
for i in range(len(blist)):
for j in range(len(blist)-i-1):
if blist[j] > blist[j+1] :
# 比较大小,最大的冒泡到最上面
blist[j+1],blist[j] = blist[j],blist[j+1]
return blist
def insert_sort(self):
'''
插入排序法,将一个数据插入到已经排好序的有序数据中,从而得到一个新的、个数加一的有序数据,算法适用于少量数据的排序;
首先将第一个作为已经排好序的,然后每次从后的取出插入到前面并排序;
时间复杂度为O(n^2),空间复杂度为O(1),稳定
'''
ilist = self.li
for i in range(len(ilist)):
for j in range(i):
if ilist[i] < ilist[j]:
ilist.insert(j, ilist.pop(i))
break
return ilist
def cock_sort(self):
'''
鸡尾酒排序法,思路类似于冒泡排序,区别在于比较和交换是双向的
时间复杂度为O(n^2),空间复杂度为O(),稳定
'''
clist = self.li
for i in range(len(clist) // 2):
isSorted = True
# 奇数轮,从左向右比较和交换
for j in range(len(clist)-i-1):
if clist[j] > clist[j+1]:
clist[j+1],clist[j] = clist[j],clist[j+1]
isSorted = False
if isSorted:
break
# 偶数轮,从右向左比较和交换
isSorted = True
for j in reversed(len(clist)-i-1):
if clist[j] < clist[j - 1]:
clist[j - 1], clist[j] = clist[j], clist[j - 1]
isSorted = False
if isSorted:
break
return clist
def quick_sort(self,qlist=[]):
'''
快速排序法,思路为通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小
整个思路是通过递归实现
时间复杂度为O(nlog(n)),空间复杂度为O(nlog(n)),不稳定
'''
# qlist = self.li
if qlist == []:
return []
else:
qfirst = qlist[0]
qless = self.quick_sort([l for l in qlist[1:] if l < qfirst])
qmore = self.quick_sort([m for m in qlist[1:] if m >= qfirst])
return qless + [qfirst] + qmore
def heap_sort(self):
'''
堆排序,它是选择排序的一种。可以利用数组的特点快速定位指定索引的元素。
堆分为大根堆和小根堆,是完全二叉树。大根堆的要求是每个节点的值都不大于其父节点的值,即A[PARENT[i]] >= A[i]。
在数组的非降序排序中,需要使用的就是大根堆,因为根据大根堆的要求可知,最大的值一定在堆顶
堆排序的时间复杂度为O(nlog(n)),空间复杂度为O(1),不稳定
'''
import copy
def heap_adjust(parent):
child = 2 * parent + 1 # left child
while child < len(heap):
if child + 1 < len(heap): # 判断右节点是否存在
if heap[child + 1] > heap[child]: #右孩子是否大于左孩子?
child += 1 # right child
if heap[parent] >= heap[child]:
break
# 如果父节点的指比左右孩子中最大的要小, 父节点和最大子节点交换
# 然后将下沉的父节点与再下一层的左右子节点比较
heap[parent], heap[child] = heap[child], heap[parent]
parent, child = child, 2 * child + 1
heap, hlist = copy.copy(self.li), []
# 构建最大二叉堆
for i in range(len(heap) // 2, -1, -1):
heap_adjust(i)
while len(heap) != 0:
heap[0], heap[-1] = heap[-1], heap[0]
# hlist.append(heap.pop()) # 从堆中取最大值,赋给数组的最后一位--result:从大到小排序
hlist.insert(0,heap.pop())# 从堆取最大值,赋给数组的第一位--result:从小到大排序
heap_adjust(0)
return hlist
DEFAULT_BUCKET_SIZE = 5 # 桶的个数,这个可以自己定义,也可以根据数组的情况来确定
def bucket_sort(self,bucket_size=DEFAULT_BUCKET_SIZE):
'''
桶排序,思路为将n个元素分到m个空桶里,分别进行排序然后拼接
时间复杂度为O(n),空间复杂度为O(n),稳定
'''
blist = self.li
# 统计各项定义
max_item,min_item = max(blist),min(blist)
#初始化
# 具体要建立多少桶,确定桶的区间范围,有多种方式
# 区间跨度 =(最大值-最小值)/桶的数量+1
count_size = (max_item-min_item)//bucket_size+1
print('count_size:',count_size)
bucket_list = [[ ] for _ in range(count_size)]
# 把各个元素放入桶中
for i in range(len(blist)):
i_num = (blist[i]-min_item)//bucket_size
bucket_list[i_num].append(blist[i])
# 对桶中的元素进行排序
for i in range(len(bucket_list)):
bucket_list[i].sort()
# 输出全部元素
sort_list = [i for i in bucket_list]
print(sort_list)
sorted_list = [item for index in bucket_list for item in index]
return sorted_list
if __name__ == "__main__":
list1 = [1,2,5,4,16,3,12,10]
# list1 = [4,5,6,7,3,2,6,9,8]
# list1 = [3,5,7,24,67,45,32,56,17,20]
print('list1 = ',list1)
new_s = Sort(list1)
s = new_s.bubble_sort()
print('冒泡排序法: ',s)
cock_s = new_s.cock_sort()
print('鸡尾酒排序法: ',cock_s)
insert_s = new_s.insert_sort()
print('插入排序法: ',insert_s)
quick_s = new_s.quick_sort(list1)
print('快速排序法:',quick_s)
heap_s = new_s.heap_sort()
print('堆排序法:',heap_s)
bucket_s = new_s.bucket_sort()
print('桶排序法:',bucket_s)