原创博文,转载请注明出处

利用周六周末的时间把几种基本的排序方法用python实现了一下,废话少说,直接上代码。

本文不注重基础知识的讲解,只做大致的描述,大家如果不清楚概念,自行查找资料。

直接插入排序:

  每次从无序表中取出第一个元素,把它插入到有序表的合适位置,使有序表仍然有序。

 def insert(arr):
l = len(arr)
for i in range(1,l):
if arr[i]<arr[i-1]:
temp =arr[i]
j=i-1
arr[j+1]=arr[j]
j=j-1
while j>=0 and arr[j]>temp:
arr[j+1]=arr[j] #元素后移
j=j-1
arr[j+1]=temp
return arr
arra=[98,36,-9,0,47,23,1,8,10,7]
print insert(arra)

折半插入排序:

  折半插入排序就是就是将上面直接插入排序中查找有序子表的工作使用折半查找来实现,在确定出待插入位置后,就可以统一的向后移动元素。

 # -*- coding: cp936 -*-
def find_ff(arr,x):#折半查找
size =len(arr)
low = 0
high = size-1
while low<=high:
mid =(low+high)/2
if arr[low]==x:
return low
elif arr[high]==x:
return high
elif arr[mid]==x:
return mid
elif arr[mid] > x:
high = mid-1
else:
low = mid+1 def insert_ff(arr):#升序
l = len(arr)
for i in range(1,l):
if arr[i]<arr[i-1]:
temp =arr[i]
j=i-1
low = 0
high = j
while low<=high:
mid = (low+high)/2
print 'mid',mid
if arr[mid] > temp:
high = mid-1
else:
low = mid+1
print 'high+1',high+1
print 'j',j
if j==0:
arr[j+1],arr[j]=arr[j],arr[j+1]
else:
print 'action 2 '
for x in range(j,high,-1):#移动元素
print 'x',x
arr[x+1]=arr[x]
arr[high+1]=temp
print arr
return arr arra=[98,36,-9,0,47,23,1,8,10,7]
print insert_ff(arra)

在分析折半插入排序时 一定要搞清楚元素的索引值。所以我在里面加入了print语句是为了测试而加入的 ,可以忽略。

希尔排序

 def shell(arr):
l = len(arr)
h = l/2
while h>=1:
for i in range(l):
j = i
while j>=h and arr[j]<arr[j-h]:
arr[j],arr[j-h]=arr[j-h],arr[j]
h=h/2
return arr
arra=[98,36,-9,0,47,23,1,8,10,7]
print shell(arra)

交换排序 : 冒泡排序和快速排序

   冒泡排序比较简单

# -*- coding: cp936 -*-
def bubble(arr):#降序
size = len(arr)
for i in range(size-1):
for j in range(i,size-1):
if arr[j+1]>arr[j]:
arr[j+1],arr[j]=arr[j],arr[j+1] return arr arra=[98,36,-9,0,47,23,1,8,10,7]
print bubble(arra)

快速排序 :对冒泡排序的一种改进,基本思想是基于分治的

 # -*- coding: cp936 -*-
def partition(data,low,high):
if low<high:
x = data[low]#以第一个元素作为枢轴值
while low<high: #循环跳出条件
while low<high and data[high]>=x:
high -= 1
data[low]=data[high]#将小于枢轴值得元素移到左端
while low<high and data[low]<=x:
low += 1
print low
data[high]=data[low]#将大于枢轴值的元素移到右端
data[low]=x
return low
def quick(arr,low,high):
if low < high:
pivotop = partition(arr,low,high)
quick(arr,low,pivotop-1)
quick(arr,pivotop+1,high)
return arr arra=[98,36,-9,0,47,23,1,8,10,7]
print quick(arra,0,len(arra)-1)

在这儿我们举了一个特例,就是第一个元素大于后面的所有元素,在测试过程中发现了好多问题,比如第六行和第九行再次加入了low<high的判断条件是为了避免边界条件问题,边界条件作为测试过程的重要环节,由于逻辑性较强,所以比较困难调试。

