您的位置:首页 > 其它

ArrayList,List等非链式线性结构是如何实现动态增长的

2014-02-19 02:39 323 查看
以前一直很好奇ArrayList和List等结构是怎么实现动态增长的。由于以前基础不扎实一直没深究,直接实现IList接口的时候也是写的一个很大长度的数组,最近在实现数据结构的时候也遇到了这个问题,带着这个问题,研究了.net框架的源码终于给解决了.很开心

ArrayList的内部数组是这个

如图


很显然这个数组是在构造函数分配的空间点进构造函数如图



点进emptyArray如图



看到发现他是个静态的变量可以联想到是在静态构造函数中分配空间的果然在类中发现了静态构造函数我们点进去如图




这里就证明了我以前的结论是错的,.net源码里并没有为数组初始分配一个很大的空间。而分配一个很大的空间类似int []nums = new int[10000]的缺点很明显浪费空间。这里就不细说了 那.net框架是如果做到动态添加元素的呢?我们点进ArrayList的Add方法如图



这里我解释下这个size就是数组的最大长度也就是说当数组的长度 等于这个最大长度的就进入if语句逻辑 这里就开始重新给数组分配空间了它具体如何做到的呢 点进EnsureCapacity方法如图



可能有的人开到16进制就看不下去。研究源码就应该穷追猛打,吾辈之程序猿又怎能被微软的一点手段放弃.咋一看这段代码的确没什么特别, 这里个人认为了微软用了观察者设计模式的思想 。首先intnum
= (this._items.Length
== 0) ? 4 : (this._items.Length
* 2); num 如果item的长度是0 就赋值为4也就是初值,如果不是0就翻倍. num就是数组的动态长度,也就是说数组的长度是由2,变到4变到8变到16 而把0x7fefffff数转化一下 我们会发现这个数的值是2146435071 soga.这正好是int类似的上限也就是说动态增长是不能封顶的! 但是到底在哪里改变的数组呢?我们点开Capacity如图



给Capacity赋值调用set方法value就是刚刚的num也就是数组的动态长度.net框架这里new了一个新的destinationArray长度是新长度 然后调用Array.Copy拷贝数组完成赋值。实现了动态增长。

哈哈是不是很神奇?

分析:

这种设计非常科学优点有二:

1.动态增长避免了空间的浪费

2.最大长度每次乘以2 不会有太多次动态增长的情况。毕竟每次增长要调用Array.Copy方法有个O(n)的时间复杂度
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: