排序算法

下面算法均是使用Python实现:

插入排序

原理:在要排序的一组数中,假定前n-1个数已经排好序,现在将第n个数插到前面的有序数列中,使得这n个数也是排好顺序的。如此反复循环,直到全部排好顺序。通常使用在长度较小的数组的情况以及作为其它复杂排序算法的一部分,比如mergesort或quicksort。时间复杂度为 O(n^2) 。

# 1nd: 两两交换
def insertion_sort(seq):
   for i in range(1, len(seq)):
       j = i
       while j >= 0 and seq[j-1] > seq[j]:
           seq[j], seq[j-1] = seq[j-1], seq[j]
           j -= 1
   return seq


# 2nd: 交换,最后处理没交换的
def insertion_sort2(seq):
   for i in range(1, len(seq)):
       j = i-1
       key = seq[i]
       while j >= 0 and seq[j] > key:
           seq[j+1] = seq[j]
           j -= 1
       seq[j+1] = key
   return seq


# 3nd: 加速版本,利用已经排好了序的进行二分查找
def insertion_sort3(seq):
   for i in range(1, len(seq)):
       key = seq[i]
       # invariant: ``seq[:i]`` is sorted
       # find the least `low' such that ``seq[low]`` is not less then `key'.
       #   Binary search in sorted sequence ``seq[low:up]``:
       low, up = 0, i
       while up > low:
           middle = (low + up) // 2
           if seq[middle] < key:
               low = middle + 1
           else:
               up = middle
       # insert key at position ``low``
       seq[:] = seq[:low] + [key] + seq[low:i] + seq[i + 1:]
   return seq


# 4nd: 原理同上,使用bisect,面试不推荐使用
import bisect


def insertion_sort4(seq):
   for i in range(1, len(seq)):
       bisect.insort(seq, seq.pop(i), 0, i)  # 默认插在相同元素的左边

   return seq

选择排序

原理:每一趟都选择当前后面最小的值和当前下标的值进行交换,适用在大型的数组,时间复杂度为 O(n^2)

# 1nd: for
def select_sort(seq):
   for i in range(0, len(seq)):
       mi = i
       # 选择坐标i后的最小值
       for j in range(i, len(seq)):
           if seq[j] < seq[mi]:
               mi = j
       seq[mi], seq[i] = seq[i], seq[mi]
   return seq


# 2nd: min
def select_sort2(seq):
   for i, x in enumerate(seq):
       mi = min(range(i, len(seq)), key=seq.__getitem__)
       seq[i], seq[mi] = seq[mi], x
   return seq

冒泡排序

原理:比较数组中两两相邻的数,如果前者大于后者,就进行交换,重复地走访过要排序的数列,达到将最小的值移动到最上面的目的,适用于小型数组,时间复杂度为O(n^2)

def bubble_sort(seq):
   for i in range(len(seq)-1):
       j = len(seq)-1
       while j > i:
           if seq[j] < seq[j-1]:
               seq[j], seq[j-1] = seq[j-1], seq[j]
           j -= 1
   return seq


def bubble_sort2(seq):
   for i in range(0, len(seq)):
       for j in range(i + 1, len(seq)):
           if seq[i] > seq[j]:
               seq[i], seq[j] = seq[j], seq[i]
   return seq

快速排序

原理:从数组中选择pivot,分成两个数组,一个是比pivot小,一个是比pivot大,最后将这两个数组和pivot进行合并,最好情况下时间复杂度为O(n log n),最差情况下时间复杂度为O(n^2)

def quick_sort(seq):
   if len(seq) <= 1:
       return seq

   pivot_idx = len(seq) // 2  # 将中间作为基准
   small, large = [], []
   for idx, val in enumerate(seq):
       if idx != pivot_idx:
           if val <= seq[pivot_idx]:
               small.append(val)
           else:
               large.append(val)
   small = quick_sort(small)
   large = quick_sort(large)
   return small + [seq[pivot_idx]] + large
 
def quick_sort(seq, left, right):
   """
  单纯移动下标的实现
  :param seq:
  :param left:
  :param right:
  :return:
  """
   if left >= right:
       return seq

   # 选择参考点,该调整范围的第1个值
   target = seq[left]
   i, j = left, right

   # 循环判断直到遍历全部
   while i < j:
       # 从右边开始查找大于参考点的值
       while i < j and seq[j] >= target:
           j -= 1
       seq[i] = seq[j]  # 这个位置的值先挪到左边

       # 从左边开始查找小于参考点的值
       while i < j and seq[i] <= target:
           i += 1
       seq[j] = seq[i]  # 这个位置的值挪到右边

   # 写回改成的值
   seq[i] = target
   # 递归,并返回结果
   quick_sort(seq, left, i - 1)  # 递归左边部分
   quick_sort(seq, i + 1, right)  # 递归右边部分
   return seq