选择排序 :简单排序和堆排序

简单排序比较简单实现如下

def simple(arr):
size = len(arr)
for i in range(size):
mini = arr[i]
for j in range(i,size):
if arr[j] < mini:
mini = arr[j]
arr[i],arr[j]=arr[j],arr[i]
return arr
arra=[98,36,-9,0,47,23,1,8,10,7]
print simple(arra)

堆排序:与简单排序不同,在排序过程中,将L[1...n]看成是一棵完全二叉树的顺序存储结构,利用二叉树中双亲节点和孩子结点的内在关系(搞清楚各种二叉树的区别),在当前无序区选择关键字最大或最小的元素。

堆的定义:n个关键字序列L[1...n]成为堆,当且仅当满足下列条件之一:

1. L(i)<=L(2i),且L(i)<=L(2i+1) 称为小根堆,也就是满足双亲节点小于孩子节点

2. L(i)>=L(2i),且L(i)>=L(2i+1) 称为大根堆,也就是满足双亲节点大于孩子节点

堆排序的关键是构建初始栈,n个结点的完全二叉树,最后一个结点是第n/2个结点的孩子。对第n/2个结点为根的子树筛选,使该子树成为堆。之后向前依次对各结点为根的子树进行筛选(对于大根堆:若根结点的关键值小于孩子结点中关键值较大者,则交换)。

 堆排序这儿还是遇到了不少麻烦,一定要理清脉络。有一点需要注意,一定要考虑到只有左孩子没有右孩子的情况,网上好多版本都没有考虑到这一特殊情况,因为加入没有右孩子结点你再载入值得话就会触发异常IndexError: list index out of range。

 # -*- coding: cp936 -*-
def buildHeap(arr):
size = len(arr)
for i in range(getParent(size-1),-1,-1):
adjustDown(arr,size-1,i) #注意 size-1不是size def getParent(k):
if k%2==1:
return int(k/2)
else:
return k/2-1 def adjustDown(arr,size,k):#一定要注意size的值
print 'k',k
left = 2*k+1
right = left+1
maxp = k
if left<size and arr[k]<arr[left]:#先判断左孩子
maxp = left
if left<size and right<size:#假如有右孩子,取两个孩子结点的最大值
maxlr = left if arr[left]>arr[right] else right
if left<size and right<size and arr[k]<arr[maxlr]:
maxp = maxlr
if maxp!=k:
arr[maxp],arr[k]=arr[k],arr[maxp]
print arr
adjustDown(arr,size,maxp) def heap(arr):
size = len(arr)
buildHeap(arr)
print 'build',arr
for i in range(size-1,-1,-1):#size-1
arr[i],arr[0]=arr[0],arr[i]
print arr[i],arr[0]
adjustDown(arr,i,0)
return arr arra=[98,36,-9,47,23,1,8]
print heap(arra)

归并排序:

  归并的含义是将两个或两个以上的有序表组合成一个新的有序表。最常见的是2-路归并排序。在程序设计中merge()是把两个有序表合并的操作。递归形式的2-路归并排序算法是基于分治的,其过程如下:

分解:将含有n个元素的待排序表分成各含n/2个元素的子表,采用 2-路归并排序算法对两个子表递归的进行排序

合并:合并两个已排序的子表得到排序结果。

性能分析: 空间复杂度为 O(n),每一趟归并的时间的复杂度为O(n),共需要进行log2n趟归并,所以算法的时间复杂度为 O(nlog2n)。 merge()操作并不会改变相同关键字记录的相对次序,故算法稳定。

 def mergeSort(arr):
if len(arr)<=1:
return arr
mid = len(arr)/2
left=mergeSort(arr[:mid])
right=mergeSort(arr[mid:])
return merge(left,right) def merge(left,right):
result=[]
i,j=0,0
while len(left)>i and len(right)>j:
if left[i]<=right[j]:
result.append(left[i])
i+=1
else:
result.append(right[j])
j+=1
result +=left[i:]
result +=right[j:]
return result arra=[98,36,-9,0,47,23,1,8,10,7]
print mergeSort(arra)

