长度一百万的数组,get(0)和get(999999)性能有区别吗?

数组和链表,应该算是最基本的数据结构了吧。
最近在帮公司招人,这个问题我几乎是必问的,然而还是有很多同学答不上来呀,不禁让人唏嘘感慨,基础知识大家还是要多补补哦!

长度一百万的数组,get(0)和get(999999)性能有区别吗?
回答这个问题之前,先来看看数组和链表的一个区别,这样再回过头来看答案时,就会很清晰。

数组

数组(Array)是有序的元素序列。 若将有限个类型相同的变量的集合命名,那么这个名称为数组名。组成数组的各个变量称为数组的分量,也称为数组的元素,有时也称为下标变量。用于区分数组的各个元素的数字编号称为下标。数组是在程序设计中,为了处理方便, 把具有相同类型的若干元素按有序的形式组织起来的一种形式。 这些有序排列的同类数据元素的集合称为数组。

数组是一种最常用的线性数据结构,它的特点是内存连续,随机访问速度极快。

为什么数组随机访问速度极快?
在这里插入图片描述
数组的随机访问速度快,这主要依赖于连续的物理内存。因为内存是连续的,且每个元素占用的空间是等长的,所以不管数组多长,不管访问哪个元素,时间复杂度都是O(1),整个访问过程都只需要两次寻址。

数组的随机访问速度快,但是元素的插入和删除效率较低。
使用ArrayList,插入元素时,插入下标后的所有元素均需要往后移动一位。删除元素时,删除下标后的所有元素均需要向前移动一位。

链表

链表又细分为单向链表、双向链表、循环链表。

单向链表
每个节点维护一个额外的next属性,指向下一个节点。
在这里插入图片描述
双向链表
每个节点维护两个额外的属性prev和next,分别指向上一个节点和下一个节点。
在这里插入图片描述
循环链表
和双向链表一样,区别是头尾节点是相连的。
在这里插入图片描述
链表的优点就是数据的删除、添加速度很快,元素不用移动位置,只需要修改头尾指针的指向就可以了。

缺点是随机访问性能很差,为什么这么说呢?
当使用链表去访问下标数据时,流程大致如下,伪代码:

class Linked{
	Object data;
	Linked prev;
	Linked next;

	Object get(int index){
		Linked node = this;
		while (index > 0) {
			node = this.next;
			index--;
		}
		return node.data;
	}
}

链表没有下标,不像数组可以根据下标+步长直接算出元素的内存地址。链表需要通过访问next节点,不断的寻址,一个一个往下找,时间复杂度是O(n)。

数组和链表的性能对比

理论讲完了,该实战一下这两者的性能差距到底几何。

分别创建一百万长度的数组和链表,访问1万次最后的元素:

class Test{
	static int len = 1000000;
	public static void main(String[] args) {
		array();
		linked();
	}

	static void array(){
		List list = new ArrayList(len);
		for (int i = 0; i < len; i++) {
			list.add(i);
		}
		long t1 = System.currentTimeMillis();
		for (int i = 0; i < 10000; i++) {
			list.get(len-1);
		}
		long t2 = System.currentTimeMillis();
		System.out.println("数组耗时:"+(t2 - t1));
	}

	static void linked(){
		List list = new LinkedList();
		for (int i = 0; i < len; i++) {
			list.add(i);
		}
		long t1 = System.currentTimeMillis();
		for (int i = 0; i < 10000; i++) {
			list.get(len-1);
		}
		long t2 = System.currentTimeMillis();
		System.out.println("链表耗时:"+(t2 - t1));
	}
}

控制台输出:
在这里插入图片描述
What???说好的数组随机访问速度极快呢???怎么没体现出来???

哈哈,别着急,速度没区别是因为JDK对LinkedList.get()方法做了一些优化。
在这里插入图片描述
单纯的访问最后一个元素,数组和链表几乎没区别,都是两次寻址就能定位到元素。
知道原因后,代码改起来就简单了,访问中间的元素不就可以了嘛。

list.get(len-1)改为list.get(len/2),代码就不重复贴了,再次测试,结果如下:
在这里插入图片描述
看到没,效果是不是非常明显,数组耗时1毫秒,而链表用了整整23秒多,碾压式的胜利啊。
而且,链表的耗时会随着List长度的增加而增加,数组不管长度多少,性能都不会波动,原因前面已经说过了。


尾巴

长度一百万的数组,get(0)和get(999999)性能有区别吗?
相信通过这篇文章,我不说答案,大家也都知道了!!!

由于数组的内存是连续的,当需要创建长度很大的集合时,JVM很可能由于找不到一块很大的连续内存而导致内存溢出,这时可以考虑使用链表。


你可能感兴趣的文章:

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员小潘

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值