数据结构与算法 - 数组

198 阅读3分钟

要点

  1. 内存存储空间连续,支持随机访问、
  2. 数据的插入和删除,都涉及到元素的移动,主要是为了保持存储空间联系的特征
  3. 平均时间复杂度都为O(n)

数组案例

JVM标记清除算法

主要是在删除数组中的元素时,当时不删除,记录那个位置的元素已经删除,位置不够的时,一次性移动元素整理数组的元素;

大多数主流虚拟机采用可达性分析算法来判断对象是否存活,在标记阶段,会遍历所有 GC ROOTS,将所有 GC ROOTS

可达的对象标记为存活。只有当标记工作完成后,清理工作才会开始。

不足:

1.效率问题。标记和清理效率都不高,但是当知道只有少量垃圾产生时会很高效

2.空间问题。会产生不连续的内存空间碎片。

多维数组在内存中的存储形式

行优先和列有限

寻址方式实例

对于 m * n 的数组,a [ i ][ j ] (i < m,j < n)的地址为:address = base_address + ( i * n + j) * type_size

数组越界导致无限循环

另外,对于数组访问越界造成无限循环,我理解是编译器的问题,对于不同的编译器,在内存分配时,会按照内存地址递增或递减的方式进行分配。老师的程序,如果是内存地址递减的方式,就会造成无限循环。

int main(int argc, char* argv[]){
    int i = 0;
    int arr[3] = {0};
    for(; i<=3; i++){ // i < 3 而不是 i  <= 3 
        arr[i] = 0;  // 当i = 3 时 arr[3] = 0 修改了 变量 i 的值;所以i的值为0了,所以形成了无限循环;
        printf("hello world\n");
    }
    return 0;
}

为什么 i 变量的存储位置在数组的后面呢?

对文中示例的无限循环有疑问的同学,建议去查函数调用的栈桢结构细节(操作系统或计算机体系结构的教材应该会讲到)。

函数体内的局部变量存在上,且是连续压栈。在Linux进程的内存布局中,栈区在高地址空间,从高向低增长。变量i

arr在相邻地址,且i比arr的地址大,所以arr越界正好访问到i。当然,前提是i和arr元素同类型,否则那段代码仍是未决行为。

其他的解释

死循环的问题跟编译器分配内存和字节对齐有关 数组3个元素

加上一个变量a 。4个整数刚好能满足8字节对齐,所以i的地址恰好跟着a后面 导致死循环。

如果数组本身有4个元素 则这里不会出现死循环。因为编译器64位操作系统下默认会进行8字节对齐

变量i的地址就不紧跟着数组后面了

还需要继续阅读有关文章