基数排序:

园内 有一篇讲解基数排序的,http://www.cnblogs.com/Braveliu/archive/2013/01/21/2870201.html,图文并茂,很不错,具体概念就不讲解了。这儿我就用python实现一下吧。

 # -*- coding: cp936 -*-
def radixSort_LSD(arr,d):
for i in xrange(d):
S = [[] for j in xrange(10)]
for x in arr:
S[x/(10**i)%10].append(x)
arr = [x for y in S for x in y]
return arr def radixSort_MSD(arr,d):
r = int(d-1)
if r>=0:
S = [[] for j in xrange(10)]
L =[]
for x in arr:
S[x/(10**r)%10].append(x)
for y in S:
M=radixSort_MSD(y,r)
L.append(M)
arr = [x for y in L for x in y]
return arr arra=[98,36,9,0,47,23,1,8,10,7]
print radixSort_MSD(arra,2)
print radixSort_LSD(arra,2)

注意MSD和LSD的区别,

LSD的排序方式由数值的最右边(低位)开始,而MSD则相反,由数值的最左边(高位)开始。

注意一点:LSD的基数排序适用于位数少的数列,如果位数多的话,使用MSD的效率会比较好。

MSD的方式与LSD相反,是由高位数为基底开始进行分配,但在分配之后并不马上合并回一个数组中,而是在每个“桶子”中建立“子桶”,将每个桶子中的数值按照下一数位的值分配到“子桶”中。所以在MSD中我构建了一个L作为子桶。 有没有感觉python非常优雅,简简单单的几句代码就解决了问题。

计数排序: 

  计数排序一般应用于序列元素是正整数的时候,计数排序不是比较排序,排序的速度快于任何比较排序算法。在学习计数排序的时候还是费了很大功夫,一直搞不懂其中的道理。

 # -*- coding: cp936 -*-
def countSort(arr):
size = len(arr)
mini = maxp = arr[0]
for i in arr:#找出最大最小值
if i<mini:
mini = i
if i>maxp:
maxp = i
bound = maxp - mini +1
count = [0 for i in range(bound)]
sorted_arr = [0 for i in range(size)]
for i in range(size):
count[arr[i]-mini]+=1#arr的元素值个数对应count的元素值,
x=0
for i in range(mini,maxp+1):
for j in range(0,count[i-mini]):
sorted_arr[x]=i
x+=1 return sorted_arr
arra=[98,36,5,47,23,1,8]
print countSort(arra)

计数排序的时间复杂度为O(n),这是其他排序方法难以达到的(其他算法的时间复杂度要么为O(n2),要么为O(nlogn))。

