T ( N ) = a ∗ T ( N / b ) + O ( N d ) T(N) = a * T(N / b) + O(N ^ d)\ T(N)=a∗T(N/b)+O(Nd)
T(N):母问题的规模
T(N/b):子问题的规模
a:调用次数
O(N^d):除去子问题,剩下操作的时间复杂度
-
logb a > d --> 复杂度为O(Nlogb a)
-
logb a = d --> 复杂度为O(Nd * log N)
-
logb a < d --> 复杂度为O(Nd)
#include3、小和问题 与 逆序对问题。int a[10] = {4,3,6,2,1,5,7,10,9,8}; void marge(int arr[], int l, int mid, int r){ int b[r - l + 1]; int i = 0; int p1 = l; int p2 = mid + 1; while(p1 <= mid && p2 <= r){ b[i++] = arr[p1] < arr[p2] ? arr[p1++] : arr[p2++]; } while(p1 <= mid){ b[i++] = arr[p1++]; } while(p2 <= r){ b[i++] = arr[p2++]; } for(int j = 0; j < i; j++){ arr[l + j] = b[j]; } } void process(int arr[], int l, int r){ if(l == r){ return; } int mid = l + r >> 1; process(arr, l, mid); process(arr, mid + 1, r); marge(arr, l, mid, r); } int main(){ process(a, 0, 9); for(int i = 0; i < 10; i++){ printf("%d ", a[i]); } return 0; }
小和问题因为要先放右侧的子数组,所以丧失了归并排序的稳定性。
#include4、荷兰国旗问题(时间复杂度O(N log N) 空间复杂度O(1))int a[5] = {1,2,3,4,5}; int marge(int arr[], int l, int mid, int r){ int b[r - l + 1]; int i = 0; int p1 = l; int p2 = mid + 1; int res = 0; while(p1 <= mid && p2 <= r){ //就加了这么一条语句 res += arr[p1] < arr[p2] ? (r - p2 + 1) * arr[p1] : 0; b[i++] = arr[p1] < arr[p2] ? arr[p1++] : arr[p2++]; } while(p1 <= mid){ b[i++] = arr[p1++]; } while(p2 <= r){ b[i++] = arr[p2++]; } for(int j = 0; j < i; j++){ arr[l + j] = b[j]; } return res; } int process(int arr[], int l, int r){ if(l == r){ return 0; } int mid = l + r >> 1; return process(arr, l, mid) + process(arr, mid + 1, r) + marge(arr, l, mid, r); } int main(){ int x = process(a, 0, 4); printf("%dn", x); for(int i = 0; i < 5; i++){ printf("%d ", a[i]); } return 0; }
给定一个数组arr,和一个数num,请把小于等于num的数放在数组的左边,等于num的数放在数组的中间, 大于num的数放在数组的右边。
思路:
- arr[i] < num,arr[i]和 小区下一个交换,小区范围右扩一位,i++
- arr[i] == num,i++
- arr[i] > num,arr[i] 和大区前一个交换,大区范围左扩一位,i原地不变
循环停止条件:当 i 包含在大区范围内
5、快速排序(最差O(log N2),平均O(N log N) 1、1.0版本先把最后一个数x提出来,剩余的数把小于x放左边,大于x放右边,递归
2、2.0版本先把最后一个数x提出来,剩余的数把小于x放左边,等于x的放中间,大于x放右边,递归
#include3、3.0版本int arr[5] = {4,2,1,3,5}; int lr[2]; void swap(int arr[], int l, int r){ int temp; temp = arr[l]; arr[l] = arr[r]; arr[r] = temp; } void parttion(int arr[], int l, int r){ //小于区的左边界 int p1 = l - 1; //大于区的右边界,最后一个数是划分值 int p2 = r; int p = l; while(p < p2){ if(arr[p] < arr[r]){ swap(arr, p++, ++p1); }else if(arr[p] > arr[r]){ swap(arr, p, --p2); }else{ p++; } } swap(arr, r, p2); lr[0] = p1; lr[1] = p2 + 1; } void process(int arr[], int l, int r){ if(l < r){ parttion(arr, l, r); process(arr, l, lr[0]); process(arr, lr[1],r); } } int main(){ process(arr, 0, 4); for(int i = 0; i < 5; i++){ printf("%d ", arr[i]); } return 0; }
随机选出一个数与最后一个数交换,用这个数来做,这样概率就相等了。



