提到排序算法,常见的有如下几种:冒泡排序、选择排序、插入排序、快速排序、堆排序、归并排序、希尔排序;查找算法最常见二分查找。这些算法的时间复杂度如下:

算法名称 时间复杂度(一般情况)

冒泡排序

O(n2)

选择排序

O(n2)

插入排序

O(n2)

快速排序

O(nlog2n)

堆排序

O(nlog2n)

归并排序

O(nlog2n)

希尔排序

O(1.3n)

二分查找

O(log2n)

  二分查找前提要求序列必须是有序的,所以下面我先介绍各排序算法的实现。注:默认按照升序排列


1、冒泡排序

  冒泡排序的原理是从序列的第一个元素开始,与相邻的元素比较大小,如果左边的元素比右边的大,则交换两个元素的位置,依次类推,则一个循环完成后,序列中最大的元素就会到达序列的最右侧,通过多次同样的循环操作将序列从小到大排列。代码实现较简单:

 def bubble(array):
for i in range(len(array)-1): # 仅需循环序列长度-1次即可完成排序
for j in range(len(array)-i-1): # 每次循环,右侧排好的元素不在进行比较
if array[j] > array[j+1]:
array[j], array[j+1] = array[j+1], array[j]
return array

  除此之外,冒泡排序算法还有一个优化的写法。假设一个很大的序列,应用冒泡排序完成几次循环后,进行下一次循环发现并没有任何两个元素交换了位置,那说明什么呢?说明该序列已经变成了有序的序列,所以我们不需要在继续比较下去了,此时结束循环以便节省时间,变成代码实现如下:

 def bubble_better(array):
for i in range(len(array)-1):
exchange = False # 每次大循环开始,将此标志设置为False
for j in range(len(array)-i-1):
if array[j] > array[j+1]:
array[j], array[j+1] = array[j+1], array[j]
exchange = True
if not exchange: # 如果此标志为False,说明本次循环没有元素交换位置,则结束整个循环
break
return array

2、选择排序

  选择排序的原理是从序列中选择出最小的元素,放在序列的最左边,然后从剩下的元素中继续寻找最小的元素,放在最左边元素的右边,依次类推,右侧无序的元素越来越少,左侧有序元素越来越多,直至完成排序。代码实现如下:

 def choice(array):
for i in range(len(array)-1):
min_index = i
for j in range(i+1, len(array)):
if array[min_index] > array[j]:
min_index = j
array[i], array[min_index] = array[min_index], array[i]
return array

3、插入排序

  插入排序的原理是从序列的第二个元素开始循环至序列最后,每次循环从当前元素开始不断的与左边相邻的元素进行比较,如果左边的元素较大,则交换两个元素位置,这样序列左边逐步有序。代码实现如下:

 def insert_sort(array):
for i in range(1, len(array)):
while i > 0 and array[i] < array[i-1]:
array[i], array[i-1] = array[i-1], array[i]
i -= 1
return array

4、快速排序

  快速排序的原理是取序列的第一个元素为基准元素,指定两个指针分别指向序列的开始和结尾,拿结尾指针指向的元素与基准元素比较,如果该元素比基准元素大,则指针减一继续比较,一旦发现比基准元素小的元素,则将该元素放至序列的最左侧,然后拿开始指针指向的元素与基准元素比较,如果该元素比基准元素小,则指针增一继续比较,一旦发现比基准元素大的元素,则将该元素放至结尾指针指向的位置,重复上述过程,则比基准元素大的元素全部到了基准元素右侧,比基准元素小的元素全部到了基准元素左侧,然后对左右两部分继续上述过程,不难发现可应用递归完成最终的排序。

  单次排序代码实现如下:

 # 快速排序中的一次调整,即将第一个元素放在某个位置,使该元素右边的元素都比该元素大,左边的元素都比该元素小
def query_mid(array, left, right):
tmp = array[left]
while left < right:
while left < right and tmp <= array[right]:
right -= 1
array[left] = array[right]
while left < right and tmp >= array[left]:
left += 1
array[right] = array[left]
array[left] = tmp
return left

  应用递归完成全部排序,代码实现如下:

 # 应用递归实现快速排序
def _quick_sort(array, left, right):
if left < right:
mid = query_mid(array, left, right)
_quick_sort(array, left, mid-1)
_quick_sort(array, mid+1, right)
return array

5、堆排序

  堆排序应用了二叉树这种数据结构-完全二叉树,分为大顶堆(父节点比任一孩子节点都大)和小顶堆(父节点比任一孩子节点都小),该排序算法的原理是首先将序列构造成大顶堆或者小顶堆,然后取下堆顶元素,将最后一个孩子节点放至堆顶位置,对堆进行调整,变成大顶堆或者小顶堆,通过不断的取下堆顶元素形成一个有序的序列。

  堆得一次构造过程代码实现如下:

 # 构建堆的调整过程