排序算法学习,python实现的更多相关文章

  1. 第四百一十五节,python常用排序算法学习

    第四百一十五节,python常用排序算法学习 常用排序 名称 复杂度 说明 备注 冒泡排序Bubble Sort O(N*N) 将待排序的元素看作是竖着排列的“气泡”,较小的元素比较轻,从而要往上浮 ...

  2. 八大排序算法的 Python 实现

    转载: 八大排序算法的 Python 实现 本文用Python实现了插入排序.希尔排序.冒泡排序.快速排序.直接选择排序.堆排序.归并排序.基数排序. 1.插入排序 描述 插入排序的基本操作就是将一个 ...

  3. 常用排序算法的python实现和性能分析

    常用排序算法的python实现和性能分析 一年一度的换工作高峰又到了,HR大概每天都塞几份简历过来,基本上一天安排两个面试的话,当天就只能加班干活了.趁着面试别人的机会,自己也把一些基础算法和一些面试 ...

  4. 十大经典排序算法总结 (Python)

    作业部落:https://www.zybuluo.com/listenviolet/note/1399285 以上链接是自己在作业部落编辑的排序算法总结- Github: https://github ...

  5. 一些排序算法的Python实现

    ''' Created on 2016/12/16 Created by freeol.cn 一些排序算法的Python实现 @author: 拽拽绅士 ''' '''值交换''' def swap( ...

  6. 八大排序算法的python实现(三)冒泡排序

    代码: #coding:utf-8 #author:徐卜灵 #交换排序.冒泡排序 L = [1, 3, 2, 32, 5, 4] def Bubble_sort(L): for i in range( ...

  7. 基本排序算法的Python实现

    本篇主要实现九(八)大排序算法,分别是冒泡排序,插入排序,选择排序,希尔排序,归并排序,快速排序,堆排序,计数排序.希望大家回顾知识的时候也能从我的这篇文章得到帮助. 为了防止误导读者,本文所有概念性 ...

  8. 经典排序算法及python实现

    今天我们来谈谈几种经典排序算法,然后用python来实现,最后通过数据来比较几个算法时间 选择排序 选择排序(Selection sort)是一种简单直观的排序算法.它的工作原理是每一次从待排序的数据 ...

  9. python基础===八大排序算法的 Python 实现

    本文用Python实现了插入排序.希尔排序.冒泡排序.快速排序.直接选择排序.堆排序.归并排序.基数排序. 1.插入排序 描述 插入排序的基本操作就是将一个数据插入到已经排好序的有序数据中,从而得到一 ...

随机推荐

  1. Windows Server 2008 网管数据采集 努力做“日拱一卒“

    Windows Server 2008R2系统管理[刘道军主讲MCITP课程] http://edu.51cto.com/course/course_id-510.html Windows Serve ...

  2. C语言中符号格式说明

    scanf 语法: #include <stdio.h>int scanf( const char *format, ... ); scanf()函数根据由format(格式)指定的格式从 ...

  3. ASP.NET MVC+EF框架+EasyUI实现权限管理系列(14)-主框架搭建

    原文:ASP.NET MVC+EF框架+EasyUI实现权限管理系列(14)-主框架搭建    ASP.NET MVC+EF框架+EasyUI实现权限管系列 (开篇)   (1):框架搭建    (2 ...

  4. 细说 ASP.NET Cache 及其高级用法【转】

    阅读目录 开始 Cache的基本用途 Cache的定义 Cache常见用法 Cache类的特点 缓存项的过期时间 缓存项的依赖关系 - 依赖其它缓存项 缓存项的依赖关系 - 文件依赖 缓存项的移除优先 ...

  5. Java对多线程~~~Fork/Join同步和异步帧

    于Fork/Join骨架,当提交的任务,有两个同步和异步模式.它已被用于invokeAll()该方法是同步的.是任何 务提交后,这种方法不会返回直到全部的任务都处理完了.而还有还有一种方式,就是使用f ...

  6. ArcGIS网络分析之Silverlight客户端最近设施点分析(四)

    原文:ArcGIS网络分析之Silverlight客户端最近设施点分析(四) 在上一篇中说了如何实现最近路径分析,本篇将讨论如何实现最近设施点分析. 最近设施点分析实际上和路径分析有些相识,实现的过程 ...

  7. vim添加自己//解决方案

    使用vim从外面将代码复制并粘贴到时间,假设有一排//凝视.自己主动下一行加入//和每行增加一个<tab>.格全乱:其他编辑器*.c *cpp其他文件格当公式,假设有一排//凝视,按o换行 ...

  8. 【百度地图API】如何利用PhoneGap制作地图APP

    原文:[百度地图API]如何利用PhoneGap制作地图APP 摘要:百度地图API是一套由javascript编写的地图程序接口,按说它应该运行在浏览器上.现在,只要利用PhoneGap,我们就能开 ...

  9. 浏览器扩展系列————异步可插入协议(pluggable protocol)的实现

    原文:浏览器扩展系列----异步可插入协议(pluggable protocol)的实现 IE中有很多我们比较熟悉的协议,如http,https,mailto,ftp等.当然你也可以实现自己定义的协议 ...

  10. PHP经验——获得PHP版本信息及版本比较

    原文:PHP经验--获得PHP版本信息及版本比较 偶然看到别人写的一句代码: <?php if (version_compare("5.2", PHP_VERSION, &q ...