排序问题及算法
冒泡排序(Bubble-Sort)
-
排序问题描述:
输入:n个数的一个序列 $ {a_1,a_2,\ldots,a_n} $。
输出:输入序列的一个排列 { a 1 ′ , a 2 ′ , … , a n ′ } \{a_1',a_2',\ldots,a_n'\} {a1′,a2′,…,an′},满足 $ a_1’\leq a_2’\leq\ldots\leq a_n’$。
-
冒泡排序是一种流行但低效的排序算法,它的作用是反复交换相邻的未按次序排列的元素。
-
代码:时间复杂度 O ( n 2 ) O\big(n^2\big) O(n2)
void BubbleSort(int* A){ int temp; for(int i=0; i<sizeof(A)/sizeof(int) ; ++i)){ for(int j=0; j<sizeof(A)/sizeof(int) ; ++j)){ if(A[j]<A[j-1]){ temp=A[j]; A[j]=A[j-1]; A[j-1]=temp; } } } return; }
插入排序(Insertion-Sort)
-
排序问题描述:
输入:n个数的一个序列 $ {a_1,a_2,\ldots,a_n} $。
输出:输入序列的一个排列 { a 1 ′ , a 2 ′ , … , a n ′ } \{a_1',a_2',\ldots,a_n'\} {a1′,a2′,…,an′},满足 $ a_1’\leq a_2’\leq\ldots\leq a_n’$。
-
流程:从第二个数向后面遍历,每次遍历将此数作为 k e y key key并与前面的数进行比对,若前面的数大于 k e y key key,则交换两数,直到数 k e y key key到达合适的位置。
-
代码:时间复杂度 O ( n 2 ) O\big(n^2\big) O(n2)
void InsertSort(int* arr){ int key,i; for(int j=2; j<sizeof(arr)/sizeof(int) ; ++j){ key=arr[j]; // Insert arr[j] into the sorted sequence arr[1...j-1]. i=j-1; while(i>0 && arr[i]>key){ arr[i+1]=arr[i]; --i; } arr[i+1]=key; } }
-
应用:
-
重写 I n s e r t S o r t ( ) InsertSort() InsertSort()函数,使之按降序排序:
void InsertSort_Desc(int* arr){ for(int j=2; j<sizeof(arr)/sizeof(int) ; ++j){ int key,i; key=arr[j]; i=j-1; while(i>0 && arr[i]<key){//Only change '<' arr[i+1]=arr[i]; --i; } arr[i+1]=key; } }
-
考虑两个 n n n位二进制整数相加:
输入:两整数分别存在两个 n n n元数组 A A A和 B B B中;
输出:将相加后的和按二进制存储在一个 ( n + 1 ) (n+1) (n+1)元数组 C C C中。
写出代码:
int* BinaryAdd(int* A, int* B){ if(sizeof(A)!=sizeof(B)){ std::cout << "Error!" << std::endl; return nullptr; } int n=sizeof(A)/sizeof(int); int* C=new int[n+1]; int carry=0; for(int i=0; i<n ;++i){ C[i]=(A[i]+B[i]+carry)%2; carry=(A&&B)||((A||B)&&C); } C[n]=carry; return C; }
归并排序(Merge-Sort)
-
归并排序算法完全遵循分治模式。直观上其操作如下:
分解:分解待排序的 n n n个元素的序列成各具 n / 2 n/2 n/2个元素的两个子序列。
解决:使用归并排序递归地排序两个子序列。
合并:合并两个已排序的子序列以产生已排序的答案。
当待排序列长度为1时,递归“开始回升”,这时不进行任何操作,因为长度为1已经排好序。
-
M e r g e S o r t ( A , p , q , r ) MergeSort(A,p,q,r) MergeSort(A,p,q,r)函数参数如下:
A A A是一个数组, p 、 q 、 r p、q、r p、q、r是数组下标,满足 p ≤ q < r p\leq q<r p≤q<r。
该过程假设子数组 A [ p . . q ] A\left[p..q\right] A[p..q]和 A [ q + 1.. r ] A\left[q+1..r\right] A[q+1..r]都已经排好序,函数只需将两子数组依次遍历,按从小到大的顺序比对,再更新原本的数组即可。
-
代码:时间复杂度 O ( n l o g ( n ) ) O\big(nlog(n)\big) O(nlog(n))
#include <iostream> using namespace std; void Merge(int* A, int p, int q, int r) { int n1 = q - p + 1; int n2 = r - q; int* L = new int[n1 + 1]; int* R = new int[n2 + 1]; for (int i = 0; i < n1; ++i) { L[i] = A[p + i]; } for (int j = 0; j < n2; ++j) { R[j] = A[q + j + 1]; } L[n1] = INT_MAX; R[n2] = INT_MAX; int i = 0, j = 0; for (int k = p; k <= r; ++k) {//two subint ASC if (L[i] <= R[j]) { A[k] = L[i]; i++; } else { A[k] = R[j]; j++; } } return; } void MergeSort(int* A, int p, int r) { if (p < r) { int q = (p + r) / 2; MergeSort(A, p, q); MergeSort(A, q + 1, r); Merge(A, p, q, r); } return; } int main() { int A[8] = { 2,4,5,7,1,2,3,6 }; MergeSort(A, 0, sizeof(A)/sizeof(int) -1); for (int i = 0; i < sizeof(A)/sizeof(int); ++i) { cout << A[i] << endl; } return 0; }