金块问题:
老板有一袋金块(共n块,n是2的幂(n>=2)),最优秀的雇员得到其中最重的一块,最差的雇员得到其中最轻的一块。假设有一架比较重量的机器,希望用自己最少的比较次数找出最重和最轻的金块,并对自己的程序做复杂性分析。
问题分析:
采用分治法的思想来划分金块,有n块金块,n=2,一次比较就足够了;n>2,第一步,将这袋金块平分成两小袋A和B;第二步,分别找出A和B中最重和最轻的金块。设A中最重和最轻的金块分别是HA和LA,以此类推,B中最重和最轻的金块分别是HB和LB。第三步,通过比较HA和HB,可以找到所有金块中最重的;通过比较LA和LB,可以找到所有金块中最轻的。在第二步中,若n>2,则递归地应用分而治之的方法。
源代码:
#include<stdio.h>
#include<stdlib.h>
#define MAX 65536
void merge(int arr[], int p, int q, int r){
int *left, *right;
int n1, n2, i, j, k;
n1 = q - p + 1;
n2 = r - q;
if ((left = (int*)malloc((n1 + 1)*sizeof(int))) == NULL){
perror("malloc error");
exit(1);
}
if ((right = (int*)malloc((n2 + 1)*sizeof(int))) == NULL){
perror("malloc error");
exit(1);
}
for (i = 0; i<n1; i++){
left[i] = arr[p + i];
}
left[i] = MAX;//封口
for (i = 0; i<n2; i++){
right[i] = arr[(q + 1) + i];//q+1是右数组的起始位置,而不是q,注意!
}
right[i] = MAX;//封口
i = 0, j = 0;
for (k = p; k <= r; k++){
if (left[i]>right[j]){
arr[k] = right[j];
j++;
}
else{
arr[k] = left[i];
i++;
}
}
}
void mergeSort(int arr[], int begin, int end){
int mid;
if (begin<end){
mid = (begin + end) / 2;
mergeSort(arr, begin, mid);
mergeSort(arr, mid + 1, end);
merge(arr, begin, mid, end);
}
}
int main(){
int a[16] = { 4,10,2,3,6,7,6,4,5,10,11,14,20,34,23,90 };
mergeSort(a, 0, 15);
printf("min:%d\n", a[0]);
printf("max:%d\n", a[15]);
return 0;
}
运行结果:
复杂度分析:时间复杂度(log(n)的平方) 空间复杂度(n)