一、插入排序(insertion sort)
1. 算法
每一步都将一条记录插入到已排序的有序表中,得到一个新的有序表,不断重复,直到全部插入排序完成。
void InsertionSort( ElenmentType A[], int N) { int j, p; ElementType Tmp; for (P = 1; P<N; P++) { Tmp = A[P]; for ( j = P; j>0&&A[j-1]>Tmp; j--) { A[j] = A[j-1]; } A[j] = Tmp; } }
1 def StraightInsertSort(array): 2 n = len(array) 3 for i in range(1, n): 4 tmp = array[i] 5 j = i 6 while j > 0 and array[j-1] > tmp: 7 array[j] = array[j-1] 8 j -= 1 9 array[j] = tmp
2.复杂度
最大时间复杂度:2+3+4+……+N = O(N2)
最小时间复杂度( 逆序数为O(N) ):O(N)
平均:O(N2)
空间复杂度:O(1); 稳定性:稳定
3.定理1:N个互异数组的平均逆序数是N(N-1)/4
定理2:通过交换相邻元素进行排序的任何算法平均需要Ω(N2)时间
二、希尔排序(Shellsort)(缩小增量排序Diminishing Increment Sort)
1.算法:基于插入排序改进
用选定步长将待记录分割为若干子序列分别进行直接插入排序,然后缩小步长,重复前面的步骤,知道全部排序完成。
void Shellsort( ElementType A[], int N ) { int i, j, Increment; ElementType Tmp; for (Increment = N/2; Increment > 0; Increment /= 2) for (i = Increment; i < N; i++) { Tmp = A[i]; for (j = i; j>=Increment; j-=Increment) if (Tmp<A[j-Increment]) A[j] = A[j-Increment]; else break; A[j] = Tmp; } }
1 def ShellSort(array): 2 n = len(array) 3 increment = n//2 4 while increment > 0: 5 for i in range(increment, n): 6 #tmp = array [i] 7 j = i 8 while j >= increment: 9 if array[j] < array[j-increment]: 10 #array[j] = array[j-increment] 11 tmp = array[j] 12 array[j] = array[j-increment] 13 array[j-increment] = tmp 14 else: 15 break 16 j -= increment 17 #array[j] = tmp 18 increment = increment//2
2.复杂度
定理3:使用希尔增量排序的最坏情形运行时间为Θ(N2)
最好:O(N)
平均:O(NlogN)
空间复杂度:O(1); 稳定性:不稳定
三、堆排序(heapsort)
1.算法:先通过下滤(percolate down)算法把原数组改为大根堆,然后用deleteMax算法循环地将最大值放入数组最后的位置上,即得到升序排序结果。
1 #include <stdio.h> 2 #define LeftChild(i) (2*i + 1) 3 4 void PerDown(int a[], int i, int N) 5 { 6 int Child, Tmp; 7 for(Tmp = a[i]; LeftChild(i) < N; i = Child) 8 { 9 Child = LeftChild(i); 10 if(Child != N-1 && a[Child + 1] > a[Child]) 11 Child ++; 12 if(Tmp < a[Child]) 13 a[i] = a[Child]; 14 else 15 break; 16 } 17 a[i] = Tmp; 18 } 19 20 void Heapsort(int a[], int N) 21 { 22 int i, tmp; 23 for(i = N/2; i >= 0; i--) /* Build Max Heap */ 24 PerDown(a, i, N); 25 for(i = N-1; i > 0; i--) /* Delete Max */ 26 { 27 tmp = a[0]; 28 a[0] = a[i]; 29 a[i] = tmp; 30 PerDown(a, 0, i); 31 } 32 } 33 34 int main(int argc, char *argv[]) 35 { 36 int i; 37 int a[] = {73, 64, 81, 29, 53, 36, 47, 91, 78,66}; 38 Heapsort(a, 10); 39 for(i = 0; i < 10; i++) 40 printf("%d ", a[i]); 41 return 0; 42 }
1 def HeapSort(array): 2 n = len(array) 3 BuildHeap(array) 4 for i in range(n-1, 0, -1): 5 array[0], array[i] = array[i], array[0] 6 PercolateDown(array, 0, i) 7 8 def BuildHeap(array): 9 n = len(array) 10 i = n//2-1 11 #for i in range(n//2, -1, -1) 12 while i >= 0: 13 PercolateDown(array, i, n) 14 i -= 1 15 16 def PercolateDown(heap, i, n): # Max Heap 17 tmp = heap[i] 18 while i <= n//2-1: 19 Lchild = 2*i + 1 20 21 '''Rchild = Lchild + 1 22 if Lchild != n - 1 and heap[Lchild] < heap[Rchild]: 23 if tmp < heap[Rchild]: 24 heap[i] = heap[Rchild] 25 i = Rchild 26 else: 27 break 28 else: 29 if tmp < heap[Lchild]: 30 heap[i] = heap[Lchild] 31 i = Lchild 32 else: 33 break''' 34 35 if Lchild != n - 1 and heap[Lchild] < heap[Lchild+1]: 36 Lchild += 1 37 if tmp < heap[Lchild]: 38 heap[i] = heap[Lchild] 39 i = Lchild 40 else: 41 break 42 heap[i] = tmp
四、归并排序(mergesort)
1.算法:合并两个已排序的表;分治(divide-and-conquer);递归(recursion)
void MSort(ElementType A[], ElementType TmpArray[], int Left, int Right) { int Center; if(Left < Right) { Center = (Left + Right)/2; MSort(A, TmpArray, Left, Center); MSort(A, TmpArray, Center+1, Right); Merge(A, TmpArray, Left, Center+1, Right); } } void Mergesort(ElementType A[], int N) { ElementType *TmpArray; TmpArray = malloc(N*sizeof(ElementType)); if(TmpArray != NULL) { MSort(A, TmpArray, 0, N-1); free(TmpArray); } else FatalError("No space for tmp array!") } /* Lpos = start of left half, Rpos = start of right half */ void Merge(ElementType A[], ElementType TmpArray[], int Lpos, int Rpos, int RightEnd) { int i, LeftEnd, NumElements, Tempos; LeftEnd = Rpos - 1; TmpPos = Lpos; NumElements = RightEnd - Lpos + 1; /*main loop*/ while(Lpos <= LeftEnd && Rpos <= RightEnd) if(A[Lpos] <= A[Rpos]) TmpArray[TmpPos++] = A[Lpos++]; else TmpArray[TmpPos++] = A[Rpos++]; while(Lpos <= LeftEnd) TmpArray[TmpPos++] = A[Lpos++]; //Copy rest of first half while(Rpos <= RightEnd) TmpArray[TmpPos++] = A[Rpos++]; //Copy rest of second half /* Copy TmpArray back */ for (i = 0; i < NumElements; i++, RightEnd--) A[RightEnd] = TmpArray[RightEnd]; }
1 def MergeSort(lists): 2 if len(lists) <= 1: 3 return lists 4 num = len(lists)//2 5 left = MergeSort(lists[:num]) 6 right = MergeSort(lists[num:]) 7 return Merge(left, right) 8 9 def Merge(left, right): 10 l, r = 0, 0 11 result = [] 12 while l < len(left) and r < len(right): 13 if left[l] < right[r]: 14 result.append(left[l]) 15 l += 1 16 else: 17 result.append(right[r]) 18 r += 1 19 result += left[l:] 20 result += right[r:] 21 return result
2.复杂度
最坏情形运行时间:O(NlogN)
【注:虽然归并排序的运行时间较优,但是它很难用于主存排序,主要问题在于合并两个排序的表需要线性附加内存,在整个算法中还要花费将数据拷贝到临时数组在拷贝回来这样一些附加工作,其结果严重放慢了排序的速度】
五、快速排序(quicksort)
1.算法:分割,递归
通过一趟排序将待排序记录分割成独立的两部分,其中一部分的所有记录都比另一部分的所有记录小,然后再按此方法对这两部分记录分别排序,知道所有排序完成。
三数中值分割法:使用左端、右端和中心位置上的三个元素的中值作为枢纽元。
#define Cutoff 3 void Quicksort( ElementType A[], int N) { Qsort(A, 0, N-1); } /* Return median of Left, Center, and Right */ /* Order these and hide the pivot */ ElementType Median3( ElementType A[], int Left, int Right ) { int Center = (Left + Right)/2; if( A[Left] > A[Center] ) Swap(&A[left], &A[Center]); if( A[Left] > A[Right] ) Swap(&A[Left], &A[Right]); if( A[Center] > A[Right]) Swap(&A[Center], A[Right]); /* Invariant: A[Left] <= A[Center] <= A[Right] */ Swap( &A[Center], &A[Right-1] ); return A[Right-1]; } void Qsort( ElementType A[], int Left, int Right) { int i, j; ElementType Pivot; if (Left + Cutoff <= Right) { Pivot = Median3( A, Left, Right ); i = Left; j = Right-1; for(; ;) { while(A[++i] < Pivot){} while(A[--j] < Pivot){} if(i < j) Swap(&A[i], &A[j]); else break; } Swap(&A[i], &A[Right-1]); Qsort( A, Left, i-1); Qsort( A, i+1, Right); } else // Do an insertion sort on the subarray InsertionSort( A+Left, Right-Left+1 ); }
1 def QuickSort(array): 2 n = len(array) 3 QuickSortPartition(array, 0, n-1) 4 5 def QuickSortPartition(array, left, right): 6 Median(array, left, right) 7 if left + 2 < right: 8 pivot = array[right] 9 i = left 10 j = right 11 while i < j: 12 while array[i] <= pivot and i < j: 13 i += 1 14 while array[j] >= pivot and i < j: 15 j -= 1 16 array[i], array[j] = array[j], array[i] 17 18 array[right] = array[i] 19 array[i] = pivot 20 21 QuickSortPartition(array, left, i-1 ) 22 QuickSortPartition(array, i+1, right ) 23 24 def Median(array, left, right): 25 center = (left+right) // 2 26 if array[left] > array[center]: 27 array[left], array[center] = array[center], array[left] 28 if array[left] > array[right]: 29 array[left], array[right] = array[right], array[left] 30 if array[center] > array[right]: 31 array[center], array[right] = array[right], array[center] 32 if left + 2 < right: 33 array[center], array[right] = array[right], array[center]
2.复杂度
实践中最快的一直排序算法,平均运行时间为:O(NlogN)
最坏情形性能为:O(N2)
最好:O(NlogN)
空间复杂度:O(NlogN);稳定性:不稳定
对于很小的数组(N<=20),快速排序不如插入排序好。
六、一般选择排序(SimpleSelectSort)
1.算法
从待排序记录中选出最小(大)的一条记录与第一个位置的记录交换,然后在剩下的记录中再找最小(大)的记录与第二个位置的记录交换,以此类推,直到全部完成。
1 def SimpleSelectSort(array): 2 n = len(array) 3 for i in range(n-1): 4 k = i 5 for j in range(i+1, n): 6 if array[j] < array[k]: 7 k = j 8 tmp = array[i] 9 array[i] = array[k] 10 array[k] = tmp
2.复杂度
最坏:O(N2);最好:O(N2);平均:O(N2)
空间复杂度:O(1); 稳定性:不稳定
七、冒泡排序(BubbleSort)
1.算法
在待排序记录中,自上而下的对相邻记录进行比较和调整,让较大的记录往下沉,较小的记录往上冒。
1 def BubbleSort(array): 2 n = len(array) 3 for j in range(n-1): 4 flag = False 5 for i in range(n-1-j): 6 if array[i] > array[i+1]: 7 #array[i], array[i+1] = array[i+1], array[i] 8 tmp = array[i] 9 array[i] = array[i+1] 10 array[i+1] = tmp 11 flag = True 12 if flag == False: 13 return
2.复杂度
最坏:O(N2);最好:O(N);平均:O(N2)
空间复杂度:O(1); 稳定性:稳定