python常见排序算法解析
python——常见排序算法解析
算法是程序员的灵魂。
下面的博文是我整理的感觉还不错的算法实现
原理的理解是最重要的,我会常回来看看,并坚持每天刷leetcode
本篇主要实现九(八)大排序算法,分别是冒泡排序,插入排序,选择排序,希尔排序,归并排序,快速排序,堆排序,计数排序。希望大家回顾知识的时候也能从我的这篇文章得到帮助。
概述
十种常见排序算法可以分为两大类:
- 非线性时间比较类排序:通过比较来决定元素间的相对次序,由于其时间复杂度不能突破O(nlogn),因此称为非线性时间比较类排序。
- 线性时间非比较类排序:不通过比较来决定元素间的相对次序,它可以突破基于比较排序的时间下界,以线性时间运行,因此称为线性时间非比较类排序。
基础定义
- 稳定:如果a原本在b前面,而a=b,排序之后a仍然在b的前面。
- 不稳定:如果a原本在b的前面,而a=b,排序之后 a 可能会出现在 b 的后面。
- 时间复杂度:对排序数据的总的操作次数。反映当n变化时,操作次数呈现什么规律。
- 空间复杂度:是指算法在计算机内执行时所需存储空间的度量,它也是数据规模n的函数。
图示
为了防止误导读者,本文所有概念性内容均截取自对应Wiki。
冒泡排序
原理
冒泡排序(Bubble Sort)是一种简单的排序算法。它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到数列的顶端。
步骤
冒泡排序算法的运作如下:
- 比较相邻的元素。如果第一个比第二个大,就交换他们两个。
- 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。这步做完后,最后的元素会是最大的数。
- 针对所有的元素重复以上的步骤,除了最后一个。
- 持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。
代码
def bubble_sort(list):length = len(list)# 第一级遍历for index in range(length):# 第二级遍历for j in range(1, length - index):if list[j - 1] > list[j]:# 交换两者数据,这里没用temp是因为python 特性元组。list[j - 1], list[j] = list[j], list[j - 1]return list
这种排序其实还可以稍微优化一下,添加一个标记,在排序已完成时,停止排序。
def bubble_sort_flag(list):length = len(list)for index in range(length):# 标志位flag = Truefor j in range(1, length - index):if list[j - 1] > list[j]:list[j - 1], list[j] = list[j], list[j - 1]flag = Falseif flag:# 没有发生交换,直接返回listreturn listreturn list
选择排序
原理
选择排序(Selection sort)是一种简单直观的排序算法。它的工作原理大致是将后面的元素最小元素一个个取出然后按顺序放置。
步骤
- 在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,
- 再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。
- 重复第二步,直到所有元素均排序完毕。
代码
def selection_sort(list):n=len(list)for i in range (0,n):min = ifor j in range(i+1,n):if list[j]<list[min]:min=jlist[min],list[i]=list[i],list[min]return list
插入排序
原理
插入排序(Insertion Sort)是一种简单直观的排序算法。它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。
步骤
- 从第一个元素开始,该元素可以认为已经被排序
- 取出下一个元素,在已经排序的元素序列中从后向前扫描
- 如果该元素(已排序)大于新元素,将该元素移到下一位置
- 重复步骤3,直到找到已排序的元素小于或者等于新元素的位置
- 将新元素插入到该位置后
- 重复步骤2~5
代码
def insert_sort(list):n = len(list)for i in range(1, n):# 后一个元素和前一个元素比较# 如果比前一个小if list[i] < list[i - 1]:# 将这个数取出temp = list[i]# 保存下标index = i# 从后往前依次比较每个元素for j in range(i - 1, -1, -1):# 和比取出元素大的元素交换if list[j] > temp:list[j + 1] = list[j]index = jelse:break# 插入元素list[index] = tempreturn list
希尔排序
原理
希尔排序,也称递减增量排序算法,是插入排序的一种更高效的改进版本。希尔排序是非稳定排序算法。
希尔排序是基于插入排序的以下两点性质而提出改进方法的:
插入排序在对几乎已经排好序的数据操作时,效率高,即可以达到线性排序的效率
但插入排序一般来说是低效的,因为插入排序每次只能将数据移动一位。
步骤
每次以一定步长(就是跳过等距的数)进行排序,直至步长为1.
代码
def shell_sort(list):n = len(list)# 初始步长gap = n // 2while gap > 0:for i in range(gap, n):# 每个步长进行插入排序temp = list[i]j = i# 插入排序while j >= gap and list[j - gap] > temp:list[j] = list[j - gap]j -= gaplist[j] = temp# 得到新的步长gap = gap // 2return list
步长使用的是Donald Shell的建议,另外步长还可以使用Sedgewick提出的(1, 5, 19, 41, 109,…)。
也可以使用斐波那契数列除去0和1将剩余的数以黄金分区比的两倍的幂进行运算得到的数列。
归并排序
原理
归并操作(归并算法),指的是将两个已经排序的序列合并成一个序列的操作。归并排序算法依赖归并操作。
步骤
1.迭代法
- 申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列
- 设定两个指针,最初位置分别为两个已经排序序列的起始位置
3.比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置 - 重复步骤3直到某一指针到达序列尾
- 将另一序列剩下的所有元素直接复制到合并序列尾
递归法
假设序列共有n个元素:
- 将序列每相邻两个数字进行归并操作,形成 {\displaystyle floor(n/2)} floor(n/2)个序列,排序后每个序列包含两个元素
- 将上述序列再次归并,形成 {\displaystyle floor(n/4)} floor(n/4)个序列,每个序列包含四个元素
- 重复步骤2,直到所有元素排序完毕
代码
# 递归法 def merge_sort(list):# 认为长度不大于1的数列是有序的if len(list) <= 1:return list# 二分列表middle = len(list) // 2left = merge_sort(list[:middle])right = merge_sort(list[middle:])# 最后一次合并return merge(left, right) # 合并 def merge(left, right):l,r=0,0result=[]while l<len(left) and r<len(right):if left[l] <right[r]:result.append(left[l])l+=1else:result.append(right[r])r +=1reslut +=left[l:]result+=right[r:] return result
鄙人不才,不知归并排序的迭代法如何用Python实现,望指教。
快速排序
原理
快速排序使用分治法(Divide and conquer)策略来把一个序列(list)分为两个子序列(sub-lists)。
步骤
- 从数列中挑出一个元素,称为”基准”(pivot),
- 重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区结束之后,该基准就处于数列的中间位置。这个称为分区(partition)操作。
- 递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序。
代码
普通版
def quick_sort(list):less = []pivotList = []more = []# 递归出口if len(list) <= 1:return listelse:# 将第一个值做为基准pivot = list[0]for i in list:# 将比急转小的值放到less数列if i < pivot:less.append(i)# 将比基准打的值放到more数列elif i > pivot:more.append(i)# 将和基准相同的值保存在基准数列else:pivotList.append(i)# 对less数列和more数列继续进行排序less = quick_sort(less)more = quick_sort(more)return less + pivotList + more
咳咳,下面这段代码出自《Python cookbook 第二版》传说中的三行实现python快速排序。
def qsort(arr):if len(arr) <= 1:return arrelse:pivot = arr[0]less = [x for x in arr[1:] if x < pivot]greater = [x for x in arr[1:] if x >= pivot]return qsort(less) + [pivot] + qsort(greater)
当然还有一行语法糖版本:
qs = lambda xs : ( (len(xs) <= 1 and [xs]) or [ qs( [x for x in xs[1:] if x < xs[0]] ) + [xs[0]] + qs( [x for x in xs[1:] if x >= xs[0]] ) ] )[0]
是不是感受到了Python的魅力?
堆排序
原理
堆排序(Heapsort)是指利用堆这种数据结构所设计的一种排序算法。堆积是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。
步骤
- 创建最大堆:将堆所有数据重新排序,使其成为最大堆
- 最大堆调整:作用是保持最大堆的性质,是创建最大堆的核心子程序
- 堆排序:移除位在第一个数据的根节点,并做最大堆调整的递归运算
代码
def heap_sort(list):# 创建最大堆for start in range((len(list) - 2) // 2, -1, -1):sift_down(list, start, len(list) - 1)# 堆排序for end in range(len(list) - 1, 0, -1):list[0], list[end] = list[end], list[0]sift_down(list, 0, end - 1)return list# 最大堆调整 def sift_down(lst, start, end):root = startwhile True:child = 2 * root + 1if child > end:breakif child + 1 <= end and lst[child] < lst[child + 1]:child += 1if lst[root] < lst[child]:lst[root], lst[child] = lst[child], lst[root]root = childelse:break
计数排序
原理
当输入的元素是n个0到k之间的整数时,它的运行时间是Θ(n + k)。计数排序不是比较排序,排序的速度快于任何比较排序算法。
由于用来计数的数组C的长度取决于待排序数组中数据的范围(等于待排序数组的最大值与最小值的差加上1),这使得计数排序对于数据范围很大的数组,需要大量时间和内存。例如:计数排序是用来排序0到100之间的数字的最好的算法,但是它不适合按字母顺序排序人名。但是,计数排序可以用在基数排序算法中,能够更有效的排序数据范围很大的数组。
步骤
- 找出待排序的数组中最大和最小的元素
- 统计数组中每个值为i的元素出现的次数,存入数组 C 的第 i 项
- 对所有的计数累加(从C中的第一个元素开始,每一项和前一项相加)
- 反向填充目标数组:将每个元素i放在新数组的第C(i)项,每放一个元素就将C(i)减去1
代码
def count_sort(list):min = 2147483647max = 0# 取得最大值和最小值for x in list:if x < min:min = xif x > max:max = x# 创建数组Ccount = [0] * (max - min +1)for index in list:count[index - min] += 1index = 0# 填值for a in range(max - min+1):for c in range(count[a]):list[index] = a + minindex += 1return list
第九种排序
None?
当然不会
自然就是系统自带的
list.sort()
转载于:https://www.cnblogs.com/quegai18/p/10404659.html
python常见排序算法解析相关推荐
- python实现常见排序算法
python实现常见排序算法 快速排序 思想:取出第一个元素把它放到序列的中间某一个正确位置,以它进行分割成左边和右边,再分别对左边和右边进行取元素分割(递归) 递归实现 def quicksort( ...
- python 经典排序算法
python 经典排序算法 排序算法可以分为内部排序和外部排序,内部排序是数据记录在内存中进行排序,而外部排序是因排序的数据很大,一次不能容纳全部的排序记录,在排序过程中需要访问外存.常见的内部排序算 ...
- 常见排序算法及其对应的时间复杂度、空间复杂度
常见排序算法及其对应的时间复杂度.空间复杂度: 排序算法经过长时间演变,大体可以分为两类:内排序和外排序.在排序过程中,全部记录存放在内存,则成为内排序:如果排序过程中需要使用外存,则称为外排序,本文 ...
- php常见排序算去,PHP兑现常见排序算法
PHP实现常见排序算法 //插入排序(一维数组) function insert_sort($arr){ $count = count($arr); for($i=1; $i $tmp = $arr[ ...
- Java常见排序算法
Java常见排序算法 转载于:https://www.cnblogs.com/hfultrastrong/p/7829889.html
- python列表按照指定顺序排序-Python常见排序操作示例【字典、列表、指定元素等】...
本文实例讲述了Python常见排序操作.分享给大家供大家参考,具体如下: 字典排序 按value排序 d1 = {"name":"python","b ...
- Java常见排序算法之插入排序
一.概述 本节由小千给大家分享Java常见排序算法之插入排序,之前我们说过排序是算法中的一部分.所以我们学习排序也是算法的入门,为了能让大家感受到排序是算法的一部分,我举个例子证明一下:比如麻将游戏, ...
- android studio插入数据表中没有_学Java能拿高薪吗 Java中常见排序算法有哪些
学Java能拿高薪吗?Java中常见排序算法有哪些?作为老牌编程语言,Java拥有广阔的市场占有率,几乎90%以上的大中型互联网应用系统在服务端开发都会首选Java.为了加入到Java这一高薪行业,很 ...
- Java 实现常见排序算法
Java 实现常见排序算法 1. 综述 复习常见排序算法,用Java实现. 2. 代码 1 package cn.edu.tju.scs; 2 3 public class Sort { 4 publ ...
最新文章
- 使用Python,OpenCV和Hough圆检测图像中的圆
- 基于Transformer对透明物体进行分割
- makefile常见伪目标(.PHONY 不会去检查目标文件)
- 如何找到Partner 相关设置里哪些是SAP 标准deliver的,哪些是我们自己创建的
- Step by Step 创建一个WCF Service
- 【JQuery NoviceToNinja系列】目录
- java 旅游网站项目实现_基于jsp的旅游网站a-JavaEE实现旅游网站a - java项目源码
- 计算机硬件故障有哪些现象,计算机常见硬件故障症状现象分析及解决办法
- 程序员常用软件:一款个人知识笔记管理神器
- 微软拼音输入法调整状态栏水平/垂直选项失效解决办法
- (HDU-1564)Play a game(博弈论)
- 9.2. switchport trunk encapsulation dot1q 提示 invaild input at^marker.
- Outlook2019添加126邮箱方法
- JavaScript里面的“类”
- 计算机的0和1是怎么变成我们屏幕上看到的图片、视频和声音的
- 知云文献翻译没反应_论文翻译工具--Copytranslate
- UE4(Unreal Engine4)在蒙太奇动画中添加音频轨道通知
- 商业转战短视频平台,浅看抖音的品牌营销特点
- iOS开发的一些奇巧淫技3
- 制作全景图的软件都有哪些?全景图怎么制作做的?
热门文章
- JavaScript基础函数体中的唯一var模式(002)
- 计算机操作系统学习笔记_6_进程管理 --死锁
- RFID开发利器 proxmark3
- 解决svn cannot set LC_CTYPE locale的问题
- 奇怪的 Markdown / LaTeX 笔记
- leveldb登山之路——cache
- exchange 2010申请分配证书服务提示:证书无效,不可用于exchange server
- 第一太阳能公司(First Solar)在罗斯资本公司的评级上调
- linux有关信号的FAQ
- containerd客户端工具nerdctl的使用