排序
- 接前面
- 分类
- 插入排序
- 希尔排序改造
- 选择排序
- 堆排序改造
- 交换排序
- 非递归快速排序
- 分配排序
- 基数分配排序改造
- 归并排序
- 归并排序改造
- 点数排序
- 测试
接前面
排序——万亿数量级里有的排序算法很快,有的却比较慢。上帝在打开一扇牗的时候会关上一樘门,这扇门就是稳定性。书上用的是
49
′
{49}'
49′,这里用二元组。看排序后(5,1), (5,4),(5,12)的位置会不会发生变化。
test=[(5,1), (11,2),(3,3), (5,4), (56,5), (65,6), (1,7), (8,8), (2,9), (6,10), (7,11), (5,12)]
![]() |
---|
分类
插入排序
直接插入排序、二分法插入排序、表插入排序和希尔排序都是插入排序。只有希尔排序是不稳定的,其他都是稳定的。
希尔排序改造
def shellSort(nums):#希尔步长缩小后移插入排序,不稳定
n = len(nums)
gap = n // 3
while gap > 0:#n/3,每次缩小1/3,
for i in range(gap, n):#每次加大
anchor = nums[i]
j = i
while j >= gap and nums[j - gap][0] > anchor[0]:#从搜索一个到全部,
nums[j] = nums[j - gap]
j -= gap
nums[j] = anchor
#gap = gap // 2
gap = (gap - 1)//3
return nums
这里用的步长是 1 3 \frac{1}{3} 31,据说这样的效果更好。nums[j - gap][0] > anchor[0]比较元组的第一个元素。
选择排序
直接选择排序和堆排序。都不稳定。直接选择排序指定i与剩下所有的j比,确定i的位置,选小的时候把后面大的相同的顺序打乱了。大堆选择排序每次 2 ∗ i d x + 1 2*idx + 1 2∗idx+1跳着比较也会打乱顺序。
堆排序改造
def heapify(a, idx, m):
left = 2*idx + 1
right = 2*idx + 2
if left < m and a[left][0] > a[idx][0]:
largest = left
else:
largest = idx
if right < m and a[right][0] > a[largest][0]:
largest = right
if largest != idx:
a[idx], a[largest] = a[largest], a[idx]
heapify(a, largest, m)
def buildheap(a):
n = len(a)
for i in range((n//2) - 1, -1, -1):#从后往前
heapify(a, i, n)
def heapS(a):#不稳定,堆选择排序
buildheap(a)
for i in range(len(a) - 1, 0, -1):
a[0], a[i] = a[i], a[0]
heapify(a, 0, i)
交换排序
起泡排序(稳定)、快速排序(不稳定)。两两比较,交换不满足顺序要求的两个值,直到全部满足为止。
非递归快速排序
def quick(alist):#非递归
assert len(alist) >= 2
q = []
q.append((0,len(alist)-1))
while q:
start, end = q.pop()
mid = alist[start]#mid is the pivot of the partition
low = start
high = end
while low < high:
while low < high and alist[high][0] >= mid[0]:
high -= 1
alist[low] = alist[high]
while low < high and alist[low][0] < mid[0]:
low += 1
alist[high] = alist[low]
alist[low] = mid
if low - 1 > start:
q.append((start, low - 1))
if low + 1 < end:
q.append((low + 1, end))
分配排序
基数排序,把排序码分解成若干部分排序。稳定
基数分配排序改造
def radixSort(L, r=10):#分配排序,基数排序,稳定
k = 10#int(math.ceil(math.log(max(L), r)))
b = [[] for i in range(r)]
for i in range(1, k+1):#循环位数次
for j in L:#循环n次
b[int(j[0] / (r ** (i-1)) % r)].append(j)
del L[:]#分桶后清空list L
for z in b:
L += z
del z[:]#l再装桶后,清除临时数组
return -1
归并排序
稳定
归并排序改造
def merge(L, R):#稳定
'''L and R merge together
'''
iL, iR = 0, 0
result = []
while iL < len(L) and iR < len(R):
if L[iL][0] <= R[iR][0]:
result.append(L[iL])
iL += 1
else:
result.append(R[iR])
iR += 1
result += L[iL:]
result += R[iR:]
return result
def merge_sort(alist):#T(n)=2T(n/2)+n的解为T(n)=O(nlogn)
if len(alist) <= 1:
return alist
#Int is a decimal truncation method, not rounding, int (x+0.5) can be rounded.
m = int(len(alist) // 2)
L = merge_sort(alist[:m])
R = merge_sort(alist[m:])
#from two to len(alist) to return merge_sort
return merge(L, R)
L[iL][0] <= R[iR][0]比较元组的第一个元素。
点数排序
稳定
测试
test=[(5,1), (11,2),(3,3), (5,4), (56,5), (65,6), (1,7), (8,8), (2,9), (6,10), (7,11), (5,12)]
shellx = test.copy()
print("希尔插入排序",shellSort(shellx))
heapx = test.copy()
heapS(heapx)
print("大堆选择排序",heapx)
quickx = test.copy()
quick(quickx)
print("快速交换排序",quickx)
radixx = test.copy()
radixSort(radixx)
print("基数分配排序",radixx)
mergex = test.copy()
print("归并稳定排序",merge_sort(mergex))
希尔插入排序 [(1, 7), (2, 9), (3, 3), (5, 4), (5, 1), (5, 12), (6, 10), (7, 11), (8, 8), (11, 2), (56, 5), (65, 6)]
大堆选择排序 [(1, 7), (2, 9), (3, 3), (5, 1), (5, 12), (5, 4), (6, 10), (7, 11), (8, 8), (11, 2), (56, 5), (65, 6)]
快速交换排序 [(1, 7), (2, 9), (3, 3), (5, 1), (5, 12), (5, 4), (6, 10), (7, 11), (8, 8), (11, 2), (56, 5), (65, 6)]
基数分配排序 [(1, 7), (2, 9), (3, 3), (5, 1), (5, 4), (5, 12), (6, 10), (7, 11), (8, 8), (11, 2), (56, 5), (65, 6)]
归并稳定排序 [(1, 7), (2, 9), (3, 3), (5, 1), (5, 4), (5, 12), (6, 10), (7, 11), (8, 8), (11, 2), (56, 5), (65, 6)]
从排序后(5,1), (5,4),(5,12)的位置看,希尔插入排序、堆选择排序和快速交换排序不稳定。