排序算法学习,python实现
原创博文,转载请注明出处
利用周六周末的时间把几种基本的排序方法用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实现的更多相关文章
- 第四百一十五节,python常用排序算法学习
第四百一十五节,python常用排序算法学习 常用排序 名称 复杂度 说明 备注 冒泡排序Bubble Sort O(N*N) 将待排序的元素看作是竖着排列的“气泡”,较小的元素比较轻,从而要往上浮 ...
- 八大排序算法的 Python 实现
转载: 八大排序算法的 Python 实现 本文用Python实现了插入排序.希尔排序.冒泡排序.快速排序.直接选择排序.堆排序.归并排序.基数排序. 1.插入排序 描述 插入排序的基本操作就是将一个 ...
- 常用排序算法的python实现和性能分析
常用排序算法的python实现和性能分析 一年一度的换工作高峰又到了,HR大概每天都塞几份简历过来,基本上一天安排两个面试的话,当天就只能加班干活了.趁着面试别人的机会,自己也把一些基础算法和一些面试 ...
- 十大经典排序算法总结 (Python)
作业部落:https://www.zybuluo.com/listenviolet/note/1399285 以上链接是自己在作业部落编辑的排序算法总结- Github: https://github ...
- 一些排序算法的Python实现
''' Created on 2016/12/16 Created by freeol.cn 一些排序算法的Python实现 @author: 拽拽绅士 ''' '''值交换''' def swap( ...
- 八大排序算法的python实现(三)冒泡排序
代码: #coding:utf-8 #author:徐卜灵 #交换排序.冒泡排序 L = [1, 3, 2, 32, 5, 4] def Bubble_sort(L): for i in range( ...
- 基本排序算法的Python实现
本篇主要实现九(八)大排序算法,分别是冒泡排序,插入排序,选择排序,希尔排序,归并排序,快速排序,堆排序,计数排序.希望大家回顾知识的时候也能从我的这篇文章得到帮助. 为了防止误导读者,本文所有概念性 ...
- 经典排序算法及python实现
今天我们来谈谈几种经典排序算法,然后用python来实现,最后通过数据来比较几个算法时间 选择排序 选择排序(Selection sort)是一种简单直观的排序算法.它的工作原理是每一次从待排序的数据 ...
- python基础===八大排序算法的 Python 实现
本文用Python实现了插入排序.希尔排序.冒泡排序.快速排序.直接选择排序.堆排序.归并排序.基数排序. 1.插入排序 描述 插入排序的基本操作就是将一个数据插入到已经排好序的有序数据中,从而得到一 ...
随机推荐
- Xcode-5.1.1更改文件盯作者
原来的文件默认是用户开机时的username ,网上说什么改通讯录事实上都是不正确的. 1.首先打开偏好设置,选择用户群组 2.进入用户界面 改动全名.此时要求你输入用户的password才干改动us ...
- jdk1.7 变更
个人实遇: 1.6与1.7 :SimpleDateFormat,1.6要求yyyy必须小写,1.7兼容大小写: jdk 8 新特性: 官方pdf文档(英文版)私人下载地址:http://pan.bai ...
- 《STL源代码分析》---stl_list.h读书笔记
STL在列表list它是一种经常使用的容器.list不连续双向链表在内存,而且是环形. 理解列表如何操作的详细信息,然后.阅读STL名单上的代码是最好的方法. G++ 2.91.57.cygnus\c ...
- Git批量删除
Git批量删除 git的改动都需要stage过程后才能commit.当git中有大量改动时就需要能够批量操作在方便.改动分三种: modify: 有文件修改 add: 有文件增加 rm: 有文件删除 ...
- 关于C#操作INI文件的总结
原文:关于C#操作INI文件的总结 INI文件其实是一种具有特定结构的文本文件,它的构成分为三部分,结构如下: [Section1]key 1 = value2key 1 = value2--[S ...
- Ubuntu14.04安装一个小问题,搜狗输入法
罕见的搜狗输入法支持ubuntu.尝试了决定性下载. 官方网站:http://pinyin.sogou.com/linux/ 官网教程:http://pinyin.sogou.com/linux/he ...
- 试想一下,在代码学习Swift!
文件 https://itunes.apple.com/us/book/the-swift-programming-language/id881256329?mt=11 htt ...
- shell的定义
shell一些符号区别对待不同的定义.主要的定义3途径: (1)单引號 (2)双引號 (3)反引號 我们最经常使用的就是双引號和单引號.对于这2个符号,用$变量能够非常清楚的说明它们的差别,例如以下: ...
- Linux开发环境的搭建和使用——Linux本必备软件SSH
SSH 至 Secure Shell 缩写.由 IETF 网络工作组(Network Working Group)开发:SSH 以建立应用层和传输层安全协议中的基础上. SSH 是眼下较可靠,专为远程 ...
- 自己定义View之绘制圆环
一.RingView 自己定义的view,构造器必须重写,至于重写哪个方法,參考例如以下: ①假设须要改变View绘制的图像,那么须要重写OnDraw方法.(这也是最经常使用的重写方式.) ②假设须要 ...