原标题:Python实现排序算法
前言冒泡排序快速排序插入排序希尔排序选择排序堆排序归并排序计数排序桶排序基数排序
前言
本章介绍使用Python实现场景的几种排序算法。分别有冒泡算法、快速排序、插入排序、希尔排序、选择排序、堆排序、归并排序、计数排序、桶排序、基数排序。
创建一个比较大的list,用于测试排序算法使用。
importnumpy asnp
importtime
src_list = np.random.randint( 1, 100000, ( 50000)).tolist
冒泡排序
冒泡排序是一种简单直观的排序算法。它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。这个算法的名字由来是因为越小的元素会经由交换慢慢"浮"到数列的顶端。
defbubble_sort(arr):
n = len(arr)
fori inrange(n -1):
forj inrange( 0, n -1-i):
ifarr[j] > arr[j+ 1] :
arr[j], arr[j+ 1] = arr[j+ 1], arr[j]
returnarr
start = time.time
result = bubble_sort(src_list)
end = time.time
print( "耗时:%d 毫秒"% int(round((end - start) * 1000)))
耗时:197286 毫秒
快速排序
在一个数据集中取个数作为参考点,大于该数的元素放在其右边;小于该数的元素放在其左边。这样就将数据集分成两部分,大于参考值部分和小于参考值部分,递归该过程,直到序列中所有记录均有序。
defquick_sort(listt, left, right):
ifleft >= right:
returnlistt
# 选择参考点,该调整范围的第1个值
pivot = listt[left]
low = left
high = right
whileleft < right:
# 从右边开始查找大于参考点的值
whileleft < right andlistt[right] >= pivot:
right -= 1
# 这个位置的值先挪到左边
listt[left] = listt[right]
# 从左边开始查找小于参考点的值
whileleft < right andlistt[left] <= pivot:
left += 1
# 这个位置的值先挪到右边
listt[right] = listt[left]
# 写回改成的值
listt[left] = pivot
# 递归,并返回结果
quick_sort(listt, low, left - 1) # 递归左边部分
quick_sort(listt, left + 1, high) # 递归右边部分
returnlistt
start = time.time
result = quick_sort(src_list, 0, 1000)
end = time.time
print( "耗时:%d 毫秒"% int(round((end - start) * 1000)))
耗时:43 毫秒
插入排序
插入排序是一种简单直观的排序算法。它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入
definsert_sort(alist):
length = len(alist)
fori inrange( 1,length):
forj inrange(i, 0, -1):
ifalist[j] < alist[j - 1]:
alist[j], alist[j - 1] = alist[j - 1], alist[i]
else:
break
returnalist
start = time.time
result = insert_sort(src_list)
end = time.time
print( "耗时:%d 毫秒"% int(round((end - start) * 1000)))
耗时:20 毫秒
希尔排序
希尔排序,也称递减增量排序算法,是插入排序的一种更高效的改进版本。但希尔排序是非稳定排序算法。希尔排序的基本思想是:先将整个待排序的记录序列分割成为若干子序列分别进行直接插入排序,待整个序列中的记录"基本有序"时,再对全体记录进行依次直接插入排序。
defshell_sort(alist):
n = len(alist)
gap = n // 2
whilegap >= 1:
fori inrange(gap,n):
while(i - gap) >= 0:
ifalist[i] < alist[i-gap]:
alist[i], alist[i-gap] = alist[i-gap], alist[i]
i = i - gap
else:
break
gap = gap // 2
returnalist
start = time.time
result = shell_sort(src_list)
end = time.time
print( "耗时:%d 毫秒"% int(round((end - start) * 1000)))
耗时:110 毫秒
选择排序
选择排序是一种简单直观的排序算法。它的工作原理:首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。
defselect_sort(alist):
n = len(alist)
fori inrange(n):
# 设置索引 i为最小值的索引
min_idx = i
# 通过比较,不断调整最小值的索引位置
forj inrange(i,n):
ifalist[j] < alist[min_idx]:
min_idx = j
# 交换第i个值与最小值
alist[i], alist[min_idx] = alist[min_idx], alist[i]
returnalist
start = time.time
result = select_sort(src_list)
end = time.time
print( "耗时:%d 毫秒"% int(round((end - start) * 1000)))
耗时:101479 毫秒
堆排序
堆排序(Heapsort)是指利用堆这种数据结构所设计的一种排序算法。堆是一个近似完全二叉树的结构,并同时满足堆的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。堆排序可以说是一种利用堆的概念来排序的选择排序。
# 调整堆的结构,使其父节点的值大于子节点的值
defmax_heap(heap, heapsize, root):
left = 2*root+ 1
right = left + 1
large = root
ifleft < heapsize andheap[large] < heap[left]:
large = left
ifright < heapsize andheap[large] < heap[right]:
large = right
# 若large=right或large=left,则说明,出现比父节点大的子节点,这时对调,使子节点变为父节点
iflarge != root:
heap[large], heap[root] = heap[root], heap[large]
max_heap(heap, heapsize, large)
# 构造一个堆,对堆中数据重新排序
defbuild_max_heap(heap):
length = len(heap)
# 从后往前调整结构
fori inrange((length -2)// 2, -1, -1):
max_heap(heap, length, i)
# 将根节点取出与最后一位对调,对前面len-1个节点继续进行对调过程
defheap_sort(heap):
build_max_heap(heap)
fori inrange(len(heap) -1, -1, -1):
heap[ 0], heap[i] = heap[i], heap[ 0]
max_heap(heap,i, 0)
returnheap
start = time.time
result = heap_sort(src_list)
end = time.time
print( "耗时:%d 毫秒"% int(round((end - start) * 1000)))
耗时:334 毫秒
归并排序
归并排序(mergesort)是创建在归并操作上的一种有效的排序算法,该算法是采用分治法的一个非常典型的应用。
分治法:
分割:递归地把当前序列平均分割成两半
集成:在保持元素顺序的同时将上一步得到的子序列集成到一起(归并)
defmerge_sort(alist):
iflen(alist) < 2:
returnalist
# 将列表分成更小的两个列表
mid = int(len(alist)/ 2)
# 分别对左右两个列表进行处理,分别返回两个排序好的列表
left = merge_sort(alist[:mid])
right = merge_sort(alist[mid:])
# 对排序好的两个列表合并,产生一个新的排序好的列表
returnmerge(left,right)
defmerge(left,right):
i = 0
j = 0
result = []
whilei < len(left) andj < len(right):
ifleft[i] < right[j]:
result.append(left[i])
i += 1
else:
result.append(right[j])
j += 1
result += left[i:]
result += right[j:]
returnresult
start = time.time
result = merge_sort(src_list)
end = time.time
print( "耗时:%d 毫秒"% int(round((end - start) * 1000)))
耗时:163 毫秒
计数排序
计数排序的核心在于将输入的数据值转化为键存储在额外开辟的数组空间中。作为一种线性时间复杂度的排序,计数排序要求输入的数据必须是有确定范围的整数。
对每一个输入的元素a[i],确定小于 a[i] 的元素个数。所以可以直接把 a[i] 放到它输出数组中的位置上。假设有5个数小于 a[i],所以 a[i] 应该放在数组的第6个位置上
defcount_sort(alist):
# 找到最大最小值
min_num = min(alist)
max_num = max(alist)
# 初始化计数列表
count_list = [ 0]*(max_num-min_num+ 1)
# 对列表中的每一个元素计数
fornum inalist:
count_list[num-min_num] += 1
alist.clear
# 当某个元素的个数不为 0,将该元素填回alist列表
forcur_num, count inenumerate(count_list):
whilecount != 0:
alist.append(cur_num+min_num)
count -= 1
returnalist
start = time.time
result = count_sort(src_list)
end = time.time
print( "耗时:%d 毫秒"% int(round((end - start) * 1000)))
耗时:20 毫秒
桶排序
把数组a划分为n个大小相同子区间(桶),每个子区间各自排序,最后合并。桶排序要求数据的分布必须均匀,不然可能会失效。计数排序是桶排序的一种特殊情况,可以把计数排序当成每个桶里只有一个元素的情况。
原理:
(1) 设置一个定量的数组当作空桶
(2) 遍历输入数据,并且把数据一个一个放到对应的桶里去
(3) 对每个不是空的桶进行排序
(4) 从不是空的桶里把排好序的数据拼接起来
defbucket_sort(alist):
min_num = min(alist)
max_num = max(alist)
# 设置桶的大小
bucket_size = (max_num - min_num)/len(alist)
# 创建桶数组
bucket_list = [[] fori inrange(len(alist)+ 1)]
# 向桶数组填数
fornum inalist:
bucket_list[int((num-min_num)//bucket_size)].append(num)
alist.clear
# 回填,这里桶内部排序直接调用了sorted
fori inbucket_list:
forj insorted(i):
alist.append(j)
returnalist
start = time.time
result = bucket_sort(src_list)
end = time.time
print( "耗时:%d 毫秒"% int(round((end - start) * 1000)))
耗时:61 毫秒
基数排序
基数排序的总体思路就是将待排序数据拆分成多个关键字进行排序,也就是说,基数排序的实质是多关键字排序,比如说成绩的排序,如果两个人总分相同,则语文高的排在前面,语文成绩也相同则数学高的排在前面,如果对数字进行排序,那么个位、十位、百位就是不同优先级的关键
原理:
(1) 取得数组中的最大数,并取得位数
(2) 建立桶数组
(3) 按位数的大小分别装进不同的桶里
(4) 将原数组清空,将各个桶里的数据依次添加进原列表
(5) 再进行前一位的排序,依次循环,直到排序的位数大于最大值的位数
defradix_sort(alist):
# 记录正在对哪一位进行排序,最低位为个位
i = 0
# 最大值的位数
max_num = max(alist)
j = len(str(max_num))
whilei < j:
# 建立桶数组,数字为0-9,所以建10个桶
bucket_list = [[] fori inrange( 10)]
# 按位数的大小分别装进不同的桶里
fornum inalist:
bucket_list[int(num/( 10**i)% 10)].append(num)
#将原列表清空,将各个桶里的数据依次添加进原列表
alist.clear
forl inbucket_list:
forb inl:
alist.append(b)
# 再进行前一位的排序,依次循环,直到排序的位数大于最大值的位数
i += 1
returnalist
start = time.time
result = radix_sort(src_list)
end = time.time
print( "耗时:%d 毫秒"% int(round((end - start) * 1000)))
耗时:123 毫秒 返回搜狐,查看更多
责任编辑: