排序

关注公众号“轻松学编程”了解更多。

1、冒泡排序

基本思想:比较相邻的元素大小,将小的前移,大的后移,就像水中的气泡一样,最小的元素经过几次移动,会最终浮到水面上。原地排序,不需要返回值。

import random
import time def bubbleSort(list1):
for i in range(len(list1)-1):
for j in range(i+1,len(list1)):
if list1[i] > list1[j]:
list1[i],list1[j] = list1[j],list1[i] list1 = [random.randint(1,999) for i in range(10000)]
list11 = list1.copy()
start1 = time.clock()
bubbleSort(list1)
end1 = time.clock()
print("冒泡排序 ",end1 - start1) start2 = time.clock()
list4 = sorted(list11)
end2 = time.clock()
print("函数sorted排序",end2-start2)
print("排序结果",list1==list4)

输出:
冒泡排序 9.2384
函数sorted排序 0.0041
排序结果 True

2、选择排序

基本思想:第1趟,在待排序记录r1 ~ r[n]中选出最小的记录,
将它与r1交换;第2趟,在待排序记录r2 ~ r[n]中选出最小的记录,
将它与r2交换;以此类推,第i趟在待排序记录r[i] ~ r[n]中选出最小的记录,
将它与r[i]交换,使有序序列不断增长直到全部排序完毕。
原地排序,不需要返回值。

import random
import time def selectSort(list1):
for i in range(len(list1)-1):
min = i #已排序好的序列的最后一个元素的下标i
for j in range(i+1,len(list1)):
if list1[min] > list1[j]: #找出未排序的序列中最小的元素的下标min
min = j
if min != i: # 对应的元素值交换
list1[i], list1[min] = list1[min], list1[i] list1 = [random.randint(1,999) for i in range(10000)]
list11 = list1.copy()
start1 = time.clock()
selectSort(list1)
end1 = time.clock()
print("选择排序 ",end1 - start1) start2 = time.clock()
list4 = sorted(list11)
end2 = time.clock()
print("函数sorted排序",end2-start2)
print("排序结果",list1==list4)

输出:
选择排序 7.4946
函数sorted排序 0.0040
排序结果 True

3、插入排序

插入排序总结:

当前需要排序的元素(array[i]),跟已经排序好的最后一个元素比较(array[i-1]),
如果满足条件继续执行后面的程序,否则循环到下一个要排序的元素。
缓存当前要排序的元素的值,以便找到正确的位置进行插入。
排序的元素跟已经排序好的元素比较,比它大的向后移动(升序)。
要排序的元素,插入到正确的位置。

import random
import time def insertSort(list1):
for i in range(1,len(list1)):
if list1[i] < list1[i-1]: #当前要排序的元素比前面的小
index = i #保存当前元素的下标,这个变量是用来记录排序元素需要插入的位置
temp = list1[i] #保存当前元素的值
while index > 0 and list1[index-1] > temp: #找到正确的排序位置
list1[index] = list1[index-1] #如果前面的比当前元素值大,就往后移动一位
index -= 1
if index != i:
list1[index] = temp list1 = [random.randint(1,999) for i in range(10000)]
list11 = list1.copy()
start1 = time.clock()
insertSort(list1)
end1 = time.clock()
print("插入排序 ",end1 - start1) start2 = time.clock()
list4 = sorted(list11)
end2 = time.clock()
print("函数sorted排序",end2-start2)
print("排序结果",list1==list4)

输出:
插入排序 9.1573
函数sorted排序 0.0042
排序结果 True

4、希尔排序

**希尔排序(Shell Sort)**是插入排序的一种。也称缩小增量排序,
是直接插入排序算法的一种更高效的改进版本。
希尔排序是非稳定排序算法。该方法因DL.Shell于1959年提出而得名。
希尔排序是记录按下标的一定增量分组,对每组使用直接插入排序算法排序;
随着增量逐渐减少,每组包含的关键词越来越多,当增量减至1时,
整个文件恰被分成一组,算法便终止。

import random
import time
def shellSort(list1):
# 设定步长
step = len(list1)//2
while step > 0:
for i in range(step, len(list1)):
# 类似插入排序, 当前值与指定步长之前的值比较, 符合条件则交换位置
while i >= step and list1[i-step] > list1[i]:
list1[i], list1[i-step] = list1[i-step], list1[i]
i -= step
step = step//2 #步长值改为之前的二分之一 list1 = [random.randint(1,999) for i in range(10000)]
list11 = list1.copy()
start1 = time.clock()
shellSort(list1)
end1 = time.clock()
print("希尔排序 ",end1 - start1) start2 = time.clock()
list4 = sorted(list11)
end2 = time.clock()
print("函数sorted排序",end2-start2)
print("排序结果",list1==list4)

输出:
希尔排序 0.0957
函数sorted排序 0.0041
排序结果 True

5、基数排序

**基数排序(radix sort)**属于“分配式排序”(distribution sort),桶式排序
又称“桶子法”(bucket sort)或bin sort,顾名思义,
它是透过键值的部份资讯,将要排序的元素分配至某些“桶”中,
藉以达到排序的作用,基数排序法是属于稳定性的排序,
其时间复杂度为O (nlogm),其中r为所采取的基数,而m为堆数,
在某些时候,基数排序法的效率高于其它的稳定性排序法。
例如:对数组中的元素按照从低位到高位排序,对于[192,221,12,23]
第一轮按照个位数字相同的放在一组,是s[1] =[221],s[2]=[192,12],s[3]=23,
第二轮按照十位数字进行排序,s[1]=[12],s[2]=[221,23],s[9]=[192],
第三轮按照百位数字进行排序,s[0]=[12,23],s[1]=[192],s[2]=[221]

import random
import time def radixSort(list1,d):
for i in range(d):#多少位数就进行几轮排序
s = [[] for x in range(10)] # 因为每一位数字都是0~9,故建立10个桶
for j in list1:
s[j//(10**i)%10].append(j) #第一次取个位数,第二次取十位数,第三次取百位数
list1 = [k for t in s for k in t] #遍历二维列表s中的元素,赋值给list1
return list1 list1 = [random.randint(1,999) for i in range(10000)]
list11 = list1.copy()
start1 = time.clock()
list2 = radixSort(list1,len(str(max(list1))))
end1 = time.clock()
print("基数排序 ",end1 - start1) start2 = time.clock()
list4 = sorted(list11)
end2 = time.clock()
print("函数sorted排序",end2-start2)
print("排序结果",list2==list4)

输出:
基数排序 0.0208
函数sorted排序 0.0047
排序结果 True

6、桶排序

桶排序 (Bucket sort)或所谓的箱排序,顾名思义就是运用桶的思想来将数据放到相应的桶内,再将每一个桶内的数据进行排序,最后把所有桶内数据按照顺序取出来,得到的就是我们需要的有序数据

import random
import time def bucketSort(list1):
maxNum = max(list1)
minNum = min(list1)
bucket = [0] *(maxNum-minNum+1) #创建一个桶列表,长度为要排序的列表中最大的数与最小的数的差加1
for i in list1:
bucket[i-minNum] += 1 #把要排序的列表中的元素放到相应下标的桶中
list2 = []
for i in range(len(bucket)): #遍历桶列表,输出排序好的新列表
if bucket[i] != 0:
list2 += [i + minNum] * bucket[i] #对桶列表中的元素进行计数,有几个就加几个相同的元素
return list2 list1 = [random.randint(1,999) for i in range(10000)]
list11 = list1.copy()
start1 = time.clock()
list2 = bucketSort(list1)
end1 = time.clock()
print("桶排序 ",end1 - start1) start2 = time.clock()
list4 = sorted(list11)
end2 = time.clock()
print("函数sorted排序",end2-start2)
print("排序结果",list2==list4)

输出:
桶排序 0.0027
函数sorted排序 0.0046
排序结果 True

7、快速排序

快速排序(quickSort)
快速排序是对冒泡排序的改进
快排的思想:首先任意选取一个数据(通常选用数组的第一个数)作为关键数据,
然后将所有比它小的数都放到它前面,所有比它大的数都放到它后面,
这个过程称为一趟快速排序。

一趟快速排序的算法是:
1)设置两个变量i、j,排序开始的时候:i=0,j=N-1;
2)以第一个数组元素作为关键数据,赋值给key,即key=A[0];
3)从j开始向前搜索,即由后开始向前搜索(j–),找到第一个小于key的值A[j],
将A[j]和A[i]互换;
4)从i开始向后搜索,即由前开始向后搜索(i++),找到第一个大于key的A[i],
将A[i]和A[j]互换;
5)重复第3、4步,直到i=j; (3,4步中,没找到符合条件的值,
即3中A[j]不小于key,4中A[i]不大于key的时候改变j、i的值,使得j=j-1,i=i+1,
直至找到为止。找到符合条件的值,进行交换的时候i, j指针位置不变。
另外,i==j这一过程一定正好是i+或j-完成的时候,此时令循环结束)。

时间复杂度:O(nlgn)
快速排序是原地排序,不需要返回值

