动态数组(一维驾驭高维数组)
好的 coder 總是有辦法以 1D array 來駕馭高維陣列操作,
但有時使用高維陣列,可讓 code 中的邏輯概念更加清晰。
早期的 C 或目前的 C++ 中,無動態陣列配置的語法,
(在 C99 中才有,例如 gcc 可編譯動態陣列)
因此需要自己實現,底下是我的簡單作法:
設計陣列配置時有 3 點需考量:
1. 配置效率: 最好只呼叫一次 malloc 或 new。
2. 存取效率: 存取速度必須逼近 primary array。
3. 語意: array 的記憶體必須連續分佈。
(所以 vector< vector > 不能算是真正的陣列,
只是個 array container... )
N維動態陣列配置較複雜,先從二維的寫起:
(1) 使用 C 語言:
void** new_arr (int size, int x, int y)//size = 元素大小
{
intsz = sizeof (void*);
void** a= (void **) malloc (sz*x + size*x*y);
if (!a) return 0;
char* p = (char*)a + sz * x;
while (x--) a[x] = p + size*x*y;
return a;
}void del_arr (void** a)
{
if (a) free (a);
}void set_arr (void** a, int size, int n...)
{
va_list p;
va_start (p, n);
memcpy (a[0], p, size*n);
}int main ()
{
typedef struct {float f;
char c;
} CC;
CC cc[4] = {0.2,'a', 0.4,'b', 0.6,'c', 0.8, 'd'};
intsz;
int**a;
char* **b;
CC**c;
a = (int**) new_arr (sz =
sizeof(int), 2,4);
set_arr ((void**)a, sz, 2*4,
1,2,3,4,//依序輸入資料
7,8,9,0
);
printf ("%d", a[1][2]);
b = (char***) new_arr (sz = sizeof(char*), 2,2);
set_arr ((void**)b, sz, 2*2,
"陣列","2D",//依序輸入資料
"輸入","範例"
);
printf ("/n%s", b[0][1]);
c = (CC**) new_arr (sz = sizeof(CC), 2,2);
set_arr ((void**)c, sz, 2*2,
cc[0], cc[1],//依序輸入資料
cc[2], cc[3]
);
printf ("/n%f %c", c[1][0].f, c[0][0].c);
del_arr ((void**)a);
del_arr ((void**)b);
del_arr ((void**)c);
}
(2) 使用 C++:
template struct Array
{
Array (int x, int y=1): y(y), x(x), p(new T[x*y]) {}
~Array () { for (x*=y;
x--;
p[x].~T());
delete[] p;
}
T* operator[] (int i) { return p+i*y;
}
Array& operator< (T o) { p[n=0] = o;
return*this;
}
Array& operator, (T o) { p[++n] = o;
return*this;
}
private:
int x, y, n;
T*p;
};
int main ()
{
struct CC {float f;
char c;
}
cc[4] = {0.2,'a', 0.4,'b', 0.6,'c', 0.8, 'd'};
Array a (2,4);
a < 1,2,3,4,//依序輸入資料
7,8,9,0;
cout << a[1][2];
Array b (2,2);
b < "陣列","模版",//依序輸入資料
"輸入","範例";
cout < c (2,2);
c < cc[0], cc[1],//依序輸入資料
cc[2], cc[3];
cout <
依照相同概念,繼續擴展到 N 維:
C 語言寫法: (此 code 由曾侃的程式修改而來)
#include void* new_arr (int size, int nDim, int n...)
{
static int d[32] = {0};
//限制最多到 32 維
int i,j, nPtr, nElem, sz = sizeof (void*);
//指位器與元素數目
void *a, **b, **c, **t;
char *p;
//a = 動態陣列起始位址va_list v;
va_start (v, nDim);
for (i=nDim-1;
i>=0;
i--)//讀取各個維數
d[i] = va_arg (v, int);
if (0 == nDim) return 0;
//禁止配置 0 維陣列
d[nDim-1] = n;
//糾正Release版別移掉nnPtr= d[1];
//計算指位器表大小
nElem = d[0]*d[1];
//與元素所佔之總空間
for (i=2;
i
C++ 寫法:
C++ 動態多維陣列目前最有效率的實作是... 暴力法....
也就是用 template 由 1 維一直特製化到 N 維,
此法速度等同 build-in array,亦是 boost::multi_array 的 4~5 倍..
底下另取它徑,實作一個動態陣列的變形,
改以 array (D1, D2, ...) 的形式來存取陣列元素:
template struct Array
{
Array (int d...)//傳入各維的維度
{
dim[1] = dim[N] = 1;
//確保()能正確存取
memcpy (dim, &d, N*sizeof(int));
//紀錄各維的維度
for (n=dim[N-1], i=N-2;
i>=0;
i--)
n *= dim[i], dim[i] = n;
//預先計算累加維度
if (0 == n) cout <<"arr size=0";
//配置錯誤
else p = new T[dim[0]];
//配置實體空間
}
T& operator()(int j...)
{
va_start (v,j);
for (n=j*dim[1], i=2;
i<=N;
++i)
n += dim[i] * va_arg (v,int);
//算出索引偏移量
return p[n];
}
~Array ()
{
for (i=dim[0];
i--;
p[i].~T());
//解構陣列內元素
delete[] p;
}
private:
int i,n, dim[N+1];
//dim[.] = 各維的維度
va_list v;
T* p;
//陣列實體
};
int main (/* daviddr 080705 */)
{
Array a(2,3,4,5);
for (int i=0;
i<2*3*4*5;
i++)
a(0,0,0,i) = i;
cout <
為了模擬陣列語法,只好再加些又長又醜陋的碼,
於是現在可以用 arr (D1,D2,..Dn) 與 arr [D1][D2]..[Dn]
兩種方法來存取陣列了~
template struct Array
{
Array (int d...)//傳入各維的維度
{
dim[1] = dim[N] = 1;
//確保()能正確存取
memcpy (dim, &d, N*sizeof(int));
//紀錄各維的維度
for (n=dim[N-1], i=N-2;
i>=0;
i--)
n *= dim[i], dim[i] = n;
//預先計算累加維度
if (0 == n) cout <<"arr size=0";
//配置錯誤
else p = new T[dim[0]];
//配置實體空間
}
T& operator()(int j...)
{
va_start (v,j);
for (n=j*dim[1], i=2;
i<=N;
++i)
n += dim[i] * va_arg (v,int);
//算出索引偏移量
return p[n];
}
~Array ()
{
for (i=dim[0];
i--;
p[i].~T());
//解構陣列內元素
delete[] p;
}
template struct Ptr//遞迴定義中繼物件
{
Ptr (T* t, int* d): p(t), d(d) {}
Ptr operator[] (int n) {
return Ptr (p + n*(*d), d+1);
}
operator T*() {return p;
}
private: T* p;
int* d;
//用來傳遞暫時參數
};
template struct Ptr//邊界定義
{
Ptr (T* t, int*): p(t) {}
T& operator[](int n) {return p[n];
}
operator T*() {return p;
}
private: T* p;
};
Ptr operator[] (int n)
{
return Ptr (p + n*dim[1], dim+2);
}
operator T*() {return p;
} private:
int i,n, dim[N+1];
//dim[.] = 各維的維度
va_list v;
T* p;
//陣列實體
};
template struct Array
{
Array (int d): d(d), p(new T[d]) {}
~Array () { while (d--) p[d].~T();
delete[] p;
}
T& operator[] (int n) {return p[n];
}
T& operator() (int n) {return p[n];
}
private: T* p;
int d;
} ;
int main (/* daviddr 080705 */)
{
int i;
Array a(2,3,4,5);
for (i=0;
i<2*3*4*5;
i++) a(0,0,0,i) = i;
cout < b(3);
for (i=0;
i<3;
i++) b(i) = java[i];
cout <
【动态数组(一维驾驭高维数组)】
推荐阅读
- 数组常用方法一
- Java|Java基础——数组
- 动态组件与v-once指令
- JS常见数组操作补充
- iview|iview upload 动态改变上传参数
- JS|JS 数组求和与数组求平均值
- 超帅的js数组去重
- JavaScript|JavaScript — 初识数组、数组字面量和方法、forEach、数组的遍历
- JavaScript判断数组的方法总结与推荐
- react-navigation|react-navigation 动态修改 tabBar 样式