一、维度及长度均可任意变形的动态数组概述 收藏
近日,有同事需要设计一个可自由变形的多维数组,苦思数日,不得其解,求助于我。于是我帮他写了一个可自由改变维度及长度的数组ADT。后来想,网上应该也有人需要这种东西吧,何不放到博客上来,让有此需要的朋友也一同来参考参考。于是就将开始的3个函数扩展为20个函数。鉴于时间仓促,源码一定有很多不完善的地方,如果遇到哪些牛人有兴趣对其进行改进,更求之不得了。
我将此ADT称为Dynamic Dimensionality and Length Array,动态维度及长度数组,简称DDLA。它的主要特性如下:
1. 超越C99的VLA可变长数组。VLA虽然每维的长度可为变量,但仍有两个限制,一是维度不可变;二是一旦定义,长度不能再改变,即非动态的。DDLA则无论维度、长度皆动态,不但每维长度可为变量,维度也可为变量。
2. DDLA即使定义之后,仍可以根据需要在任何时候任意改变维度及长度,做到真正的完全动态,堪称数组中的变形金刚。而且,变形之后,原有数据仍可保留。变形方式简单快捷。
3. 超越c/c++数组作为形参会隐式转换为指针的特性。c/c++这项特性在提高效率的同时,也造成了在被调函数内部无法通过sizeof运算直接取得传入数组大小的问题。DDLA继续保持这个效率的同时,仍然可以在被调函数内部直接计算出传入数组的大小。
设计DDLA类型的动态数组,不可避免需要建立中间地址缓冲区,如何构造这个缓冲区?通常的算法,是随时构造随时分配,例如一个动态二维数组可以这样构造:
view plaincopy to clipboardprint?
int i, m = 10, n = 20;
int **p = ( int** )malloc( m * sizeof( int* ) );
for( i = 0; i < m; ++i )
p[i] = ( int* )malloc( n * sizeof( int ) );
int i, m = 10, n = 20;
int **p = ( int** )malloc( m * sizeof( int* ) );
for( i = 0; i < m; ++i )
p[i] = ( int* )malloc( n * sizeof( int ) );
这种方法有一个明显的缺点,就是无论元素存储区还是中间地址缓冲区都是不连续的!这会造成如下这些问题:
1. 堆管理函数频繁运行,效率低下,数组越大,效率影响越明显;
2. 如果中间某个步骤内存分配失败,需要对已分配的内存重新释放,算法复杂;
3. 数组使用完后,需要逐个内存块释放,效率低;
4. 若需要动态改变数组,算法复杂。
但实际上,中间地址缓冲区和元素存储区的大小是可以预先计算出来的,在此前提下,两个存储块可以预先整体一次分配,效率有很大提高,更重要的是,这个做法使数组变形的算法大大简化,变形过程变得非常简单,只要改变元素存储区的大小,然后重新产生中间地址就行了。DDLA就是基于这个原理设计的,使用的中间地址缓冲区和元素存储区都是连续的。
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/supermegaboy/archive/2009/08/27/4491523.aspx