7.1 采用递归实现
import random
import time def parttion(list1,left,right): # 找到中间那个数
key = list1[left] #以第一个数组元素作为关键数据
while left < right:
# 由后开始向前搜索(right--),找到第一个小于key的值A[right],将A[left]和A[right]互换
while left < right and list1[right] >= key:
right -= 1
list1[left] = list1[right]
# 由前开始向后搜索(left++),找到第一个大于key的A[left],将A[right]和A[left]互换;
while left < right and list1[left] <= key:
left += 1
list1[right] = list1[left]
list1[left] = key
return left
def quickSort(list1,left,right):
if left < right:
# 先对序列排序,并找到一个元素A,这个元素的特点是:左边的所有元素<=A,右边的所有元素>=A
p = parttion(list1,left,right)
quickSort(list1,left,p) #对A的左边进行递归,重复过程parttion()
quickSort(list1,p+1,right) #对A的右边进行递归,重复过程parttion() list1 = [random.randint(1,999) for i in range(10000)]
list11 = list1.copy()
start1 = time.clock()
quickSort(list1,0,len(list1)-1)
end1 = time.clock()
print("快速排序(递归)",end1 - start1) start2 = time.clock()
list4 = sorted(list11)
end2 = time.clock()
print("函数sorted排序",end2-start2)
print("排序结果",list1==list4)

输出:
快速排序(递归) 0.0593
函数sorted排序 0.0042
排序结果 True

采用递归弊端:当数据量大的时候,在python中采用递归方式时有可能会造成内存溢出,并且排序时间较长,不建议使用。

7.2 采用栈实现
import random
import time def quickSort(list1):
stack = []
stack.append(0)
stack.append(len(list1)-1)
while stack:
high = right = stack.pop()
low = left = stack.pop()
if low == high:
continue
key = list1[left]
while left < right:
while left < right and list1[right] >= key:
right -= 1
list1[left] = list1[right]
while left < right and list1[left] <= key:
left += 1
list1[right] = list1[left]
list1[left] = key if left - 1 > low:
stack.append(low)
stack.append(left-1)
if left +1 < high:
stack.append(left+1)
stack.append(high) list1 = [random.randint(1,999) for i in range(10000)]
list11 = list1.copy()
start1 = time.clock()
quickSort(list1)
end1 = time.clock()
print("快速排序(栈) ",end1 - start1) start2 = time.clock()
list4 = sorted(list11)
end2 = time.clock()
print("函数sorted排序",end2-start2)
print("排序结果",list1==list4)

输出:
快速排序(栈) 0.0570
函数sorted排序 0.0058
排序结果 True

8、归并排序

归并排序:先分开再合并,分开成单个元素,合并的时候按照正确顺序合并。
分:
假如我们有一个n个数的数列,下标从0到n-1
  首先是分开的过程
1 我们按照 n//2 把这个数列分成两个小的数列
2 把两个小数列 再按照新长度的一半 把每个小数列都分成两个更小的
。。。一直这样重复,一直到每一个数分开了
并:
两个有序数组排序的方法则非常简单,同时对两个数组的第一个位置进行比大小,将小的放入一个空数组,然后被放入空数组的那个位置的指针往后 移一个,然后继续和另外一个数组的上一个位置进行比较,以此类推。到最后任何一个数组先出栈完,就将另外一个数组里的所有元素追加到新数组后面。

由于递归拆分的时间复杂度是logN 然而,进行两个有序数组排序的方法复杂度是N,该算法的时间复杂度是N*logN 所以是NlogN。

8.1 采用递归实现

参考网站


import random
import time def merge(left,right ):
# 从两个有顺序的列表里边依次取数据比较后放入result
# 每次我们分别拿出两个列表中最小的数比较,把较小的放入result
result = []
while len(left)>0 and len(right)>0 :
#为了保持稳定性,当遇到相等的时候优先把左侧的数放进结果列表,因为left本来也是大数列中比较靠左的
if left[0] <= right[0]:
result.append( left.pop(0) )
else:
result.append( right.pop(0) )
#while循环出来之后 说明其中一个数组没有数据了,我们把另一个数组添加到结果数组后面
result += left
result += right
return result
def mergeSort( li ):
#不断递归调用自己一直到拆分成成单个元素的时候就返回这个元素,不再拆分了
if len(li) == 1:
return li #取拆分的中间位置
mid = len(li) // 2
#拆分过后左右两侧子串
left = li[:mid]
right = li[mid:] #对拆分过后的左右再拆分 一直到只有一个元素为止
#最后一次递归时候ll和lr都会接到一个元素的列表
# 最后一次递归之前的ll和rl会接收到排好序的子序列
ll = mergeSort( left )
rl = mergeSort( right ) # 我们对返回的两个拆分结果进行排序后合并再返回正确顺序的子列表
# 这里我们调用拎一个函数帮助我们按顺序合并ll和lr
return merge(ll , rl) list1 = [random.randint(1,999) for i in range(10000)]
list11 = list1.copy()
start1 = time.clock()
list2 = mergeSort(list1)
end1 = time.clock()
print("归并排序 ",end1 - start1) start2 = time.clock()
list4 = sorted(list11)
end2 = time.clock()
print("函数sorted排序",end2-start2)
print("排序结果",list2==list4)

