之前小六六一直觉得自己的算法比较菜,算是一个短板吧,以前刷题也还真是三天打鱼,两天晒网,刷几天,然后就慢慢的不坚持了,所以这次,借助平台的活动,打算慢慢的开始开刷,并且自己还会给刷的题总结下,谈谈自己的一些思考,和自己的思路等等,希望对小伙伴能有所帮助吧,也可以借此机会把自己短板补一补,希望自己能坚持下去呀
之前刷了不少题了,这边又开始了,这个月从数组刷起吧,嘿嘿,感谢掘金和大家的支持,我们冲
数组是数据结构中最基础的结构,是很多高级数据结构实现的基石,打好这个基础才能走的更远。数组与链表是物理内存中真实存在的物理结构,二叉树、二叉搜索树、红黑树、图、堆等其他数据结构都是属于逻辑结构,底层都是用数组和链表实现。
数组是存放在连续内存空间上的相同类型数据的集合。可以方便的通过下标索引的方式获取到下标下对应的数据。
不能单独删除、释放数组中的某个元素,只能覆盖。如果要释放,就是全释放(程序运行结束,回收内存栈空间)。
因为数组的在内存空间的地址是连续的,所以我们在删除或者增添元素的时候,就难免要移动其他元素的地址。对于数组来说,在尾部插入、删除元素是比较高效的,时间复杂度是 O(1),但是如果在中间或者开头插入、删除元素,就会涉及数据的搬移,时间复杂度为 O(N),效率较低。
技巧: 把待删除元素交换到最后一个,然后再删除,就可以避免数据搬移。
使用双指针法,可原地修改数组
数组(Array):一种线性表数据结构,用一组连续的内存空间,来存储一组具有相同类型的数据。 通过数组的定义,我们可以看到数组是一种线性表数据结构。线性表,顾名思义,就是将存储的数据排成一条线一样的结构,存储的每个数据最多只有前后两个方向。
数组是用连续内存空间存储相同类型的元素,就是因为有这个限制条件,使得数组按照下标随机访问(随机访问:可以用同等的时间访问到一组数据中的任意一个元素)数组中数据元素时间复杂度达到 O(1) 级别。当然这样的限制也有缺点,在头部或者中间进行数据删除、插入操作时,为了保证这个连续性,需要对数据进行大量的复制迁移来保持此特性。
下面我们通过代码来看一下,数组是如何通过下标来访问数据,使得时间复杂度达到 O(1) 级别的。
// 数组初始化必须为它指定初始容量
int[] i = new int[10];
上面的代码,我们声明了一个数组 i ,i 是这个数组的引用变量,指向这个数组的首地址(计算机会给每个内存单元分配一个地址,计算机通过这个地址来访问内存中的数据)。因为数组是连续的内存空间且数据类型相同,当我们知道了数据的首地址,便可以通过下面的公式,计算出数组中每个元素的内存地址,然后让计算机直接访问,达到 O(1) 级别的时间复杂度
// i 表示数组下标, base_address 表示数组首地址,data_type_size 表示数组中每个数据大小
a[i]_address = base_address + i * data_type_size
这里有一个注意点,我们是通过数组下标访问数据时,时间复杂度才是 O(1) ,当我们通过数据查找元素时,我们需要遍历数组查找对应的数据,时间复杂度是 O(n)。
我们知道一维数组的空间地址肯定是连续的,那么我们的二维数组的地址呢?是不是也是连续的呢?
不同编程语言的内存管理是不一样的,以C++为例,在C++中二维数组是连续分布的。
我们来做一个实验,C++测试代码如下:
void test_arr() {
int array[2][3] = {
{0, 1, 2},
{3, 4, 5}
};
cout << &array[0][0] << " " << &array[0][1] << " " << &array[0][2] << endl;
cout << &array[1][0] << " " << &array[1][1] << " " << &array[1][2] << endl;
}
int main() {
test_arr();
}
测试地址为
0x7ffee4065820 0x7ffee4065824 0x7ffee4065828
0x7ffee406582c 0x7ffee4065830 0x7ffee4065834
注意地址为16进制,可以看出二维数组地址是连续一条线的。
那么我们来看看Java的,也做一个实验。
public static void test_arr() {
int[][] arr = {{1, 2, 3}, {3, 4, 5}, {6, 7, 8}, {9,9,9}};
System.out.println(arr[0]);
System.out.println(arr[1]);
System.out.println(arr[2]);
System.out.println(arr[3]);
}
输出的地址为:
[I@7852e922
[I@4e25154f
[I@70dea4e
[I@5c647e05
这里的数值也是16进制,这不是真正的地址,而是经过处理过后的数值了,我们也可以看出,二维数组的每一行头结点的地址是没有规则的,更谈不上连续。