目录
排序
排序分为:插入排序、交换排序、选择排序和归并排序
插入排序
将无序子序列中的一个或几个记录插入到有序序列中,从而增加记录的有序子序列的长度。
分为:
直接插入排序
折半插入排序
希尔插入排序
直接插入排序
每次将一个待排序的记录按其关键字大小插入到前面已经安排好的子序列中的适当位置,指导全部记录插入完成为止。
第一个为固定有序值,然后除第一个之后都是无序的,相当于一个一个往后移的比较,第一个和第二个先比较,然后再加入第三个比较,然后依次类推。
最后实例:
def insertionSort(arr):
for i in range(1, len(arr)):
key = arr[i]
j = i - 1
while j >= 0 and key < arr[j]:
arr[j + 1] = arr[j]
j -= 1
arr[j + 1] = key
arr = [59, 12, 77, 64, 72, 69, 46, 89, 31, 9]
print('before: ', arr)
insertionSort(arr)
print("after:")
for i in range(len(arr)):
print("%d " % arr[i], end='')
折半插入排序
对插入排序算法的一种改进
由于插入排序前半部分已排好序,因此可以引入折半查找方法来加快寻找插入位置的速度。
最后实例:
def binary_sort(a):
for i in range(0, len(a)):
index = a[i]
low = 0
hight = i - 1 #low和hight组成的相当于一个区间
while low <= hight:
mid = (low + hight) // 2 #找中间值,和折半查找一样
if index > a[mid]:
low = mid + 1
else:
hight = mid - 1
for j in range(i, low, -1):
a[j] = a[j - 1]
a[low] = index
li=[59,12,77,64,72,69,46,89,31,9]
print('before: ',li)
binary_sort(li)
print('after: ',li)
希尔排序
采用大跨度间隔比较方式让记录跳跃式接近它的排序位置
相当于是给一个步长,然后逐渐缩小步长来进行排序。
最后实例:
def shell_sort(alist):
n=len(alist)
gap=n//2
while gap>0:
for i in range(gap,n):
j=i
while j>=gap and alist[j-gap]>alist[j]:
alist[j-gap],alist[j]=alist[j],alist[j-gap]
j-=gap
gap =gap//2 #每次步长都是上一次步长的一半
li=[11,9,84,32,92,26,58,91,35,27,46,28,75,29,37,12]
print('before: ',li)
shell_sort(li)
print('after: ',li)
交换排序
无序序列中的记录的到其中关键字最小或最大的记录,并将其加入到有序子序列中,最终形成有序序列。
分为:
冒泡排序
快速排序
冒泡排序
比较两两待排序的记录,当这两个数次序相反(“逆序”或“反序”)时进行交换,直到没有反序为止。
比较相邻位置,如果前大于后,则交换,对数组从0到n-1进行遍历,然后可以发现最大的值移动到了第n-1个位置。依次类推,将最大的直接提取出来,然后剩下的再比较
最后实例:
def bubble_sort(alist):
for j in range(len(alist)-1,0,-1): #外循环 每次把最大的那个直接去掉排剩下的
for i in range(j): #内循环
if alist[i]>alist[i+1]:
alist[i],alist[i+1]=alist[i+1],alist[i]
li=[54,26,93,17,77,31,44,55,20]
print('before: ',li)
bubble_sort(li)
print('after: ',li)
快速排序
每一轮处理其实就是将这一轮的基准数定位,直到所有的数都排序完成为止。
1.选一个基准值(通常可选第一个元素);
2.比基准值小的数值移到基准值左边,形成左子序列;
3.比基准值大的数值移到基准值右边,形成右子序列;
4.分别对左、右子序列执行以上三步(递归),直到左右序列只剩下一个数值或没有数值
最后实例:
def quick_sort(alist ,start,end):
if start>=end:
return
mid =alist[start]
low=start
high =end
while low < high:
while low<high and alist[high]>=mid:
high -=1
alist[low]=alist[high]
while low<high and alist[low]<mid:
low +=1
alist[high]=alist[low]
alist[low]=mid
quick_sort(alist ,start,low-1)
quick_sort(alist ,low+1,end)
li=[48,36,61,99,81,14,30]
print('before:',li)
quick_sort(li,0,len(li)-1)
print('after:',li)
选择排序
从记录的无序子序列中选择关键字最小或最大记录,并将它加入到有序子序列中,获得有序序列
分为:
简单选择排序
堆排序
简单选择排序
相当于找序列中的最小值,然后放在第一位(和第一位交换位置),然后再剩下的序列中,再找最小值,然后刚在后面,以此类推。
最后实例:
def selection_sort(alist):
n=len(alist)
for i in range(0,n):
min = i #将当前下标定义为最小值下标
for j in range(i+1,n):
if alist[j]<alist[min]: #如果有小于当前最小值的关键字
min = j #将此关键字的下标赋值给min_index
if i != min: #i不是最小数时,将i 和最小数交换
alist[i],alist[min]=alist[min],alist[i]
li=[5,2,1,8,3,4,6,7]
print('before:',li)
selection_sort(li)
print('after:',li)
堆排序
特殊的完全二叉树。
堆分为最大堆和最小堆
最大堆中最大元素出现在根结点(堆顶),而且父节点的值大于等于孩子结点。最大值
最小堆中最小元素出现在根结点(堆顶),而父节点的值小于等于孩子结点。最小值
基本流程
步骤1:构建最大堆:刚开始把序列看作是一颗顺序存储的全二叉树,在起始数组为0的情况下,节点i的左子节点再外置(2*i+1),右子节点为(2*i+2);子节点i的父节点在位置。调整它们的顺序,使之成为一个最大(小)堆。找到最后一个非终端节点,与它的左右子节点比较,将根结点与左、右孩子中较小(或大)的进行交换。
步骤2:输出堆顶元素,输出堆顶元素后,将堆底元素送入堆顶,堆被破坏,因为仅是根结点不满足堆的性质。将根结点与左、右孩子中较小(或大)的进行交换。若与左子女交换,则左子树堆被破坏,且仅左子树的根结点不满足堆的性质;若与右子女交换,则右子树堆被破坏,且仅右子树的根结点不满足堆的性质。以此类推直到叶子结点完成调整。
步骤3:反复执行步骤2,直到无序区只有一个元素为止。
最后实例:
代码一:
def buildMaxHeap(arr):
import math
for i in range(math.floor(len(arr)/2),-1,-1):
heapify(arr,i)
def heapify(arr, i):
left = 2*i+1
right = 2*i+2
largest = i
if left < arrLen and arr[left] > arr[largest]:
largest = left
if right < arrLen and arr[right] > arr[largest]:
largest = right
if largest != i:
swap(arr, i, largest)
heapify(arr, largest)
def swap(arr, i, j):
arr[i], arr[j] = arr[j], arr[i]
def heapSort(arr):
global arrLen
arrLen = len(arr)
buildMaxHeap(arr)
for i in range(len(arr)-1,0,-1):
swap(arr,0,i)
arrLen -=1
heapify(arr, 0)
return arr
L = [50, 16, 30, 10, 60, 90, 2, 80, 70]
print(heapSort(L))
代码二:
from collections import deque
def swap_param(L, i, j): #把堆顶元素和堆末尾的元素交换
L[i], L[j] = L[j], L[i]
return L
def heap_adjust(L, start, end): #heap_ adjust函数用于调整为大根堆
temp = L[start]
i = start
j = 2 i
while j <= end: #代表在调整完整棵树树之前一直进行循环
if (j < end) and (L[j] < L[j + 1]): #保证 j 取到较大子树的坐标
j += 1
if temp < L[j]:
#如果子树的根节点小于子树的值, 就把根节点和较大的子树的值进行交换
L[i] = L[j]
i = j
j = 2 i
else:
break
L[i] = temp
def heap_sort(L): #heap_sort函数用于构造大根堆
L_length = len(L)- 1 #引入一个辅助空间
first_sort_count = L_length // 2
for i in range(first_sort_count): #把序列调整为一个大根堆
heap_adjust(L, first_sort_count - i, L_length)
for i in range(L_length - 1):
L = swap_param(L, 1, L_length - i)
#把堆顶元素和堆末尾的元素交换(引入的一个辅助空间,序列长度减1)
heap_adjust(L, 1, L_length - i - 1) #把剩下的元素调整为一个大根堆
return [L[i] for i in range(1, len(L))]
def main():
L = deque([50, 16, 30, 10, 60, 90, 2, 80, 70])
L.appendleft(0)
print(heap_sort(L))
if name == '__main__':
main()
代码三:
import heapq
def heapsort(iterable):
h = []
for value in iterable:
heapq.heappush(h, value)
return [heapq.heappop(h) for i in range(len(h))]
if name == '__main__':
li=[50, 16, 30, 10, 60, 90, 2, 80, 70]
print("before: ",li)
h=heapsort(li)
print("after: ",h)
归并排序
将两个或两个以上的有序子序列“归并”为一个有序序列。即把待排序列分为若干个子序列,每个子序列是有序。然后再把有序子序列合并为整体有序序列。
归并排序核心在于先分解,再合并。
最后实例:
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.extend(left[i:])
result.extend(right[j:])
return result
def merge_sort(alist):
if len(alist)<=1:
return alist
mid = len(alist)//2
left =merge_sort(alist[:mid])
right =merge_sort(alist[mid:])
return merge(left,right)
def main():
li=[9,4,6,2,1,7]
print("befroe: ",li)
print("after: ",merge_sort(li))
if name=='__main__':
main()