输出:
归并排序 0.1365
函数sorted排序 0.0043
排序结果 True

9、堆排序

参考网站

堆排序是采用二叉堆的数据结构来实现的。

二叉堆具有以下性质:

  1. 父节点的键值总是大于或等于(小于或等于)任何一个子节点的键值。
  2. 每个节点的左右子树都是一个二叉堆(都是最大堆或最小堆)。

步骤:

构造最大堆(Build_Max_Heap):若数组下标范围为0~n,考虑到单独一个元素是大根堆,则从下标n/2开始的元素为大根堆。于是只要从n/2-1开始,向前依次构造大根堆,这样就能保证,构造到某个节点时,它的左右子树都已经是大根堆。

堆排序(HeapSort):由于堆是用数组模拟的。得到一个大根堆后,数组内部并不是有序的。因此需要将堆化数组有序化。思想是移除根节点,并做最大堆调整的递归运算。第一次将heap[0]与heap[n-1]交换,再对heap[0…n-2]做最大堆调整。第二次将heap[0]与heap[n-2]交换,再对heap[0…n-3]做最大堆调整。重复该操作直至heap[0]和heap[1]交换。由于每次都是将最大的数并入到后面的有序区间,故操作完后整个数组就是有序的了。

最大堆调整(Max_Heapify):该方法是提供给上述两个过程调用的。目的是将堆的末端子节点作调整,使得子节点永远小于父节点 。

import random
import time def heapSort(list1) :
n = len(list1)
first = n//2-1
for start in range(first,-1,-1) : #构造大根堆
maxHeapify(list1,start,n-1)
for end in range(n-1,0,-1): #堆排,将大根堆转换成有序数组
list1[end],list1[0] = list1[0],list1[end]
maxHeapify(list1,0,end-1) #最大堆调整:将堆的末端子节点作调整,使得子节点永远小于父节点
#start为当前需要调整最大堆的位置,end为调整边界
def maxHeapify(list1,start,end):
root = start
while True :
child = root*2 +1 #调整节点的子节点
if child > end : break
if child+1 <= end and list1[child] < list1[child+1] :
child = child+1 #取较大的子节点
if list1[root] < list1[child] : #较大的子节点成为父节点
list1[root],list1[child] = list1[child],list1[root] #交换
root = child
else :
break list1 = [random.randint(1,999) for i in range(10000)]
list11 = list1.copy()
start1 = time.clock()
heapSort(list1)
end1 = time.clock()
print("推排序 ",end1 - start1) start2 = time.clock()
list4 = sorted(list11)
end2 = time.clock()
print("函数sorted排序",end2-start2)
print("排序结果",list1==list4)

输出:
推排序 0.0940
函数sorted排序 0.0041
排序结果 True

后记

【后记】为了让大家能够轻松学编程,我创建了一个公众号【轻松学编程】,里面有让你快速学会编程的文章,当然也有一些干货提高你的编程水平,也有一些编程项目适合做一些课程设计等课题。

也可加我微信【1257309054】,拉你进群,大家一起交流学习。
如果文章对您有帮助,请我喝杯咖啡吧!

公众号

关注我,我们一起成长~~

