Row / Column Major
首先要瞭解:C 是 Row Maojr 的語言。
代碼:
int A[2][3] = { {1, 2, 3}, {4, 5, 6} };
意思是:有2個一維整數陣列,它們各有3個整數。因此,在 RAM 的某處,會有
代碼:
1 2 3  4 5 6
Column Major 的話則會是(如:ForTran、MatLab 和 OpenGL,Assign的方式當然也不一樣。)
代碼:
1 4  2 5  3 6
意思是:有3個一維整數陣列,它們各有2個整數。
所以,在C,上例 A[0][3] 就是 A[1][0],A[0][4] 就是 A[1][1],A[0][5] 就是 A[1][2],
而 A[0][6] 就是 A[1][3] 就是 A[2][0] 就超界 = 不合法!

只要算對了,Column / Row 用反了有差嗎?
要知道多數電腦存取下一〝個〞記憶體比下 N 〝個〞記憶體快!
所以,存取完A[0][1],要存取A[0][2] 通常比存取 A[1][1]快!
因此,常連續處理的資料,要放在最後一維裡!
這在大陣列 或 O(n<sup>p</sup>)演算法裡,速度差很多!(p 越大差越多)
若是O(x<sup>n</sup>) ,那放錯順序就完蛋了:慢到暈倒!

什麼叫〝個〞呢? Byte, Word, Double Word 或 Para 都行!只要是 CPU 且 BUS 支援的定址法。
且?是的!生意手法曾出不窮!
像 8088, 80386(386希望沒記錯) 等就是〝掛羊頭賣狗肉〞的 CPU:內位元數與外位元數不同!<hr>恭禧大家,可以進入主題了。Very Happy

二維陣列的種類(一):定義

C 的二維陣列有三種:int a[4][3], *b[4], **c; 雖然常常可以混用,但它們是不一樣的!
(註:4, 3 是方便下面說明用的。)

為了 a,compiler配置了 一個位置給 a,和 4*3=12 個sizeof(int)位置給整個 a[4][3]。
 在存取a[2][1]時,是用 (a+2*3+1) 得到位置,去存取值。
 因為,每個 a[i] 都是 3 個元素。

*b[4] 則不同。compiler 配置了一個位置給 b,還有 4 個指位置空間給整個 *b[4]。
 注意,雖然b[3][1]是合法的語法,但compiler 並沒有配置空間給 b[3][1]!
  所以,要先 b[3] = malloc(n);,才能讀寫 b[3][1]!(n > 1)(註:malloc 在 C++ 建議用 new)
 在算b[2][1]時,是由 b[2]找到 b[2][0] 的位置,再加 1單位 找到 b[2][1]!
 因為每個 b[0]、b[1]、b[2]、b[3]可以配置不同大小的東東,如:
代碼:
for (i=0; i<4; i++)
  b[i] = malloc(sizeof(*b) * (i * i + 1));

/* C 和 C++ 在這裡不同!
  C 會自動轉換型別 (coercion, implicit type conversion) ,
  C++一定要手動轉型 (cast, explicit type conversion)!
  所以,C++ 要在 = 右邊放上 (int) ,C不用。*/
 所以沒辦法用 a 的算法得知 b[2][1] 的位置在哪!

那,**c 呢?它等同於前述的 compiler 配給 ab 本身的東東。That's all!
 沒有任何其它空間配給 c[_] 或 c[_][_]!
(和 b 一樣,配置足夠空間後,給每個c[_]初值:對應到可用的空間,就可以用了。
 沒做上述處理前,c[2][1] 在 compile 時是合法的!但執行時(runtime)會出問題!)

[] 和 * 至少還有一個差別,請參 http://tw.knowledge.yahoo.com/question/?qid=1607082407793 的最佳解答與意見

二維陣列的種類(二):差別
由上可知,雖然a, b, c 都是二級指位器,但至少有五大不同:
 1. 配置法: initial 時的配置(前述)
 2. 找法:執行時,找 x[_][_]的方法(前述)
 3. 配置區:函數內宣告的變數(不管是不是陣列、幾維),用的 RAM 是 Stack。
   其它方式的變數(全域(global)、用static 修飾、或是用動態配置(malloc()系 或 new))用的 RAM 是 Heap。
 4. 最大 大小:
   Stack 通常都很小:幾 K(Apple][ 是 0.25K ) 到幾 M(XP 好像是 4M);
   Heap 就是接近整個 RAM,有的還會含 虛擬記憶體 (VM)。
 5. 速度:有些電腦,Stack 會比 Heap 快一點!
   (當然也要 compiler 有用那功能才會看到差別。)
   (感謝 iseeyou 在討論中提供了一個例子!Very Happy
   這個差別就算有,也不大。
   不過,Stack 幾乎不會用到 VM,Heap 就很有可能!
   一旦用到 VM,所有的電腦都一樣,Heap 的速度就……Crying or Very sad
malloc 的上限 http://tw.knowledge.yahoo.com/question/question?qid=1406072517903

大二維動態配置應注意事項
強列不建議用上面二維陣列的種類(一)裡示範碼的寫法,去做大的二維動態配置!
速度是大陣列的重點!二維動態配置常用在大陣列上!
配置法錯誤,速度有明顯的差異!
上面的寫法至少有五個問題:
 1. 初值化時的速度:所有有在研究/大量使用malloc 的都知道:malloc 有個致命傷:很慢!!!
   不管在 DOS / Windows / Linux / Unix 都一樣!
 2. 使用時的速度:每個第二維的陣列都存在不同的位置,
   a. 陣列本身失去 locality 的加速性!
   b. 不可用跨維計算位址!
 3. 比較耗 RAM:每次 malloc/new,OS會用掉另一小塊 RAM來記得這塊 RAM 分配出去了!
   這個小塊 RAM 是一般程式裡看不到的!
   超大陣列就在怕 RAM 不夠用了,還讓 OS 吃掉寶貴的 RAM!Confused
   嫌 RAM 太快,想用 VM 來降速?Rolling Eyes
 4. 用完要 free 時,free 到昏倒!而且,free 也不快!
 5. 當 parallel 時,send/receive 明顯變慢!

所以,我建議
new/malloc 二次就好!因此,也只要 delete/free 二次就好!
一次是[ROW*COLUMN],一次是 *[ROW],再用個迴圈把*[ROW]依序指到[ROW*COLUMN]裡去!


如果要速度、陣列 Size 小於(約)2M,可以用
  int P[大數]

  int P[中數][中數]
去做,速度會比 動態 的做法快!

改天我有空再補這部份

陣列 是 const pointer
http://tw.knowledge.yahoo.com/question/question?qid=1008010406774
arrow
arrow
    全站熱搜
    創作者介紹
    創作者 dascan 的頭像
    dascan

    阿達の設計手札

    dascan 發表在 痞客邦 留言(0) 人氣()