7个经典排序算法
介绍
作为算法入门,排序算法是最最基础的部分,今天整理一下7个经典的排序算法,包括insertionSort,ShellSort,BubbleSort,QuickSort,SelectionSort,HeapSort,MergeSort,并对他们的复杂度做一个对比总结。顺便推荐一个网站Comparison Sorting Algorithms,可以演示算法具体步骤。注意本文代码部分都使用的是python3。
Insertion Sort
主要思想是decrease-and-conquer,遍历整个数组,把小的值往前放,直接上代码:
# input: an array A
# output: a sorted array A
def insertionSort(A):
n = len(A)
if n <= 1:
return A
for i in range(1,n):
v = A[i]
j = i - 1
while j >= 0 and v <= A[j]:
A[j+1] = A[j]
j = j - 1
A[j+1] = v
#print(A)
ShellSort
希尔排序是插入排序的另一个(高阶)版本,可以把一个无序数组变成一个大致有序的数组,然后再通过插入排序就可以高效完成排序了。
def shellSort(A):
n = len(A)
gap = n//2
while gap>0:
for i in range(gap,n):
key = A[i]
while i>gap and A[i-gap]>key:
A[i] = A[i-gap]
i -= gap
A[i] = key
gap //= 2
#A = insertionSort(A)
BubbleSort
冒泡排序(Bubble Sort)也是一种简单直观的排序算法。它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。这个算法的名字由来是因为越小的元素会经由交换慢慢"浮"到数列的顶端。
def bubbleSort(A):
n = len(A)
if n <= 1:
return A
for i in range(n):
# Last i elements are already in place
for j in range(0, n-i-1):
if A[j] > A[j+1] :
A[j], A[j+1] = A[j+1], A[j]
QuickSort
快排的基本思想:通过一趟排序将待排记录分隔成独立的两部分,其中一部分记录的关键字均比另一部分的关键字小,则可分别对这两部分记录继续进行排序,以达到整个序列有序。
def quick_sort(A,l,r):
if l < r:
s = partition(A,l,r)
quick_sort(A,l,s-1)
quick_sort(A,s+1,r)
def partition(A,l,r):
p = A[l] # pivot
i = l
j = r
while i < j:
while i < r and A[i] <= p:
i += 1
while j >= l and A[j] > p:
j -= 1
A[i],A[j] = A[j],A[i]
A[i],A[j] = A[j],A[i] # undo the last swap
A[l],A[j] = A[j],A[l] # bring the pivot to the correct position
return j
SelectionSort
选择排序是一种简单直观的排序算法。原理:首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。
def selectionSort(A):
for i in range(len(A)):
min_idx = i
for j in range(i+1, len(A)):
if A[min_idx] > A[j]:
min_idx = j
A[i], A[min_idx] = A[min_idx], A[i]
HeapSort
堆排序是指利用堆这种数据结构所设计的一种排序算法。堆积是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。堆排序每次利用max heap找到最大的元素,将它放在最末并从堆中删除它,然后继续对剩下的堆进行max heap找最大元素,依次重复这个过程完成排序。
def heapify(arr, n, i):
largest = i
l = 2 * i + 1 # left = 2*i + 1
r = 2 * i + 2 # right = 2*i + 2
if l < n and arr[i] < arr[l]:
largest = l
if r < n and arr[largest] < arr[r]:
largest = r
if largest != i:
arr[i],arr[largest] = arr[largest],arr[i] # 交换
heapify(arr, n, largest)
def heapSort(arr):
n = len(arr)
# Build a maxheap.
for i in range(n, -1, -1):
heapify(arr, n, i)
# 一个个交换元素
for i in range(n-1, 0, -1):
arr[i], arr[0] = arr[0], arr[i] # 交换
heapify(arr, i, 0)
如果你看不懂这个算法,可以试试这个视频。
MergeSort
归并排序是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为2-路归并。
def merge(arr, l, m, r):
n1 = m - l + 1
n2 = r- m
# 创建临时数组
L = [0] * (n1)
R = [0] * (n2)
# 拷贝数据到临时数组 arrays L[] 和 R[]
for i in range(0 , n1):
L[i] = arr[l + i]
for j in range(0 , n2):
R[j] = arr[m + 1 + j]
# 归并临时数组到 arr[l..r]
i = 0 # 初始化第一个子数组的索引
j = 0 # 初始化第二个子数组的索引
k = l # 初始归并子数组的索引
while i < n1 and j < n2 :
if L[i] <= R[j]:
arr[k] = L[i]
i += 1
else:
arr[k] = R[j]
j += 1
k += 1
# 拷贝 L[] 的保留元素
while i < n1:
arr[k] = L[i]
i += 1
k += 1
# 拷贝 R[] 的保留元素
while j < n2:
arr[k] = R[j]
j += 1
k += 1
def mergeSort(arr,l,r):
if l < r:
m = int((l+(r-1))/2)
mergeSort(arr, l, m)
mergeSort(arr, m+1, r)
merge(arr, l, m, r)