python实现经典的排序算法的更多相关文章

  1. Python实现的选择排序算法原理与用法实例分析

    Python实现的选择排序算法原理与用法实例分析 这篇文章主要介绍了Python实现的选择排序算法,简单描述了选择排序的原理,并结合实例形式分析了Python实现与应用选择排序的具体操作技巧,需要的朋 ...

  2. 一篇夯实一个知识点系列--python实现十大排序算法

    写在前面 排序是查找是算法中最重要的两个概念,我们大多数情况下都在进行查找和排序.科学家们穷尽努力,想使得排序和查找能够更加快速.本篇文章用Python实现十大排序算法. 干货儿 排序算法从不同维度可 ...

  3. Python实现一些常用排序算法

    一些常用的排序 #系统内置排序算法#list.sort()#heapq模块 def sys_heap_sort(list): import heapq heap = [] for i in range ...

  4. C++/Python冒泡排序与选择排序算法详解

    冒泡排序 冒泡排序算法又称交换排序算法,是从观察水中气泡变化构思而成,原理是从第一个元素开始比较相邻元素的大小,若大小顺序有误,则对调后再进行下一个元素的比较,就仿佛气泡逐渐从水底逐渐冒升到水面一样. ...

  5. Java 实现的各种经典的排序算法小Demo

    由于有上机作业,所以就对数据结构中常用的各种排序算法都写了个Demo,有如下几个: 直接插入排序 折半插入排序 希尔排序 冒泡排序 快速排序 选择排序 桶排序 Demo下载地址 下面谈一谈我对这几个排 ...

  6. [转]Java学习---7大经典的排序算法总结实现

    [原文]https://www.toutiao.com/i6591634652274885128/ 常见排序算法总结与实现 本文使用Java实现这几种排序. 以下是对排序算法总体的介绍. 冒泡排序 比 ...

  7. Python版常见的排序算法

    学习笔记 排序算法 目录 学习笔记 排序算法 1.冒泡排序 2.选择排序 3.插入排序 4.希尔排序 5.快速排序 6.归并排序 7.堆排序 排序分为两类,比较类排序和非比较类排序,比较类排序通过比较 ...

  8. 经典的排序算法java实现版

    /** * * @author yuzhiping * @version 1.0 * 功能说明:计算机领域经典的算法 * */ public class sortAlgorithm<T exte ...

  9. 用Python实现几种排序算法

    #coding=utf-8 # 1 快速排序算法 def qksort(list): if len(list)<=1: return list else: pivot = list[0] les ...

随机推荐

  1. 微服务通信之feign的注册、发现过程

    前言 feign 是目前微服务间通信的主流方式,是springCloud中一个非常重要的组件.他涉及到了负载均衡.限流等组件.真正意义上掌握了feign可以说就掌握了微服务. 一.feign的使用 f ...

  2. obj2opengl:转换OBJ 3D模型到iPhone OpenGL ES兼容的数组中

    原文如下:obj2opengl: convert obj 3D models to arrays compatible with iPhone OpenGL ES obj2opengl在GitHub中 ...

  3. 006 01 Android 零基础入门 01 Java基础语法 01 Java初识 06 使用Eclipse开发Java程序

    006 01 Android 零基础入门 01 Java基础语法 01 Java初识 06 使用Eclipse开发Java程序 Eclipse下创建程序 创建程序分为以下几个步骤: 1.首先是创建一个 ...

  4. Arduino control Eeprom by IIC method of using device address in Arduino

    参考: 1.https://www.arduino.cc/ 2.https://www.arduino.cc/reference/en/ 3.https://www.arduino.cc/en/Ref ...

  5. Ubuntu常用工具安装

    安装 aptitude 管理软件 $ sudo apt-get install aptitude 安装gdebi(安装deb包) # 安装: $ sudo apt install gdebi-core ...

  6. Java中的对象都是在堆上分配的吗?

    作者:LittleMagic https://www.jianshu.com/p/8377e09971b8 为了防止歧义,可以换个说法: Java对象实例和数组元素都是在堆上分配内存的吗? 答:不一定 ...

  7. 【转载】可能是世界上最牛逼的网站统计程序——Matomo

    大家做网站的时候一般都会使用网站统计程序.通常,国内网站会使用百度统计.CNZZ等,而国外网站则会使用Google Analytics等统计.国内的统计程序普遍功能不太丰富,且响应速度一般.Googl ...

  8. 用vscode写python,from引用本地文件的时候老是有红色波浪线,很不爽

    前言 出于一些原因,国际关系等等,最近想把开发工具切换到一些免费开源的工具上面,先尝试了在vscode上搭建python环境,总体还是很简单的, 网上教程很多,vscode本身的插件也很丰富,可惜了国 ...

  9. k8s集群,使用pvc方式实现数据持久化存储

    环境: 系统 华为openEulerOS(CentOS7) k8s版本 1.17.3 master 192.168.1.244 node1 192.168.1.245 介绍: 在Kubernetes中 ...

  10. 分析如何直接绕过超时代VPY视频播放器的播放密码

    声明:仅技术交流和学习! 前言: 你有没试过在网上下载一套视频,因网盘限速整整开机下载好几晚,下完后打开发现加密了,又找不到卖家注册.心里是几万只草泥马飞奔啊. 于是不甘心和好奇下,偿试自己破解. 目 ...