/*
* =====================================================================================
*
* Filename: arrydiff.cpp
*
* Description: test
*
* Version: 1.0
* Created: 2012年09月11日 22时34分30秒
* Revision: none
* Compiler: gcc
*
* Author: (http://blog.csdn.net/njzhiyuan)
* Organization:
*
* =====================================================================================
*/
#include <iostream>
extern "C" {
#include <stdlib.h>
#include <math.h>
#include <time.h>
}
#include <string>
using namespace std;
/**
*sum_a 第一个数组的和
*a 第一个数组中一个元素
*sum_b 第二个数组的和
*b 第二个数组中一个元素
×函数返回假如交换a、b元素后,两数组元素之和的差,原始试子应为(sum_a - a + b) - (sum_b - b + a)
*/
template<typename T>
inline T get_swap_diff(const T &sum_a, const T &a,const T &sum_b, const T &b){
return abs(sum_a - sum_b - 2 * a + 2 * b);
}
//此处在std里已有,这里属重复定义,故注释
/*template<typename T>
void swap(T &a, T &b){
T temp = a;
a = b;
b = temp;
}*/
//求数组元素之和
template<typename T, size_t element_nums>
T array_sum(const T(&array)[element_nums]){
T sum = 0;
for(size_t i = 0; i < element_nums; ++i)
sum += *(array + i);
return sum;
}
/**
*实现两个数组间元素的交换,使两数组元素之和的差最小,思想如下:
*如果两数组元素之和的差已经最小,那么任意交换两数组的元素,都不能使差再减小,故这可以作为最外层循环的退出条件。
*依次选取第一个数组的元素a,再从第二个数组中选出一元素b,使得a、b交换能使得两数组元素之和的差减小得最多。
*交换a、b,重新计算两数组的两数组元素之和及它们的差。重复上述步骤,如果不能再使差减小了,就退出外层循环。
*/
template<typename T, size_t element_nums>
void min_diff(T(&arr_a)[element_nums], T(&arr_b)[element_nums]){
bool flag;
do{
flag = false;
T sum_a = array_sum(arr_a);
T sum_b = array_sum(arr_b);
if(sum_a == sum_b) break;
T diff = abs(sum_a - sum_b);
for(size_t index_a = 0; index_a < element_nums; ++index_a){
size_t temp_index;
bool chang_flag = false;
for(size_t index_b = 0; index_b < element_nums; ++index_b){
if(diff > get_swap_diff(sum_a, *(arr_a + index_a), sum_b, *(arr_b + index_b))){
diff = get_swap_diff(sum_a, *(arr_a + index_a), sum_b, *(arr_b + index_b));
temp_index = index_b;
chang_flag = true;
}
}
if(chang_flag){
swap(*(arr_a + index_a),*(arr_b + temp_index));
//已调用swap交换了元素,两数组的两数组元素之和时须注意。
sum_a = sum_a + *(arr_a + index_a) - *(arr_b + temp_index);
sum_b = sum_b + *(arr_b + temp_index) - *(arr_a + index_a);
flag = true;
}
}
}while(flag);
}
//显示数组元素
template<typename T, size_t element_nums>
void array_display(const T (&array)[element_nums]){
for(size_t i=0; i < element_nums; ++i)
cout << *(array + i) << '\t';
cout << endl;
}
//给数组元素赋随机值
template<typename T, size_t element_nums>
void create_value(T (&array)[element_nums],int seed = 100){
size_t i = 0;
srand((unsigned) time(NULL) + seed);
while(i < element_nums){
*(array + i++) = static_cast<T>(rand() % 1000);
}
}
// 下面的几个函数参数中,数组名作为是指针传递参数,实现的功能与以上同名函数相同
template<typename T>
T array_sum(const T *array, size_t element_nums){
T sum = 0;
for(size_t i = 0; i < element_nums; ++i)
sum += *(array + i);
return sum;
}
template<typename T>
void min_diff(T *arr_a,T *arr_b,size_t element_nums){
bool flag;
do{
flag = false;
T sum_a = array_sum(arr_a,element_nums);
T sum_b = array_sum(arr_b,element_nums);
if(sum_a == sum_b) break;
T diff = abs(sum_a - sum_b);
for(size_t index_a = 0; index_a < element_nums; ++index_a){
size_t temp_index;
bool chang_flag = false;
for(size_t index_b = 0; index_b < element_nums; ++index_b){
if(diff > get_swap_diff(sum_a, *(arr_a + index_a), sum_b, *(arr_b + index_b))){
diff = get_swap_diff(sum_a, *(arr_a + index_a), sum_b, *(arr_b + index_b));
temp_index = index_b;
chang_flag = true;
}
}
if(chang_flag){
swap(*(arr_a + index_a),*(arr_b + temp_index));
sum_a = sum_a + *(arr_a + index_a) - *(arr_b + temp_index);
sum_b = sum_b + *(arr_b + temp_index) - *(arr_a + index_a);
flag = true;
}
}
}while(flag);
}
template<typename T>
void array_display(const T *array,size_t element_nums){
for(size_t i=0; i < element_nums; ++i)
cout << *(array + i) << '\t';
cout << endl;
}
template<typename T >
void create_value(T *array,size_t element_nums,int seed = 100){
size_t i = 0;
srand((unsigned) time(NULL) + seed);
while(i < element_nums){
*(array + i++) = static_cast<T>(rand() % 1000);
}
}
//指针形式参数系列函数的测试
void pt_test(){
while(true){
size_t array_size;
string size_temp; //避免直接cin>>array_size,因为输入非数值字符时,会导致意想不到的错误
cout << "Please input the size of array: ";
cin>>size_temp;
if((array_size = atol(size_temp.c_str())) < 1)
array_size = 10;
long *array_a;
long *array_b;
if((array_a = new long[array_size]) == NULL){
cout << "Apply space for the first array failed!"<<endl;
break;
}
if((array_b = new long[array_size]) == NULL){
cout << "Apply space for the second array failed!"<<endl;
delete[] array_a;
break;
}
create_value(array_a,array_size);
create_value(array_b,array_size,rand());
cout << "before the change:\n";
array_display(array_a,array_size);
array_display(array_b,array_size);
cout << "array_a sum " << array_sum(array_a,array_size) << endl;
cout << "array_b sum " << array_sum(array_b,array_size) << endl;
min_diff(array_a,array_b,array_size);
cout << "after the change:\n";
array_display(array_a,array_size);
array_display(array_b,array_size);
cout << "array_a sum " << array_sum(array_a,array_size) << endl;
cout << "array_b sum " << array_sum(array_b,array_size) << endl;
delete[] array_a;
delete[] array_b;
cout << "Do you want to continue with this program? Y/N : ";
char response;
cin>>response;
if(response != 'Y' && response != 'y')
break;
}
}
//引用形式参数系列函数的测试
void ref_test(){
const size_t size =10;
int array_a[size];
int array_b[size];
create_value(array_a);
create_value(array_b,rand());
cout << "before the change:\n";
array_display(array_a);
array_display(array_b);
cout << "array_a sum " << array_sum(array_a) << endl;
cout << "array_b sum " << array_sum(array_b) << endl;
min_diff(array_a,array_b);
cout << "after the change:\n";
array_display(array_a);
array_display(array_b);
cout << "array_a sum " << array_sum(array_a) << endl;
cout << "array_b sum " << array_sum(array_b) << endl;
}
int main(int argc, char *argv[]){
ref_test();
pt_test();
return 0;
}