许多程序使用排序作为一个中间步,所以排序是计算机科学中的一个基本操作。
插入排序
原址排序,在任何时候,最多只有其中的常数个数字存储在需要排序的数组外面。
思想:将当前要排序的值插入到正确的位置。
最佳运行时间O(n),最坏情况O(n2),平均O(n2)。
算法描述:
def sort1(A):
for j in range(1, len(A)):
key = A[j]
i = j - 1
while i >= 0 and A[i] > key:
A[i + 1] = A[i]
i = i - 1
A[i + 1] = key
return
冒泡排序
流行但是低效,反复交换相邻的未按次序排序的元素。
运行时间同插排。
算法描述:
def sort2(A):
for i in range(len(A) - 2):
for j in range(len(A) - 1, i, -1):
if A[j] < A[j - 1]:
temp = A[j]
A[j] = A[j - 1]
A[j - 1] = temp
return
归并排序
分治模式:
1. 分解原问题为若干个子问题,这些子问题是原问题的规模较小的实例。
2. 解决这些子问题,递归的求解各个子问题。然而若子问题的规模足够小,则直接求解。
3. 合并这些子问题的解成原问题的解。
平均运行时间与最坏运行时间均为O(nlogn)
算法描述:
def merge(a, p, q, r):
"""
将已经排好序的a[p...q]和a[q+1...r]有序的合并在一起
:param a:
:param p:
:param q:
:param r:
:return:
"""
n1 = q - p + 1
n2 = r - q
L = [0.] * (n1 + 1)
R = [0.] * (n2 + 1)
for i in range(n1):
L[i] = a[p + i]
L[n1] = float("inf") # 设置一个守门员
for i in range(n2):
R[i] = a[q + 1 + i]
R[n2] = float("inf")
i = 0
j = 0
for k in range(p, r + 1):
if L[i] < R[j]:
a[k] = L[i]
i = i + 1
else:
a[k] = R[j]
j = j + 1
return
def sort3(a, p=0, *end):
if 0 == len(end):
r = len(a) - 1
else:
r = end[0]
if p < r:
q = int((p + r) / 2)
sort3(a, p, q)
sort3(a, q + 1, r)
merge(a, p, q, r)
return
希尔排序
希尔排序使用一个序列h1,h2,…,叫做增量序列。在使用增量h的一趟排序之后,对于每一个i有A[i]<=A[i+h],相隔h的元素都被排序。当h=1时整个序列被排序。
最坏情形:使用希尔增量i=i/2:O(n2);使用hibbard增量1,3,7,…,2k-1:O(n2/3)。
算法描述:
def sort4(a):
length = len(a)
increment = int(len(a) / 2)
j = 0
while increment > 0:
for i in range(increment, length):
temp = a[i]
for j in range(i, increment - 1, increment * -1):
if temp < a[j - increment]:
a[j] = a[j - increment]
else: # 最后一次循环是从哪里跳出的
j = j + increment
break
a[j - increment] = temp
increment = int(increment / 2)
return
堆排序
将要排列的数组构造为一个最大堆,依次删除最大值即堆定。
算法复杂度:O(nlogn)
算法描述:
def perc_down(a, i, n):
temp = a[i]
while (2 * i + 1) < n:
child_max = 2 * i + 1
if child_max < (n - 1) and a[child_max] < a[child_max + 1]:
child_max = child_max + 1
if temp < a[child_max]:
a[i] = a[child_max]
i = child_max
else:
break
a[i] = temp
return
def perc_down1(a, i):
child_max = 2 * i + 1
if child_max < len(a):
if child_max < (len(a) - 1):
if a[child_max] < a[child_max + 1]:
child_max = child_max + 1
if a[i] < a[child_max]:
temp = a[i]
a[i] = a[child_max]
a[child_max] = temp
perc_down1(a, child_max)
return
def sort5(a):
for i in range(int((len(a) - 2) / 2), -1, -1):
perc_down(a, i, len(a))
for i in range(len(a) - 1, -1, -1):
temp = a[0]
a[0] = a[i]
a[i] = temp
perc_down(a, 0, i)
return
快排
属于分治的排序算法。
1. 如果S中的元素个数是0或者1,则返回;
2. 取S中任一元素v,称之为枢纽元;
3. 将S-{v}(S中的其他元素)分为两个不相交的集合:S1={x<=v},S2={x>=v};
4. 返回{S1,v,S2}
算法描述:
def swap(a, i, j):
temp = a[i]
a[i] = a[j]
a[j] = temp
return
def median3(a, left, right):
center = int((left + right) / 2)
if a[left] > a[center]:
swap(a, left, center)
if a[left] > a[right]:
swap(a, left, right)
if a[center] > a[right]:
swap(a, center, right)
swap(a, center, right - 1)
return a[right - 1]
def sort6(a, left, right):
if (right - left) >= 3:
pivot = median3(a, left, right)
i = left + 1
j = right - 2
while 1:
while a[i] < pivot:
i = i + 1
while a[j] > pivot:
j = j - 1
if i < j:
swap(a, i, j)
else:
if a[i] < pivot:
swap(a, right - 1, i + 1)
i = i + 1
else:
swap(a, right - 1, i)
break
sort6(a, left, i - 1)
sort6(a, i + 1, right)
else:
if 0 == right - left:
return
elif 1 == right - left:
if a[left] > a[right]:
swap(a, left, right)
return
else:
if a[left] > a[left + 1]:
swap(a, left, left + 1)
if a[left] > a[right]:
swap(a, left, right)
if a[left + 1] > a[right]:
swap(a, left + 1, right)
return