已知由 n(n≥2)个正整数构成的集合 A={ak|0≤k<n},将其划分为两个不相交的子集 A1和 A2,元素个数分 别是 n1和 n2,A1和 A2中元素之和分别为 S1和 S2。设计一个尽可能高效的划分算法,满足|n1-n2|最小且|S1-S2|最大。要求:
(1)给出算法的基本设计思想。
(2)根据设计思想,采用 C 或 C++语言描述算法,关键之处给出注释。
(3)说明你所设计算法的平均时间复杂度和空间复杂度。
int quick_part(int A[],int n)
{
int i=0,j=n-1,part=A[i],temp=0,i_0=i,j_0=j,sum=0;
while(1)
{
while(i<j)
{
while(A[j]>part)j--;
while(A[i]<part)i++;
temp=A[j];
A[j]=A[i];
A[i]=temp;
}
A[i]=part;
if(i==n/2)break;
if(i>n/2)
{
j=i-1;
i=i_0;
j_0=j;
i_0=i;
}
else
{
i=i+1;
j=j_0;
j_0=j;
i_0=i;
}
}
for(j=i;j<n;j++)
{
sum=sum+A[j];
}
for(j=0;j<i;j++)
{
sum=sum-A[j];
}
return sum;
} int setPartition(int a[], int n, int lo1, int hi1) {
int lo = lo1, hi = hi1;
int pivot_val = a[lo];
while (lo < hi) {
while (lo < hi && a[hi] >= pivot_val) --hi;
a[lo] = a[hi];
while (lo < hi && a[lo] <= pivot_val) ++lo;
a[hi] = a[lo];
}
a[lo] = pivot_val;
int m = (n - 1) >> 1;
if (lo == m) {
return lo;
} else if (lo < m) {
return setPartition(a, n, lo + 1, hi1);
} else return setPartition(a, n, lo1, lo - 1);
}
int gk(int *arr, int n) {
int p = setPartition(arr, n, 0, n - 1) + 1;
printf("p=%d\n", p - 1);
int s1 = 0, s2 = 0;
for (int i = 0; i < p; ++i) {
s1 += arr[i];
}
while (p < n) {
s2 += arr[p++];
}
return s2 - s1;
} 递归代码