python 排序算法总结及实例详解


Posted in Python onSeptember 28, 2016

总结了一下常见集中排序的算法

python 排序算法总结及实例详解

归并排序

归并排序也称合并排序,是分治法的典型应用。分治思想是将每个问题分解成个个小问题,将每个小问题解决,然后合并。

具体的归并排序就是,将一组无序数按n/2递归分解成只有一个元素的子项,一个元素就是已经排好序的了。然后将这些有序的子元素进行合并。

合并的过程就是 对 两个已经排好序的子序列,先选取两个子序列中最小的元素进行比较,选取两个元素中最小的那个子序列并将其从子序列中

去掉添加到最终的结果集中,直到两个子序列归并完成。

代码如下:

#!/usr/bin/python 
import sys 
 
def merge(nums, first, middle, last): 
  ''''' merge ''' 
  # 切片边界,左闭右开并且是了0为开始 
  lnums = nums[first:middle+1] 
  rnums = nums[middle+1:last+1] 
  lnums.append(sys.maxint) 
  rnums.append(sys.maxint) 
  l = 0 
  r = 0 
  for i in range(first, last+1): 
    if lnums[l] < rnums[r]: 
      nums[i] = lnums[l] 
      l+=1 
    else: 
      nums[i] = rnums[r] 
      r+=1 
def merge_sort(nums, first, last): 
  ''''' merge sort
  merge_sort函数中传递的是下标,不是元素个数
  ''' 
  if first < last: 
    middle = (first + last)/2 
    merge_sort(nums, first, middle) 
    merge_sort(nums, middle+1, last) 
    merge(nums, first, middle,last) 
 
if __name__ == '__main__': 
  nums = [10,8,4,-1,2,6,7,3] 
  print 'nums is:', nums 
  merge_sort(nums, 0, 7) 
  print 'merge sort:', nums

稳定,时间复杂度 O(nlog n)

插入排序

代码如下:

#!/usr/bin/python 
importsys 
 
definsert_sort(a): 
  ''''' 插入排序
  有一个已经有序的数据序列,要求在这个已经排好的数据序列中插入一个数,
  但要求插入后此数据序列仍然有序。刚开始 一个元素显然有序,然后插入一
  个元素到适当位置,然后再插入第三个元素,依次类推
  ''' 
  a_len = len(a) 
  if a_len = 0 and a[j] > key: 
      a[j+1] = a[j] 
      j-=1 
    a[j+1] = key 
  return a 
 
if __name__ == '__main__': 
  nums = [10,8,4,-1,2,6,7,3] 
  print 'nums is:', nums 
  insert_sort(nums) 
  print 'insert sort:', nums

稳定,时间复杂度 O(n^2)

交换两个元素的值python中你可以这么写:a, b = b, a,其实这是因为赋值符号的左右两边都是元组

(这里需要强调的是,在python中,元组其实是由逗号“,”来界定的,而不是括号)。

选择排序

选择排序(Selection sort)是一种简单直观的排序算法。它的工作原理如下。首先在未排序序列中找到最小(大)元素,存放到

排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到所

有元素均排序完毕。

import sys 
def select_sort(a): 
  ''''' 选择排序 
  每一趟从待排序的数据元素中选出最小(或最大)的一个元素,
  顺序放在已排好序的数列的最后,直到全部待排序的数据元素排完。
  选择排序是不稳定的排序方法。
  ''' 
  a_len=len(a) 
  for i in range(a_len):#在0-n-1上依次选择相应大小的元素 
    min_index = i#记录最小元素的下标 
    for j in range(i+1, a_len):#查找最小值 
      if(a[j]<a[min_index]): 
        min_index=j 
    if min_index != i:#找到最小元素进行交换 
      a[i],a[min_index] = a[min_index],a[i] 
 
if __name__ == '__main__': 
  A = [10, -3, 5, 7, 1, 3, 7]  
  print 'Before sort:',A  
  select_sort(A)  
  print 'After sort:',A

不稳定,时间复杂度 O(n^2)

希尔排序

希尔排序,也称递减增量排序算法,希尔排序是非稳定排序算法。该方法又称缩小增量排序,因DL.Shell于1959年提出而得名。

先取一个小于n的整数d1作为第一个增量,把文件的全部记录分成d1个组。所有距离为d1的倍数的记录放在同一个组中。先在各组内进行排序;

然后,取第二个增量d2

import sys 
def shell_sort(a): 
  ''''' shell排序 
  ''' 
  a_len=len(a) 
  gap=a_len/2#增量 
  while gap>0: 
    for i in range(a_len):#对同一个组进行选择排序 
      m=i 
      j=i+1 
      while j<a_len: 
        if a[j]<a[m]: 
          m=j 
        j+=gap#j增加gap 
      if m!=i: 
        a[m],a[i]=a[i],a[m] 
    gap/=2 
 
if __name__ == '__main__': 
  A = [10, -3, 5, 7, 1, 3, 7]  
  print 'Before sort:',A  
  shell_sort(A)  
  print 'After sort:',A

