C++作为经典古老而先进的语言被大规模科学计算所青睐,是大规模科学计算的编程语言主要选项之一。在C++中,由于栈内存的限制,较大规模的动态数组通常用指针通过new分配。一个常见的2000x2000的二维数组分配代码如下:
const int n = 2000;
double** a = new double* [n];
for (int i=0;i<n;++i)
{
a[i] = new double[n]();
}
通过上述代码,即分配了一个2000x2000的数组。
下面采用上述方法计算矩阵算法,具体代码如下:
int main(int argc, char** argv)
{
const int n = 2000;
double** a = new double* [n]; double** b = new double* [n]; double** c = new double* [n];
for (int i=0;i<n;++i)
{
a[i] = new double[n]();
b[i] = new double[n]();
c[i] = new double[n]();
}
for (int i=0;i<n;++i)
{
for (int j=0;j<n;++j)
{
a[i][j] = 1.0; b[i][j] = 2.0;
}
}
clock_t t1 = clock();
for (int i=0;i<n;++i)
{
for (int j=0;j<n;++j)
{
c[i][j] = 0.0;
for (int k=0;k<n;++k)
{
c[i][j] += a[i][k] * b[k][j];
}
}
}
clock_t t2 = clock();
std::cout << "c " << c[n - 1][n - 1] << std::endl;
std::cout << "time " << (t2 - t1) / CLOCKS_PER_SEC << std::endl;
return 0;
}
上述代码计算结果如下:
需要的时间为39s。
下面考虑对该程序进行优化。
从分配内存的角度,在对数组进行逐行分配时,采用的代码是:
for (int i=0;i<n;++i)
{
a[i] = new double[n]();
}
该代码实际上是对a的每一行逐行分配,每循环一次分配一次。这样做在效率上产生了一个不利的条件:上一行与下一行的地址是不连续的。由于不连续的地址导致在运算时寻址效率低。
实际上,一个可选的优化是在对第一行的首地址申请空间时就把整个二维数组的空间均申请,再将其余各行“依次对应”到首地址之后的地址。这样申请之后,整个数组的地址连续。
修改后的代码如下:
int main(int argc, char** argv)
{
const int n = 2000;
//分配方式修改
double** a = new double* [n]; double** b = new double* [n]; double** c = new double* [n];
a[0] = new double[n * n]; b[0] = new double[n * n]; c[0] = new double[n * n];
for (int i=1;i<n;++i)
{
a[i] = a[0]+i*n;
b[i] = b[0]+i*n;
c[i] = c[0]+i*n;
}
for (int i=0;i<n;++i)
{
for (int j=0;j<n;++j)
{
a[i][j] = 1.0; b[i][j] = 2.0;
}
}
clock_t t1 = clock();
for (int i=0;i<n;++i)
{
for (int j=0;j<n;++j)
{
c[i][j] = 0.0;
for (int k=0;k<n;++k)
{
c[i][j] += a[i][k] * b[k][j];
}
}
}
clock_t t2 = clock();
std::cout << "c " << c[n - 1][n - 1] << std::endl;
std::cout << "time " << (t2 - t1) / CLOCKS_PER_SEC << std::endl;
return 0;
}
计算结果:
计算时间从39s变为11s,效率大幅提高。
以上,就是二维动态数组分配初步优化的全部内容,感谢您的阅读!