def shift(array, low, high):
tmp = array[low]
i = low
j = 2 * i + 1
while j <= high:
if j + 1 <= high and array[j] < array[j + 1]:
j += 1
if tmp < array[j]:
array[i] = array[j]
i = j
j = 2 * i + 1
else:
break
array[i] = tmp

  排序过程代码实现如下:

 def heap_sort(array):
n = len(array)
# 将array构造成大顶堆
for i in range(n//2-1, -1, -1):
shift(array, i, n-1)
# 从堆顶开始取数
for i in range(n):
array[0], array[n-1-i] = array[n-1-i], array[0]
shift(array, 0, n-i-2)
return array

6、归并排序

  归并排序分为分解与合并两个过程,分解过程是将序列细分成两两元素的比较,然后在合并这些两两有序的元素,不断扩大合并,这种合并过程就是序列分成两部分,每一部分都是有序的,然后将这两部分合并成一个大的有序的序列。

  一次归并排序的代码实现如下:

 # 一次归并排序
def merge(array, low, mid, high):
tmp_list = []
i = low
j = mid + 1
while i <= mid and j <= high:
if array[i] < array[j]:
tmp_list.append(array[i])
i += 1
elif array[i] > array[j]:
tmp_list.append(array[j])
j += 1
else:
tmp_list.append(array[i])
i += 1
if j <= high:
for num in array[j:high+1]:
tmp_list.append(num)
if i <= mid:
for num in array[i:mid+1]:
tmp_list.append(num)
array[low:high+1] = tmp_list
return array

  应用递归实现分解与合并的过程代码实现如下:

 def _merge_sort(array, low, high):
if low < high:
mid = (low+high) // 2
_merge_sort(array, low, mid)
_merge_sort(array, mid+1, high)
merge(array, low, mid, high)
return array

7、希尔排序

  希尔排序的原理是,针对待排序的序列,选定一个步长(初始步长一般为序列长度一半),拿出索引相差该步长位置的元素进行插入排序,然后步长减半,再次拿出索引相差该步长位置的元素进行插入排序,直至步长变为1。该排序代码实现如下:

 def shell_sort(array):
gap = len(array) // 2
while gap >= 1:
for i in range(gap, len(array)):
tmp = array[i]
j = i - gap
while j >= 0 and array[j] > tmp:
array[j+gap] = array[j]
j -= gap
array[j+gap] = tmp
gap = gap / 2
return array

  基于以上算法对序列进行排序后,就可以应用二分查找来查找相应的元素,每次拿序列的中间位置元素与被查找元素比较,如果中间位置元素比被查找元素小,则在中间元素右侧的序列中继续该方式查找;如果中间位置元素比被查找元素大,则在中间元素左侧的序列中继续该方式查找,通过该方式每次将范围缩短一半,大大缩短了查找时间,代码实现较简单,如下:

 def half_find(array, data):
begin = 0
end = len(array) - 1
while begin <= end:
mid = (begin+end) // 2
if array[mid] == data:
return '%s founded at %s' % (data, mid)
elif array[mid] > data:
end = mid - 1
else:
begin = mid + 1
return 'not found'

各算法运行时间比较

  这里构造了一个长度为10000的列表,打乱元素顺序,分别应用以上算法对该列表进行排序,通过一个计算运行时间的装饰器计算出各个排序算法所耗时间,装饰器代码如下:

 # 计算算法执行时间装饰器
def use_time(func):
def use_time_inner(*args, **kwargs):
begin_time = time.time()
f = func(*args, **kwargs)
end_time = time.time()
global t
t = end_time - begin_time
print('use time(%s):%ss' % (func.__name__, t))
return f
return use_time_inner

  使用该装饰器对各个算法进行装饰,执行以下代码得出时间:

 # 生成序列
a = list(range(10000))
random.shuffle(a)
l1 = copy.copy(a)
l2 = copy.copy(a)
l3 = copy.copy(a)
l4 = copy.copy(a)
l5 = copy.copy(a)
l6 = copy.copy(a)
l7 = copy.copy(a)
l8 = copy.copy(a) # 各排序算法执行
r1 = bubble_sort(l1) # 冒泡排序
r2 = bubble_better(l2) # 冒泡排序优化
r3 = choice_sort(l3) # 选择排序
r4 = insert_sort(l4) # 插入排序
r5 = quick_sort(l5) # 快速排序
r6 = heap_sort(l6) # 堆排序
r7 = merge_sort(l7) # 归并排序
r8 = shell_sort(l8) # 希尔排序 # 二分查找执行
r9 = half_find(r6, random.randint(0, len(a)))

  运行结果如下,可以看到冒泡、选择、插入排序与其他排序算法时间相差还是很悬殊的!

use time(bubble_sort):15.331599950790405s
use time(bubble_better):14.486400127410889s
use time(choice_sort):7.4547998905181885s
use time(insert_sort):13.032400131225586s
use time(quick_sort):0.062399864196777344s
use time(heap_sort):0.062400102615356445s
use time(merge_sort):0.062400102615356445s
use time(shell_sort):0.07799983024597168s
use time(half_find):0.0s

常见算法的python实现的更多相关文章

  1. 几种常见算法的Python实现

    1.选择排序 选择排序是一种简单直观的排序算法.它的原理是这样:首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的后 ...

  2. 常见排序算法之python实现

    冒泡排序 简介 冒泡排序(英语:Bubble Sort)是一种简单的排序算法.它重复地遍历要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来.遍历数列的工作是重复地进行直到没有再需要交 ...

  3. Python的十种常见算法

    十种排序算法 1. 常见算法分类 十种常见排序算法一般分为以下几种: (1)非线性时间比较类排序: ​ a. 交换类排序(快速排序.冒泡排序) ​ b. 插入类排序(简单插入排序.希尔排序) ​ c. ...

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

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

  5. 机器学习算法与Python实践之(五)k均值聚类(k-means)

    机器学习算法与Python实践这个系列主要是参考<机器学习实战>这本书.因为自己想学习Python,然后也想对一些机器学习算法加深下了解,所以就想通过Python来实现几个比较常用的机器学 ...

  6. 狄克斯特拉算法(Python实现)

    概述 狄克斯特拉算法--用于在加权图中找到最短路径 ps: 广度优先搜索--用于解决非加权图的最短路径问题 存在负权边时--贝尔曼-福德算法 下面是来自维基百科的权威解释. 戴克斯特拉算法(英语:Di ...

  7. 常见数据结构的 Python 实现(建议收藏)

    数据结构作为计算机基础的必修内容,也是很多大型互联网企业面试的必考题.可想而知,它在计算机领域的重要性. 然而很多计算机专业的同学,都仅仅是了解数据结构的相关理论,却无法用代码实现各种数据结构. 今日 ...

  8. 数据结构与算法(Python)

    数据结构与算法(Python) Why? 我们举一个可能不太恰当的例子: 如果将最终写好运行的程序比作战场,我们码农便是指挥作战的将军,而我们所写的代码便是士兵和武器. 那么数据结构和算法是什么?答曰 ...

  9. Hadoop学习笔记—12.MapReduce中的常见算法

    一.MapReduce中有哪些常见算法 (1)经典之王:单词计数 这个是MapReduce的经典案例,经典的不能再经典了! (2)数据去重 "数据去重"主要是为了掌握和利用并行化思 ...

随机推荐

  1. 【OpenJ_Bailian - 2192】Zipper(dfs)

    Zipper Descriptions: Given three strings, you are to determine whether the third string can be forme ...

  2. MySQL调优之数据类型选择原则

    本文涉及:高可用数据库设计时数据类型的选择原则 在进行数据库设计时,如果能够选择最恰当的数据类型就可以为后期的数据库调优打好最坚实的基础 选择数据类型的原则 更小的通常更好 例如存储订单状态字段很多时 ...

  3. QString:常用成员函数总结

    QString是Qt中使用频率最高的几种数据类型之一,主要在于其提供了大量功能强大的成员函数,这里重点介绍一些常用的成员函数: 一.字符串处理相关 1.1 split() (拆分字符串) split( ...

  4. Poj 3294 Life Forms (后缀数组 + 二分 + Hash)

    题目链接: Poj 3294 Life Forms 题目描述: 有n个文本串,问在一半以上的文本串出现过的最长连续子串? 解题思路: 可以把文本串用没有出现过的不同字符连起来,然后求新文本串的heig ...

  5. treap板子(洛谷 P3369 【模板】普通平衡树(Treap/SBT))

    由于有相同的数,每个节点加一个权值表示此数出现的次数 #include<cstdio> #include<cstdlib> #include<ctime> #inc ...

  6. Web常见几种攻击与预防方式

    DoS和DDoS攻击 DoS(Denial of Service),即拒绝服务,造成远程服务器拒绝服务的行为被称为DoS攻击.其目的是使计算机或网络无法提供正常的服务.最常见的DoS攻击有计算机网络带 ...

  7. js ajax 数组类型参数传递

    若一个请求中包含多个值,如:(test.action?tid=1&tid=2&tid=3),参数都是同一个,只是指定多个值,这样请求时后台会发生解析错误,应先使用 tradititon ...

  8. 在阿里云上搭建nginx + ThinkPHP 的实践

    作为一个程序猿,理应用linux系统来作为平时的工作机环境,哎,之前倒是用过一段时间的linux,可惜后来换了本本,后来竟然没有保持,嗷嗷后悔中... 废话不多说,大家用windows的理由都一样,但 ...

  9. Android常规布局(网络异常布局、空数据布局,未登录布局等)切换工具类,Layout切换

    本人已整理好发布到github,已优化. github地址:https://github.com/buhuiming/StatusLayoutManager 使用:compile 'com.bhm.s ...

  10. AndroidStudio启动App时,数据取不到。

    最近在用AndroidStudio开发App的时候,所连的服务器如果是换成本机上的,那么启动App的时候数据就读取不出来,连其它电脑上的服务器就是正常的,如下: 05-11 09:36:57.178 ...