Standard C Library - 思维火花 - 博客频道 - CSDN.NET
Standard C Library - 思維火花 - 博客頻道 - CSDN.NET
? DIY 了一套 ACQUIRE |
返回首頁
| 骨骼動畫的插值與融合 ?
動態數組的 C 實現
上次談到了一個常用的 ADT ,sequence 的 C 實現。通常,我們不會直接使用 sequence ,而是用它來實現滿足最終需要的數據結構。比如消息隊列,比如指令堆棧,等等。一個實現的優秀的 seq 的好處在于,即使你只用到其中一部分功能,也不會因為那些沒用的部分損失太多的(時間和空間上的)性能。
今天我想談另一個更為實用的 ADT ,動態數組。這個在傳世神作《C 語言接口與實現》中也提到過,我不是想說其寫的不對,或是講述的不周全,實現的不漂亮。只是以我的觀點來展開相關的問題。
為什么要有數組?C 語言內置了數組、在 C99 中更是允許在堆棧上聲明非固定長度的數組。C++ 里以 STL 的形式提供了 vector 模塊供程序員使用。
我們面臨的問題,不是語言和庫為我們提供了多少可能。而是我們無法確定,我們到底至少需要什么?
通常,數組讓我們可以隨機(以 O(1) 的時間復雜度)訪問其內的數據。但是,隨機訪問不是目的,而是手段。我們究竟需要一個數組解決怎樣的問題?面對怎樣的問題,需要處理的數據需要以數組方式組織?我這幾年始終不敢說自己得到了確切的答案。往往,我們只是直覺上感覺,用一個 vector (使用 C++ )非常方便,所以就用了。當我在用 C 的時候,我總是隨手寫上一個 realloc ,來擴展我的數據塊。最近一段時間,我覺得有必要歸納一下需求,設計一個通用模塊來統一解決問題了。
思考的結果就是:當我們周期性的聚合一堆數據時,我們需要一個數組,且這個數組的長度是不確定的,應該可以動態增長。
數組最重要的特性是可以最高效的遍歷,即依次處理數組內部的元素。在 C 語言的層面考慮這個問題時,就應該更細致考慮實現的差別引起的性能差異。比如鏈表的遍歷同樣是 O(N) ,但是時間和空間的開銷都是大于連續內存空間的數組的。
我們需要快速的清空數組,方便下一個周期聚合新的數據。
我們需要對數據排序,使得按我們的需要的次序去依次處理(遍歷)數組中的元素。
有時候,我們需要相對快速的查找。一旦數據是有序的,二分查找可以讓時間復雜度減少到 O(log n) 。
其它,我們不再需要。
注:我們往往混淆了另一個需求。很多時候,我們把數組當成了一個高性能卻有局限性的 key-value 字典。這個 key 就是數組內數據的數字索引。對于用一個 key (可能是數,也可能不是)快速索引到值的需求,應該放到另一個地方去考慮。
?
?
最終,我為 array 這個 ADT 提供了如下的方法:
struct array * array_create(int atom_size); void array_release(struct array *); void array_clear(struct array *); void array_push(struct array *, void *atom); void array_iterator(struct array *, seqi iter); void array_sort(struct array *, int (*compar)(void *,void *));這里,暫時沒有提供 binarysearch 方法,因為暫時我還沒有用到。我還不確定是不是真的有意義,以及最佳的接口定義應該是怎樣。
在實現時,我開辟了一整塊連續內存保存數據。當使用者 push 一個元素時,采用值復制的方式,復制到 array 內部。然后用 seq 來管理對內部元素的引用(指針)。
當數據區不夠大時,采用 realloc 擴展數據區內存。一旦內存地址發生變化,則修改對應的 seq 里的指針。把索引和數據分開存放,可以提高排序的效率(數據交換量比較小)。
sort 函數提供了一個類似 qsort 接口的比較函數。但是,由于和 qsort 的定義有所不同,所以不能直接去調用 qsort 。在 glibc 中,有另一個 qsort_r 可以滿足需求。不過我考慮到性能,自己重新實現了一個快速排序。反正,也沒幾行代碼。
?
?
這里,由于數據在內存中的位置并不固定。從 seqi 中拿到的指針是不可以被傳遞保存到別的數據結構體中的。包括 seqi 這個迭代子,根據上篇關于 sequence 實現的描述,也不允許長期保留。你可以認為,這是這個 ADT 的局限性。不過我個人認為,我們每設計一個東西,只應該解決有限的,定義好的需求。而不應該包羅萬象。
只做一件事,并把它做好。
總結
以上是生活随笔為你收集整理的Standard C Library - 思维火花 - 博客频道 - CSDN.NET的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 实现高性能稳定的socket tcp通讯
- 下一篇: 【转】 PDO使用归纳【PHP】