归并排序

原理:归并排序是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。

# 1nd: 将两个有序数组合并到一个数组
def merge(left, right):
   i, j = 0, 0
   result = []
   while i < len(left) and j < len(right):
       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


def merge_sort(seq):
   if len(seq) <= 1:
       return seq

   mid = len(seq) // 2
   left = merge_sort(seq[:mid])
   right = merge_sort(seq[mid:])
   return merge(left, right)


# 2nd: use merge,面试不推荐使用
from heapq import merge


def merge_sort2(m):
   if len(m) <= 1:
       return m

   middle = len(m) // 2
   left = m[:middle]
   right = m[middle:]

   left = merge_sort(left)
   right = merge_sort(right)
   return list(merge(left, right))

堆排序

原理:堆排序(Heapsort)是指利用堆积树(堆)这种数据结构所设计的一种排序算法,是选择排序的一种。可以利用数组的特点快速定位指定索引的元素。堆分为大根堆和小根堆,是完全二叉树。大根堆的要求是每个节点的值都不大于其父节点的值。一般升序采用大顶堆,降序采用小顶堆。平均时间复杂度为O(n logn)。

def heapify(seq, start, end):
   """
  找出从start到end的范围内的最大值,放在堆顶的位置
  :param seq:
  :param start:
  :param end:
  :return:
  """
   # start结点的左右子结点
   left, right = 2 * start + 1, 2 * (start + 1)
   ma = start
   # 选出最大值
   if left < end and seq[start] < seq[left]:
       ma = left
   if right < end and seq[ma] < seq[right]:
       ma = right
   if ma != start:
    # 找到最大值后调整位置
       seq[start], seq[ma] = seq[ma], seq[start]
       heapify(seq, ma, end)


def heap_sort(seq):
   start, end = len(seq) // 2 - 1, len(seq)
   # 创建堆,i从根结点开始调整
   for i in range(start, -1, -1):
       heapify(seq, i, end)

   # 调整堆,将堆顶元素与末尾元素进行交换,使末尾元素最大。
   # 然后继续调整堆,再将堆顶元素与末尾元素交换,得到第二大元素。如此反复进行交换、重建、交换
   for i in range(end - 1, 0, -1):
       seq[i], seq[0] = seq[0], seq[i]
       heapify(seq, 0, i)

   return seq


# 2nd: use heapq
import heapq


def heap_sort2(seq):
   """ Implementation of heap sort """
   heapq.heapify(seq)
   return [heapq.heappop(seq) for _ in range(len(seq))]

希尔排序

原理:希尔排序(Shell Sort)是插入排序的一种。也称缩小增量排序,是直接插入排序算法的一种更高效的改进版本。希尔排序是非稳定排序算法。希尔排序是把记录按下标的一定增量分组,对每组使用直接插入排序算法排序;随着增量逐渐减少,每组包含的关键词越来越多,当增量减至1时,整个文件恰被分成一组,算法便终止。

def shell_sort(seq):
   count = len(seq)
   step = 2
   group = count // step
   while group > 0:
       for i in range(0, group):
           j = i + group
           while j < count:
               k = j - group
               key = seq[j]
               while k >= 0:
                   if seq[k] > key:
                       seq[k + group] = seq[k]
                       seq[k] = key
                   k -= group
               j += group
       group //= step
   return seq

区别

