python实现十大经典排序算法
Python实现十大经典排序算法
代码最后面会给出完整版,或者可以从我的Githubfork,想看动图的同学可以去这里看看;
小结:
- 运行方式,将最后面的代码copy出去,直接python sort.py运行即可;
- 代码中的健壮性没有太多处理,直接使用的同学还要检查检查;
- 对于希尔排序,gap的选择至关重要,需要结合实际情况更改;
- 在我的测试中,由于待排序数组很小,长度仅为10,且最大值为10,因此计数排序是最快的,实际情况中往往不是这样;
- 堆排序没来得及实现,是的,就是懒了;
- 关键在于理解算法的思路,至于实现只是将思路以合理的方式落地而已;
- 推荐大家到上面那个链接去看动图,确实更好理解,不过读读代码也不错,是吧;
- 分治法被使用的很多,事实上我不太清楚它背后的数学原理是什么,以及为什么分治法可以降低时间复杂度,有同学直到麻烦评论区告诉我一下哈,多谢;
运行图
由于数组小,且范围在1到10之间,这其实对于计数排序这种非比较类算法是比较友好的,因为没有多大的空间压力,因此计数排序速度第一很容易理解,而之所以选择、插入比希尔归并要快,主要还是因为问题规模本身太小,而我的分治法的实现是基于递归,因此看不出分治法的优势,事实上如果对超大的数组进行排序的话,这个区别会体现出来;
完整代码
可以看到,全部代码不包括测试代码总共才170行,这还包括了空行和函数名等等,所以本身算法实现是很简单的,大家还是要把注意力放在思路上;
import sys,random,time
def bubble(list_):
running = True
while running:
have_change = False
for i in range(len(list_)-1):
if list_[i]>list_[i+1]:
list_[i],list_[i+1] = list_[i+1],list_[i]
have_change = True
if not have_change:
break
return list_
def select(list_):
for i in range(len(list_)-1):
min_idx = i
for j in range(i,len(list_)):
if list_[min_idx]>list_[j]:
min_idx = j
list_[i],list_[min_idx] = list_[min_idx],list_[i]
return list_
def insert(list_):
for i in range(1,len(list_)):
idx = i
for j in range(i):
if list_[j]>list_[idx]:
idx = j
break
if idx != i:
tmp = list_[i]
list_[idx+1:i+1] = list_[idx:i]
list_[idx] = tmp
return list_
def shell(list_,gap=None):
'''
gap的选择对结果影响很大,是个难题,希尔本人推荐是len/2
这个gap其实是间隙,也就是间隔多少个元素取一组的元素
例如对于[1,2,3,4,5,6,7,8,9,10]
当gap为len/2也就是5时,每一组的元素都是间隔5个的元素组成,也就是1和6,2和7,3和8等等
'''
len_ = len(list_)
gap = int(len_/2) if not gap else gap
while gap >= 1:
for i in range(gap):
list_[i:len_:gap] = insert(list_[i:len_:gap])
gap = int(gap/2)
return list_
def merge(list_):
'''
归并排序的递归实现
思路:将数据划分到每两个为一组为止,将这两个排序后范围,2个包含2个元素的组继续排序为1个4个元素的组,
直到回溯到整个序列,此时其实是由两个有序子序列组成的,典型的递归问题
'''
if len(list_)<=1:
return list_
if len(list_)==2:
return list_ if list_[0]<=list_[1] else list_[::-1]
len_ = len(list_)
left = merge(list_[:int(len_/2)])
right = merge(list_[int(len_/2):])
tmp = []
left_idx,right_idx = 0,0
while len(tmp)<len(list_):
if left[left_idx]<=right[right_idx]:
tmp.append(left[left_idx])
left_idx+=1
if left_idx==len(left):
tmp += right[right_idx:]
break
else:
tmp.append(right[right_idx])
right_idx+=1
if right_idx==len(right):
tmp += left[left_idx:]
break
return tmp
def quick(list_):
'''
快速排序:基于分治法,选定某个元素为基准,对剩余元素放置到基准的左侧和右侧,递归这个过程
'''
if len(list_)<=1:
return list_
if len(list_)==2:
return list_ if list_[0]<=list_[1] else list_[::-1]
base_idx = int(len(list_)/2)
base = list_[base_idx]
left = []
right = []
for i in range(len(list_)):
if i != base_idx:
if list_[i] <= base:
left.append(list_[i])
else:
right.append(list_[i])
return quick(left)+[base]+quick(right)
def count(list_):
'''
需要元素都是整型
'''
min_,max_ = list_[0],list_[0]
for i in range(1,len(list_)):
if list_[i]<min_:
min_ = list_[i]
if list_[i]>max_:
max_ = list_[i]
count_list = [0]*(max_-min_+1)
for item in list_:
count_list[item-min_] += 1
list_ = []
for i in range(len(count_list)):
for j in range(count_list[i]):
list_.append(i+min_)
return list_
def heap(list_):
'''
'''
pass
def bucket(list_):
'''
每个桶使用选择排序,分桶方式为最大值除以5,也就是分为5个桶
桶排序的速度取决于分桶的方式
'''
bucket = [[],[],[],[],[]] # 注意长度为5
max_ = list_[0]
for item in list_[1:]:
if item > max_:
max_ = item
gap = max_/5 # 对应bucket的长度
for item in list_:
bucket[int((item-1)/gap)].append(item)
for i in range(len(bucket)):
bucket[i] = select(bucket[i])
list_ = []
for item in bucket:
list_ += item
return list_
def radix(list_):
'''
基数排序:对数值的不同位数分别进行排序,比如先从个位开始,然后十位,百位,以此类推;
注意此处代码是假设待排序数值都是整型
'''
max_ = list_[0]
for item in list_[1:]:
if item > max_:
max_ = item
max_radix = len(str(max_))
radix_list = [[],[],[],[],[],[],[],[],[],[]] # 对应每个位上可能的9个数字
cur_radix = 0
while cur_radix<max_radix:
base = 10**cur_radix
for item in list_:
radix_list[int(item/base)%10].append(item)
list_ = []
for item in radix_list:
list_ += item
radix_list = [[],[],[],[],[],[],[],[],[]] # 对应每个位上可能的9个数字
cur_radix += 1
return list_
def test(name,sort_func,times,info,idea,*param):
list_ = [1,2,3,4,5,6,7,8,9,10]
print(name+' Sort:')
print('\t'+info)
print('\t'+idea)
print('\tTimes: '+str(times))
start_time = time.time()
for i in range(times):
random.shuffle(list_)
#print('\tInput: '+str(list_))
list_ = sort_func(list_) if len(param)<=0 else sort_func(list_,param[0])
#print('\tOutput: '+str(list_))
#print('\t'+str(list_))
print('\tCost time: '+str(time.time()-start_time))
if __name__ == "__main__":
test('Bubble',bubble,100000,'O(n^2), O(1), 稳定, 比较排序','思路: 循环的从头向后遍历,直到没有需要交换位置的两个元素为止')
test('Select',select,100000,'O(n^2), O(1), 不稳定, 比较排序','思路: 从头到尾依次将后续序列中最小的数字放到当前位置')
test('Insert',insert,100000,'O(n^2), O(1), 稳定, 比较排序','思路: 从头到尾将每个元素插入到前面的已排序序列中合适的位置,插入后后面的元素都向后移动')
test('Shell(gap=len/2)',shell,100000,'O(nlogn), O(1), 不稳定, 比较排序','思路: 将序列根据gap分组,并不断细分直到只有1,每个组使用直接插入排序,有点分治法的意思,gap的选择是个难题,通常默认为len/2')
test('Shell(gap=3)',shell,100000,'O(nlogn), O(1), 不稳定, 比较排序','思路: 将序列根据gap分组,并不断细分直到只有1,每个组使用直接插入排序,有点分治法的意思,gap的选择是个难题,通常默认为len/2',3)
test('Shell(gap=2)',shell,100000,'O(nlogn), O(1), 不稳定, 比较排序','思路: 将序列根据gap分组,并不断细分直到只有1,每个组使用直接插入排序,有点分治法的意思,gap的选择是个难题,通常默认为len/2',2)
test('Merge',merge,100000,'O(nlogn), O(n), 稳定, 比较排序','思路: 基于分治法进行归并操作,既然是分治法,那么用递归解决是最简单的实现')
test('Quick',quick,100000,'O(nlogn), O(logn), 不稳定, 比较排序','思路: 同样基于分治法,通过指定某个元素为基准,小于基准的放到左边序列,大于的放到右边,递归的使左右序列有序即可')
# test('Heap',heap,100000,'O(nlogn), O(1), 不稳定, 比较排序','思路: 利用堆的性质构建完全二叉树')
test('Count',count,100000,'O(n+k), O(k), 稳定, 非比较排序','思路: 构造数组用于存储待排序数组中各个元素的个数,元素值作为新数组的下标')
test('Bucket',bucket,100000,'O(n+k), O(n+k), 稳定, 非比较排序','思路: 将元素根据某种规则映射到N个桶中,对每个桶进行排序后,将各个桶内元素依次读出来即可')
test('Radix',radix,100000,'O(n*k), O(n+k), 稳定, 非比较排序','思路: 针对各个元素的某一位依次进行排序,直到最高位为止')
# print(heap([4,6,8,3,5,10,9,2,1,7]))
最后
大家可以到我的Github上看看有没有其他需要的东西,目前主要是自己做的机器学习项目、Python各种脚本工具、有意思的小项目以及Follow的大佬、Fork的项目等:
https://github.com/NemoHoHaloAi
python实现十大经典排序算法的更多相关文章
- 用Python实现十大经典排序算法-插入、选择、快速、冒泡、归并等
本文来用图文的方式详细讲解了Python十大经典排序算法 —— 插入排序.选择排序.快速排序.冒泡排序.归并排序.希尔排序.插入排序.桶排序.基数排序.计数排序算法,想要学习的你们,继续阅读下去吧,如 ...
- Python实现十大经典排序算法(史上最简单)。
十大排序算法(Python实现)一. 算法介绍及相关概念解读 算法分类十种常见排序算法可以分为两大类: 非线性时间比较类排序:通过比较来决定元素间的相对次序,由于其时间复杂度不能突破O(nlogn), ...
- Python实现十大经典排序算法(史上最简单)
十大排序算法(Python实现)一. 算法介绍及相关概念解读 算法分类十种常见排序算法可以分为两大类: 非线性时间比较类排序:通过比较来决定元素间的相对次序,由于其时间复杂度不能突破O(nlogn), ...
- python基础__十大经典排序算法
用Python实现十大经典排序算法! 排序算法是<数据结构与算法>中最基本的算法之一.排序算法可以分为内部排序和外部排序,内部排序是数据记录在内存中进行排序,而外部排序是因排序的数据很大, ...
- 十大经典排序算法(python实现)(原创)
个人最喜欢的排序方法是非比较类的计数排序,简单粗暴.专治花里胡哨!!! 使用场景: 1,空间复杂度 越低越好.n值较大: 堆排序 O(nlog2n) O(1) 2,无空间复杂度要求.n值较大: 桶排序 ...
- 十大经典排序算法最强总结(含Java、Python码实现)
引言 所谓排序,就是使一串记录,按照其中的某个或某些关键字的大小,递增或递减的排列起来的操作.排序算法,就是如何使得记录按照要求排列的方法.排序算法在很多领域得到相当地重视,尤其是在大量数据的处理方面 ...
- 十大经典排序算法+sort排序
本文转自:十大经典排序算法,其中有动图+代码详解,本文简单介绍+个人理解. 排序算法 经典的算法问题,也是面试过程中经常被问到的问题.排序算法简单分类如下: 这些排序算法的时间复杂度等参数如下: 其中 ...
- 十大经典排序算法的 JavaScript 实现
计算机领域的都多少掌握一点算法知识,其中排序算法是<数据结构与算法>中最基本的算法之一.排序算法可以分为内部排序和外部排序,内部排序是数据记录在内存中进行排序,而外部排序是因排序的数据很大 ...
- JavaScript 数据结构与算法之美 - 十大经典排序算法汇总(图文并茂)
1. 前言 算法为王. 想学好前端,先练好内功,内功不行,就算招式练的再花哨,终究成不了高手:只有内功深厚者,前端之路才会走得更远. 笔者写的 JavaScript 数据结构与算法之美 系列用的语言是 ...
随机推荐
- opencv +数字识别
现在很多场景需要使用的数字识别,比如银行卡识别,以及车牌识别等,在AI领域有很多图像识别算法,大多是居于opencv 或者谷歌开源的tesseract 识别. 由于公司业务需要,需要开发一个客户端程序 ...
- preload & prefetch
原文地址在 我的笔记里,觉得还行就给个 star 吧:) 关于 preload 和 prefetch 早有耳闻,知道它们可以优化页面加载速度,然具体情况却了解不多.搜索了相关的资料后对其有了些认识,在 ...
- ES6的编程风格
1,建议使用let替代var 2,全局常量使用const,多使用const有利于提高程序的运行效率. const有两个好处:一是阅读代码的人立刻会意识到不应该修改这个值,二是防止无意间修改变量值导致错 ...
- 关于js拖放功能的实现
这是具体的拖放代码的HTML,里面依赖两个组件:EventUtil.js是兼容浏览器添加方法的库,EventTarget.js是一个发布-订阅者模式的对象库. EventUtil.js: var Ev ...
- Markdown中插入复杂的合并表格方法
由于Markdown自身的语法限制,不能直接插入有合并单元格的复杂表格. 姓名 学号 专业 张三 2018123456 计算机 赵四 2018222356 自动化 李六 2018666666 信息工程 ...
- 使用twisted将mysql插入变成异步执行
python 异步MySQL存库 对于异步框架而言,这些延迟是无法接受的.因此, Twisted 提供了 twisted.enterprise.adbapi, 遵循DB-API 2.0协议的一个异 ...
- 鸡汤 & 毒鸡汤
1.别低估任何人. 2.你没那么多观众,别那么累. 3.温和对人对事.不要随意发脾气,谁都不欠你的. 4.现在很痛苦,等过阵子回头看看,会发现其实那都不算事. 5.和对自己有恶意的人绝交.人有绝交,才 ...
- jadx初识
一.jadx介绍 一款相对流行的反编译工具 下载:https://github.com/skylot/jadx/releases/tag/v1.0.0 解压后得到这么几个文件: 启动:(以下来两个文件 ...
- vscode 对于 md的编写 左侧 大纲 很重要!!
vscode 对于 md的编写 左侧 大纲 很重要!!
- Linux进程间通信-eventfd
Linux进程间通信-eventfd eventfd是linux 2.6.22后系统提供的一个轻量级的进程间通信的系统调用,eventfd通过一个进程间共享的64位计数器完成进程间通信,这个计数器由在 ...