赞
踩
若待排序的序列中,存在多个具有相同关键字的记录,经过排序, 这些记录的相对次序保持不变,则称该算法是稳定的;若经排序后,记录的相对 次序发生了改变,则称该算法是不稳定的。
算法稳定的好处:
插入排序基本思想是:每次将一个待排序的记录,按其关键字大小插入到前面已经排好序的文件中的适当位置,直到全部记录插入完成为止。
假设待排序的记录存放在数组arr中,排序过程的某一中间时刻,arr被划分成两个子区间[R[1],R[i-1]]
和[R[i],R[n-1]]
,其中前一个子区间是已排好序的有序区,后一个子区间则是当前未排好序的部分,即无序区。直接插入排序的基本操作就是将当前无序区的第1个记录插入到有序区中适当位置,保证有序区有序。
特点:
def insertionSort(arr):
n=len(arr)
for i in range(1,n):# 依次将arr[i]插入有序区
key=arr[i]
while arr[i-1]>key:# 边比较边交换
arr[i]=arr[i-1]
i-=1
if i==0:
break
arr[i]=key
取定一个小于
n
n
n的整数
d
1
d_1
d1作为第一个增量,把文件的全部记录分成
d
1
d_1
d1个组(所有距离为
d
1
d_1
d1倍数的记录放在同一个组),各组内进行直接插入排序;取第二个增量
d
2
<
d
1
d_2<d_1
d2<d1,重复上述分组和排序,直至所取增量为1。
特点:
def shellSort(arr):
n=len(arr)
gap=int(n/2)
while gap>0:
for i in range(gap,n):
key=arr[i]
j=i
while j>=gap and arr[j-gap]>key:
arr[j]=arr[j-gap]
j-=gap
arr[j]=key
gap//=2
两两比较待排序记录的关键字,发现两个记录的次序相反时即进行交换,直至没有反序的记录为止。
特点:
def bubbleSort(arr):
n=len(arr)
for j in range(n,1,-1):
# 前j个元素,将最大的放在最后
for i in range(j-1):
if arr[i]>arr[i+1]:
arr[i],arr[i+1]=arr[i+1],arr[i]
快速排序是一种分治的算法,快排算法每次选择一个元素并且将整个数组以那个元素分为两部分,根据实现算法的不同,元素的选择一般有如下几种:
整个快速排序的核心是分区(partition),分区的目的是传入一个数组和选定的一个元素,把所有小于那个元素的其他元素放在左边,大于的放在右边。
特点:
'''low起始索引,high结束索引 永远选最后一个元素为基准 partition返回分区后基准所在位置''' def partition(arr,low,high): i=low-1# 当前比基准值小的元素的最大下标 pivot=arr[high] # 遍历除了基准元素外的所有值 for j in range(low,high): if arr[j]<=pivot: i+=1 arr[i],arr[j]=arr[j],arr[i] arr[i+1],arr[high]=arr[high],arr[i+1] return i+1 def quickSort(arr,low,high): if low<high: pi=partition(arr,low,high) quickSort(arr,low,pi-1) quickSort(arr,pi+1,high) arr = [10, 7, 8, 9, 1, 5] n = len(arr) quickSort(arr,0,n-1)
每一趟从待排序的记录中选出关键字最大或最小的记录,顺序放在已排好序的子文件的最后,直至全部记录排序完毕。
假设待排序的记录存放在数组arr中,排序过程的某一中间时刻,arr被划分成两个子区间[R[1],R[i-1]]
和[R[i],R[n-1]]
,其中后一个子区间是已排好序的有序区,前一个子区间则是当前未排好序的部分,即无序区。直接选择排序就是将当前无序区的最大元素加入有序区。
特点:
# arr前n个元素中最大的元素位置
def findMaxPos(arr,n):
pos=0
maxnum=arr[0]
for i in range(1,n):
if arr[i]>maxnum:
maxnum=arr[i]
pos=i
return pos
def selectionSort(arr):
n=len(arr)
for i in range(n,1,-1):
pos=findMaxPos(arr,i)
arr[i-1],arr[pos]=arr[pos],arr[i-1]
堆是一个近似完全二叉树的结构,且满足子结点的键值或索引总是小于(或者大于)它的父节点。堆排序是一树形选择排序,在排序过程中,将arr看做是一棵完全二叉树顺序存储结构,利用完全二叉树中双亲结点和孩子结点之间的内在关系来选择关键字最小的记录。
建堆(大根堆):
只有一个结点的树显然是堆。在完全二叉树中,所有序号 i > ⌊ n / 2 ⌋ i>\lfloor n/2\rfloor i>⌊n/2⌋的结点都是叶子,因此以这些结点为根的树均已是堆。这样,我们只需依次将序号为 ⌊ n / 2 ⌋ , ⌊ n / 2 ⌋ − 1 , . . . , 1 \lfloor n/2\rfloor,\lfloor n/2\rfloor-1,...,1 ⌊n/2⌋,⌊n/2⌋−1,...,1的结点作为根的子树调整为堆即可。
已知结点 R [ i ] R[i] R[i] 的左右子树已是堆,将以 R [ i ] R[i] R[i] 为根的完全二叉树调整为堆(筛选法): 在 R [ i ] R[i] R[i]和它的左右孩子中选取关键字最大的结点放到 R [ i ] R[i] R[i] 的位置上:
堆排序:
利用大根堆排序,每一趟排序的基本操作是:将当前无序区调整为一个大根堆,选取关键字最大的堆顶记录,将它和无序区中最后一个记录交换
特点:
# 对编号为i的结点做heapify(大根堆)操作,只考虑tree的前n个结点 def heapify(tree,n,i): #递归出口:叶子结点不需要heapify if i>n:return #比较i和其子结点,返回值最大的结点下标 c1,c2=2*i+1,2*i+2 maxp=i if c1<n and tree[c1]>tree[maxp]: maxp=c1 if c2<n and tree[c2]>tree[maxp]: maxp=c2 # 如果值最大的不是i结点,则交换,并heapify调整子树 if maxp!=i: tree[maxp],tree[i]=tree[i],tree[maxp] heapify(tree,n,maxp) # 建堆 # 从最后一个非叶子结点(最后一个结点的父结点)开始递减做heapify def build_heap(tree): n=len(tree) last_node=n-1 parent=last_node//2 for i in range(parent,-1,-1): heapify(tree,n,i) # 堆排序 def heap_sort(tree): n=len(tree) build_heap(tree) for i in range(n-1,-1,-1): tree[0],tree[i]=tree[i],tree[0] # 重建堆,不考虑已经排好序的结点,由于此时根结点左右子树已是堆,只需heapify操作 heapify(tree,i,0)
heapq.heapify(x)
heapq.heappush(heap, item)
heapq.heappop(heap)
heapq.heappushpop(heap, item)
heapq.heapreplace(heap, item)
heapq.merge(*iterables, key=None, reverse=False)
heapq.nlargest(n, iterable, key=None)
heapq.nsmallest(n, iterable, key=None)
后两个函数在 n 值较小时性能最好。 对于更大的值,使用 sorted() 函数会更有效率。 此外,当 n==1 时,使用内置的 min() 和 max() 函数会更有效率。 如果需要重复使用这些函数,请考虑将可迭代对象转为真正的堆。
堆排序 可以通过将所有值推入堆中然后每次弹出一个最小值项来实现。
def heapsort(iterable):
h = []
for value in iterable:
heappush(h, value)
return [heappop(h) for i in range(len(h))]
堆元素可以为元组。 这适用于将比较值(例如任务优先级)与跟踪的主记录进行赋值的场合:
>>> h = []
>>> heappush(h, (5, 'write code'))
>>> heappush(h, (7, 'release product'))
>>> heappush(h, (1, 'write spec'))
>>> heappush(h, (3, 'create tests'))
>>> heappop(h)
(1, 'write spec')
“归并”是指将若干个已排序的子文件合并成一个有序文件。
二路归并排序思想:将待排序文件 R [ 0 ] R[0] R[0] 到 R [ n − 1 ] R[n-1] R[n−1] 看成 n 个长度为1的有序子文件,把这些子文件两两归并,得到 ⌈ n / 2 ⌉ \lceil n/2\rceil ⌈n/2⌉个有序的子文件;然后再把这 ⌈ n / 2 ⌉ \lceil n/2\rceil ⌈n/2⌉个有序的子文件两两归并,如此反复,直到最后得到一个长度为 n 的有序文件为止。
# arr[L,M-1]、arr[M,R]是两个已排好序(升序)的区间段,归并 def merge(arr,L,M,R): left_size=M-L right_size=R-M+1 left=arr[L:M] right=arr[M:] # i指向left,j指向right,k指向当前合并的arr位置 i,j,k=0,0,L while i<left_size and j<right_size: if left[i]<right[j]: arr[k]=left[i] i+=1 k+=1 else: arr[k]=right[j] j+=1 k+=1 while i<left_size: arr[k]=left[i] k+=1 i+=1 while j<right_size: arr[k]=right[j] k+=1 j+=1 # 归并排序 def mergeSort(arr,L,R): if L<R: M=(L+R)//2 mergeSort(arr,L,M) mergeSort(arr,M+1,R) merge(arr,L,M+1,R) arr=[6,8,9,10,4,5,2,7] L,R=0,7 mergeSort(arr,L,R)
桶排序的原理是将数组分到有限数量的桶中,再对每个桶子再分别排序(有可能再使用别的排序算法或是以递归方式继续使用桶排序进行排序),最后将各个桶中的数据有序的合并起来。
基数排序是一种非比较型整数排序算法,其原理是将整数按位数切割成不同的数字,然后按每个位数分别比较。排序过程是将所有待比较数值统一为同样的数位长度,数位较短的数前面补零,然后从最低位开始,依次进行一次排序。这样从最低位排序一直到最高位排序完成以后, 数列就变成一个有序序列。
数据结构——用C语言描述(唐策善等)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。