一些对于数组的记录与思考

  数组是一段存放着相同数据类型的连续内存空间,这大概是最早接触到的第一种数据结构了。

  以前老是说数组查找某一个元素很高效,在做删除和插入的操作确实很慢的。为什么呢,首先我理解的是申请一段数组空间时,是系统为我们分配内存,我们并不知道其中某一个与元素的地址是什么,但是可以通过寻址公式:(a[i]_address = first_address + i * type_of_size)快速计算出所查找的元素地址,至于怎么访问,当然是通过指针咯。数组查找某一元素的时间复杂度是O(1),插入和删除的最好时间复杂度也是O(1),最坏时间复杂度是O(n) 。因为可能插入的位置刚好在第一个或者最后一个,平均时间复杂度却是O(n),因为每插入一个元素,为了保持内存空间的连续性,插入元素后面的数据都要进行一次数据迁移的操作,如果数组的空间满了,则要进行扩容,插入到没个位置的概率是一样的,所以T(n)= O(n) = (1+2+3+.......+n/n)=(n+n(n-1)/2)/n = (n + 1)/2 = O(n)。

  数组的插入和删除都是低效的,那有没有什么办法优化一下呢?答案是有的,这也是我近期学习过程中了解到的,在这里记录一下:

  插入:插入操作时对于一组有序的数据,每插入一个数据则要进行后面的数据迁移。但对于无序的数据,在并不关系数据顺序的情况下,可以进行插入数据的替换。比如说初始化这样一个数组char * arr[7] = “apple”,这个数组并未存满,在数组的第三个位置插入字母o,则可以将a[2] = ‘o’,a[5] = ‘p’,这样时间复杂度就变成了O(1),但只限于这种无序的数组。

  删除:还是这个例子char * arr[6] = “apple”,想要删除前三个字母,可以先将这三个字母删除,却不进行数据迁移的操作,直到数组中的空间满了之后,再进行一次数据的迁移,这样就减少了数据迁移的操作。

  使用数组要小心,谨防数组越界是一个程序员的职业素养呢,哈哈。这里记录一段很有意思的代码,一个不小心,就会引发无尽的意想不到。

1 int main(int argc, char* argv[]){
2     int i = 0;
3     int arr[3] = {0};
4     for(; i<=3; i++){
5         arr[i] = 0;
6         printf("hello world\n");
7     }
8     return 0;
9 }

  这个函数死循环了,访问a[3]会越界,可是为什么会导致死循环当时也是百思不得其解,后来了解到原来是这个i在作祟。因为i和arr都是局部变量,在存储局部变量时会进行压栈的操作,且栈是自顶向下增长的,所以这两个变量在当前栈桢的存储顺序是i a[2] a[1] a [0],当访问a[3]时,根据寻址公式,正好访问到了i的地址,也就是将i = 0,所以就导致了死循环的。这里还有最后一个疑问,为什么a[3]的地址就正好等于i的地址呢,因为他们是相同的数据类型,开辟的内存空间也一样大,根据寻址公式计算就刚好是i的地址了。如果它们的类型不相同的话,则会出现数组越界访问的错误。

猜你喜欢

转载自www.cnblogs.com/leoncumt/p/10332307.html