数据结构与算法--01数组:为什么很多编程语言中数组从0开始编号?
- 一、数组特性
- 二、数组访问越界问题
- 三、数组与容器
- 四、回到开篇
- 五、总结
一、数组特性
1.数组本质上是一种线性表数据结构,用一组连续的内存空间来存储一组具有相同类型的数据。除了数组,链表、队列、栈等也是线性表结构。相对线性表的是非线性表,包括二叉树、堆、图等,其结构并不是简单的前后关系。
2.连续的内存空间和相同类型的数据。
正是这两个特性,使得数组具有“随机访问”的特性,但也具有操作低效的弊端。
二、数组访问越界问题
直接上代码:
int main(int argc, char* argv[])
{
int i = 0;
int arr[3] = {0};
for(; i <= 3; i++) {
arr[i] = 0;
printf("hello world\n”);
}
return 0;
}
这段代码的运行结果并非是打印三行“hello word”,而是会无限打印“hello world”,这是为什么呢?数组访问越界。
我们知道,在C语言中,只要不是访问受限的内存,所有的内存空间都是可以自由访问的,那么a[3]就会被定位到某块不属于数组的内存地址上,而这个地址正好是存储变量i的内存地址,那么a[3]=0就相当于i=0,所以会导致无限循环。
三、数组与容器
针对数组类型,很多语言提供了容器类,比如Java中的ArrayList、C++STL中的vector,那么何时使用它们呢?
- ArrayList优势:可以将很多数组操作的细节封装起来、支持动态扩容,每次存储空间不够时,它会将空间自动扩容为1.5倍大小。
- ArrayList缺点:正因为扩容操作,会涉及内存申请和数据搬移,是比较耗时的。所以,如果事先能确定需要存储的数据大小,最好在创建 ArrayList 的时候事先指定数据大小。
- 数组优势:可以存储基本类型,如int、long,而ArrayList则需要封装为Integer、Long类。
- 如果数据大小事先已知,并且对数据的操作非常简单,用不到 ArrayList 提供的大部分方法,也可以直接使用数组。
- 表示多维数组时,用数组往往比较直观。
总结:对于业务开发,直接使用容器就足够了,省时省力。毕竟损耗一点性能,完全不会影响到系统整体的性能。但如果你是做一些非常底层的开发,比如开发网络框架,性能的优化需要做到极致,这个时候数组就会优于容器,成为首选。
四、回到开篇
为什么很多编程语言中数组从0开始编号?
- 从数组存储的内存模型上来看,“下标”最确切的定义应该是“偏移,因此会涉及减法操作。那么从0开始编号能够减少一次减法操作,以提升处理效率。
- 历史原因,习惯问题。
五、总结
数组可以说是最基础、最简单的数据结构了。数组用一块连续的内存空间,来存储相同类型的一组数据,最大的特点就是支持随机访问,但插入、删除操作也因此变得比较低效,平均情况时间复杂度为 O(n)。在平时的业务开发中,我们可以直接使用编程语言提供的容器类,但是,如果是特别底层的开发,直接使用数组可能会更合适。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)