不稳定,时间复杂度 平均时间 O(nlogn) 最差时间O(n^s)1

堆排序 ( Heap Sort )

“堆”的定义:在起始索引为 0 的“堆”中:

节点 i 的右子节点在位置 2 * i + 24) 节点 i 的父节点在位置 floor( (i ? 1) / 2 )   : 注 floor 表示“取整”操作

堆的特性:

每个节点的键值一定总是大于(或小于)它的父节点

“最大堆”:

“堆”的根节点保存的是键值最大的节点。即“堆”中每个节点的键值都总是大于它的子节点。

上移,下移 :

当某节点的键值大于它的父节点时,这时我们就要进行“上移”操作,即我们把该节点移动到它的父节点的位置,而让它的父节点到它的位置上,然后我们继续判断该节点,直到该节点不再大于它的父节点为止才停止“上移”。

现在我们再来了解一下“下移”操作。当我们把某节点的键值改小了之后,我们就要对其进行“下移”操作。

方法:

我们首先建立一个最大堆(时间复杂度O(n)),然后每次我们只需要把根节点与最后一个位置的节点交换,然后把最后一个位置排除之外,然后把交换后根节点的堆进行调整(时间复杂度 O(lgn) ),即对根节点进行“下移”操作即可。 堆排序的总的时间复杂度为O(nlgn).

代码如下:

#!/usr/bin env python 
 
# 数组编号从 0开始 
def left(i): 
  return 2*i +1 
def right(i): 
  return 2*i+2 
 
#保持最大堆性质 使以i为根的子树成为最大堆 
def max_heapify(A, i, heap_size): 
  if heap_size <= 0: 
    return 
  l = left(i) 
  r = right(i) 
  largest = i # 选出子节点中较大的节点 
  if l A[largest]: 
    largest = l 
  if r A[largest]: 
    largest = r 
  if i != largest :#说明当前节点不是最大的,下移 
    A[i], A[largest] = A[largest], A[i] #交换 
    max_heapify(A, largest, heap_size)#继续追踪下移的点 
  #print A 
# 建堆  
def bulid_max_heap(A): 
  heap_size = len(A) 
  if heap_size >1: 
    node = heap_size/2 -1 
    while node >= 0: 
     max_heapify(A, node, heap_size) 
     node -=1 
 
# 堆排序 下标从0开始 
def heap_sort(A): 
  bulid_max_heap(A) 
  heap_size = len(A) 
  i = heap_size - 1 
  while i > 0 : 
    A[0],A[i] = A[i], A[0] # 堆中的最大值存入数组适当的位置,并且进行交换 
    heap_size -=1 # heap 大小 递减 1 
    i -= 1 # 存放堆中最大值的下标递减 1 
    max_heapify(A, 0, heap_size) 
 
if __name__ == '__main__' : 
 
  A = [10, -3, 5, 7, 1, 3, 7] 
  print 'Before sort:',A 
  heap_sort(A) 
  print 'After sort:',A

不稳定,时间复杂度 O(nlog n)

快速排序

快速排序算法和合并排序算法一样,也是基于分治模式。对子数组A[p…r]快速排序的分治过程的三个步骤为:

分解:把数组A[p…r]分为A[p…q-1]与A[q+1…r]两部分,其中A[p…q-1]中的每个元素都小于等于A[q]而A[q+1…r]中的每个元素都大于等于A[q];

解决:通过递归调用快速排序,对子数组A[p…q-1]和A[q+1…r]进行排序;

合并:因为两个子数组是就地排序的,所以不需要额外的操作。

对于划分partition 每一轮迭代的开始,x=A[r], 对于任何数组下标k,有:

1) 如果p≤k≤i,则A[k]≤x。

2) 如果i+1≤k≤j-1,则A[k]>x。

3) 如果k=r,则A[k]=x。

代码如下:

#!/usr/bin/env python 
# 快速排序 
'''''
划分 使满足 以A[r]为基准对数组进行一个划分,比A[r]小的放在左边,
  比A[r]大的放在右边
快速排序的分治partition过程有两种方法,
一种是上面所述的两个指针索引一前一后逐步向后扫描的方法,
另一种方法是两个指针从首位向中间扫描的方法。
''' 
#p,r 是数组A的下标 
def partition1(A, p ,r): 
  '''''
   方法一,两个指针索引一前一后逐步向后扫描的方法
  ''' 
  x = A[r] 
  i = p-1 
  j = p 
  while j < r: 
    if A[j] < x: 
      i +=1 
      A[i], A[j] = A[j], A[i] 
    j += 1 
  A[i+1], A[r] = A[r], A[i+1] 
  return i+1 
 
def partition2(A, p, r): 
  '''''
  两个指针从首尾向中间扫描的方法
  ''' 
  i = p 
  j = r 
  x = A[p] 
  while i = x and i < j: 
      j -=1 
    A[i] = A[j] 
    while A[i]<=x and i < j: 
      i +=1 
    A[j] = A[i] 
  A[i] = x 
  return i 
 
# quick sort 
def quick_sort(A, p, r): 
  '''''
    快速排序的最差时间复杂度为O(n2),平时时间复杂度为O(nlgn)
  ''' 
  if p < r: 
    q = partition2(A, p, r) 
    quick_sort(A, p, q-1) 
    quick_sort(A, q+1, r) 
 
if __name__ == '__main__': 
 
  A = [5,-4,6,3,7,11,1,2] 
  print 'Before sort:',A 
  quick_sort(A, 0, 7) 
  print 'After sort:',A

不稳定,时间复杂度 最理想 O(nlogn)最差时间O(n^2)

说下python中的序列:

列表、元组和字符串都是序列,但是序列是什么,它们为什么如此特别呢?序列的两个主要特点是索引操作符和切片操作符。索引操作符让我们可以从序列中抓取一个特定项目。切片操作符让我们能够获取序列的一个切片,即一部分序列,如:a = [‘aa','bb','cc'], print a[0] 为索引操作,print a[0:2]为切片操作。

  希望通过此文掌握Python 算法排序的知识,谢谢大家对本站的支持!

Python 相关文章推荐
python3编写C/S网络程序实例教程
Aug 25 Python
Python 常用string函数详解
May 30 Python
windows10系统中安装python3.x+scrapy教程
Nov 08 Python
Python实现的多项式拟合功能示例【基于matplotlib】
May 15 Python
Mac下Anaconda的安装和使用教程
Nov 29 Python
Python中的集合介绍
Jan 28 Python
python获取点击的坐标画图形的方法
Jul 09 Python
在Python中os.fork()产生子进程的例子
Aug 08 Python
解决django中form表单设置action后无法回到原页面的问题
Mar 13 Python
Python库skimage绘制二值图像代码实例
Apr 10 Python
python 字典item与iteritems的区别详解
Apr 25 Python
Python 防止死锁的方法
Jul 29 Python
一些常用的Python爬虫技巧汇总
Sep 28 #Python
Python三级目录展示的实现方法
Sep 28 #Python
Python黑帽编程 3.4 跨越VLAN详解
Sep 28 #Python
python 采集中文乱码问题的完美解决方法
Sep 27 #Python
20招让你的Python飞起来!
Sep 27 #Python
python搭建虚拟环境的步骤详解
Sep 27 #Python
利用python发送和接收邮件
Sep 27 #Python
You might like
ThinkPHP模板循环输出Volist标签用法实例详解
2016/03/23 PHP
PHP用PDO如何封装简单易用的DB类详解
2017/07/30 PHP
PHP实现求连续子数组最大和问题2种解决方法
2017/12/26 PHP
iframe跨域通信封装详解
2015/08/11 Javascript
clipboard.js无需Flash无需依赖任何JS库实现文本复制与剪切
2015/10/10 Javascript
同步异步动态引入js文件的几种方法总结
2016/09/23 Javascript
原生JS实现匀速图片轮播动画
2016/10/18 Javascript
Vue数组更新及过滤排序功能
2017/08/10 Javascript
详解nodejs通过代理(proxy)发送http请求(request)
2017/09/22 NodeJs
dropload.js插件下拉刷新和上拉加载使用详解
2017/10/20 Javascript
vue微信分享的实现(在当前页面分享其他页面)
2019/04/16 Javascript
VUE接入腾讯验证码功能(滑块验证)备忘
2019/05/07 Javascript
layui导出所有数据的例子
2019/09/10 Javascript
js实现多个标题吸顶效果
2020/01/08 Javascript
node.js文件的复制、创建文件夹等相关操作
2021/02/05 Javascript
python 定义n个变量方法 (变量声明自动化)
2018/11/10 Python
pyqt5实现俄罗斯方块游戏
2019/01/11 Python
django 控制页面跳转的例子
2019/08/06 Python
你不知道的葡萄干处理法、橙蜜处理法、二氧化碳酵母法
2021/03/17 冲泡冲煮
eDreams澳大利亚:预订机票、酒店和度假产品
2017/04/19 全球购物
来自世界各地的饮料:Flavourly
2019/05/06 全球购物
艺术设计专业个人求职信
2013/09/21 职场文书
汽车运用工程毕业生自荐信
2013/10/29 职场文书
美术教学感言
2014/02/22 职场文书
家教广告词
2014/03/19 职场文书
日化店促销方案
2014/03/26 职场文书
干部鉴定材料
2014/05/18 职场文书
2016自主招生校长推荐信范文
2015/03/23 职场文书
经理岗位职责范本
2015/04/15 职场文书
2015年采购员工作总结
2015/04/27 职场文书
小学教研工作总结2015
2015/05/13 职场文书
论文答辩开场白大全
2015/05/27 职场文书
python爬虫之爬取笔趣阁小说
2021/04/22 Python
MySQL 如何分析查询性能
2021/05/12 MySQL
MySQL如何使用使用Xtrabackup进行备份和恢复
2021/06/21 MySQL
拙作再改《我的收音机情缘》
2022/04/05 无线电