Python 实现排序算法的更多相关文章

  1. Python之排序算法:快速排序与冒泡排序

    Python之排序算法:快速排序与冒泡排序 转载请注明源地址:http://www.cnblogs.com/funnyzpc/p/7828610.html 入坑(简称IT)这一行也有些年头了,但自老师 ...

  2. python实现排序算法 时间复杂度、稳定性分析 冒泡排序、选择排序、插入排序、希尔排序

    说到排序算法,就不得不提时间复杂度和稳定性! 其实一直对稳定性不是很理解,今天研究python实现排序算法的时候突然有了新的体会,一定要记录下来 稳定性: 稳定性指的是 当排序碰到两个相等数的时候,他 ...

  3. python常见排序算法解析

    python——常见排序算法解析   算法是程序员的灵魂. 下面的博文是我整理的感觉还不错的算法实现 原理的理解是最重要的,我会常回来看看,并坚持每天刷leetcode 本篇主要实现九(八)大排序算法 ...

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

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

  5. Python实现排序算法之快速排序

    Python实现排序算法:快速排序.冒泡排序.插入排序.选择排序.堆排序.归并排序和希尔排序 Python实现快速排序 原理 首先选取任意一个数据(通常选取数组的第一个数)作为关键数据,然后将所有比它 ...

  6. python 经典排序算法

    python 经典排序算法 排序算法可以分为内部排序和外部排序,内部排序是数据记录在内存中进行排序,而外部排序是因排序的数据很大,一次不能容纳全部的排序记录,在排序过程中需要访问外存.常见的内部排序算 ...

  7. python——常见排序算法解析

    算法是程序员的灵魂. 下面的博文是我整理的感觉还不错的算法实现 原理的理解是最重要的,我会常回来看看,并坚持每天刷leetcode 本篇主要实现九(八)大排序算法,分别是冒泡排序,插入排序,选择排序, ...

  8. python之排序算法

    排序是每个语言都需要学会的,不管是c++.java还是python,套路都是类似的 python中也有自带的排序函数sort,直接使用也可 闲来无事写了几个排序算法,各不相同 1.每次遇到最小的数都交 ...

  9. Python 八大排序算法速度比较

    这篇文章并不是介绍排序算法原理的,纯粹是想比较一下各种排序算法在真实场景下的运行速度. 算法由 Python 实现,用到了一些语法糖,可能会和其他语言有些区别,仅当参考就好. 测试的数据是自动生成的, ...

随机推荐

  1. Quartz使用-入门使用

    注:这里使用的是Quartz1.6.5版本(包:quartz-1.6.5.jar) //测试main函数 //QuartzTest.java package quartzPackage; import ...

  2. 编写高质量代码改善程序的157个建议:第87个建议之区分WPF和WinForm的线程模型

    今天有时间了,继续<编写高质量代码改善程序的157个建议>的阅读,当我阅读到建议87的时候,里面的一些代码示例和文中所说的不一致了,是不是我现在用的是NetFramework 4.0的缘故 ...

  3. nth-child 和nth-type的区别

    一.深呼吸,直接内容:nth-child和:nth-of-type都是CSS3中的伪类选择器,其作用近似却又不完全一样,对于不熟悉的人对其可能不是很区分,本文就将介绍两者的不同,以便于大家正确灵活使用 ...

  4. angular.js ng-repeat渲染时出现闪烁问题解决

    当我们前端运用到angular.js框架时,想必大家都会遇到一些坑.其中,我也来分享一个常见的angular.js渲染时出现的坑. 当我们进行页面渲染时,绑定表达式最开始会用{{data.name}} ...

  5. VB6之扫雷克星

    很久之前,那时候我还不太会玩(现在也不厉害)扫雷这个游戏,同学总在我面前炫耀自己的技术有多叼.“高级,99颗雷,只需三分钟...”,如此这般.也许确实需要天赋,我总要排查个半天才敢点下左键,然后就BO ...

  6. God 1.1.1 多线程之内存可见性

    共享变量在线程间的可见性 synchronize实现可见性 volatile实现可见性 指令重排序 as-if-serial语义 volatile使用注意事项 synchronized和volatil ...

  7. (转)基于 Token 的身份验证

    原文:https://ninghao.net/blog/2834 最近了解下基于 Token 的身份验证,跟大伙分享下.很多大型网站也都在用,比如 Facebook,Twitter,Google+,G ...

  8. 一颗简单的hibernate栗子

    Hibernate是一个开源的ORM框架,顾名思义,它的核心思想即ORM(Object Relational Mapping,对象关系映射),可以通过对象来操作数据库中的信息,据说开发者一开始是不太熟 ...

  9. JavaScript跨域请求和jsonp请求实例

    <script type="text/javascript" src="./whenReady.js"></script> <sc ...

  10. 在ASP.NET MVC中利用Aspose.cells 将查询出的数据导出为excel,并在浏览器中下载。

    正题前的唠叨 本人是才出来工作不久的小白菜一颗,技术很一般,总是会有遇到一些很简单的问题却不知道怎么做,这些问题可能是之前解决过的.发现这个问题,想着提升一下自己的技术水平,将一些学的新的'好'东西记 ...