我知道因为数组的内存中连续和等分的特点,所以对于任意一个二维数组int[][]
LOC(i,j)=LOC(0,0) + (b*i + j)L
LOC(0,0)是该二维数组的起始存储位置,b 是每行的长度,L 是每个数据元素的宽度
所以 get 和 set 的时间复杂度是一个常数时间 O(1)
但是对于锯齿数组
int[][] ja = new int[4][];
ja[0] = new int[6];
ja[1] = new int[4];
ja[2] = new int[4];
ja[3] = new int[5];
第二维度的长度并不固定,如果要计算出 LOC(i,j)是不是需要通过 sum 确定偏移量
这样对于锯齿数组的 get 和 set 是不是 O(i-1)?
1
xenme 2019-10-01 14:29:22 +08:00 via iPhone
数组里面存不定长数组的地址
等于取两次地址 或者长度变化不大的,按最大长度指定。变成普通数组 |
2
xupefei 2019-10-01 14:37:22 +08:00 via iPhone
get 在最坏情况下需要 sum 所有的行,所以是 O(i)。
set 在给定坐标的情况下还是 O(1)。 |
5
xupefei 2019-10-01 15:04:03 +08:00
@asiufasd 你指的是把第一层指针换成链表还是把所有数组都换成链表?
无论怎样都不行,因为链表比数组慢很多且不支持随机访问。 最好的办法是像一楼说的那样,变成普通数组。 还有个办法是按长度排序,每 n 行分出一个组,一个组里所有的数组长度等于此组内最长数组的长度。 |
6
asiufasd OP @xupefei 我是想说既然对于锯齿数组 get 和 set 已经不是 O(1)了,那就失去了数组的随机访问的特性了,相比之下链表还有插入和删除的速度优势。
其实仔细想想可能更想表达的是,对于锯齿数组在内存中的存储结构是怎么样子的,可能确实如一楼所言是数组里面存不定长数组的地址,并不是普通数组那样内存中连续的结构吧。 |
7
xupefei 2019-10-01 15:24:51 +08:00
@asiufasd 数组的数组在内存里不连续。在内存里是一个连续的指针数组,其中每个指针指向另一个连续数组。
锯齿数组(数组的数组):访问行是 O(i),访问列是 O(1)。 链表的链表:访问行是 O(i),访问列是 O(i)。 链表的数组:访问行是 O(1),访问列是 O(i)。 如果你有插入需求的话就没得选了,只能链表。 |
8
reus 2019-10-01 18:23:36 +08:00 via Android
可以加 skiplist 维护偏移量
|