博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
LinkedList遍历方式之坑
阅读量:6904 次
发布时间:2019-06-27

本文共 3136 字,大约阅读时间需要 10 分钟。

Java中普通的遍历方式一般常用的就是fori和foreach方式,在一般情况下这两种区别不大,往往是效率区别和有一些特殊场合注意问题,下次再详解,这次先描述关于LinkedList遍历时遇到的问题。

具体问题:

项目中需要实现接收对方频繁发送过来的数据并解析后序列化文件到目的服务器,采用了定量发送的办法,每次把接收的数据解析成功后放入到LinkedList当中,当达到目标数量时,遍历LinkedList中的数据,拼接成功想要的内容,然后序列化到目的服务器中。刚开始遍历的方法是这样的:

1 for (int i = 0; i < linkedList.size(); i++) {2             linkedList.get(i); // 具体操作略,只表现遍历方式3 }复制代码

咋一看没什么问题,开始测试时目标为1w也没什么问题,后面加大目标数量到10w时有明显卡顿,程序一直停顿在遍历中,一时没明白是为什么ps一起一直用ArrayList是这种遍历方式没出现过问题,仔细查看了一下LinkedList的数据结构发现了问题所在:

LinkedList的数据结构是双向链表,在进行get方式遍历的时候采用的方式如下:

1   public E get(int index) {2         checkElementIndex(index);3         return node(index).item;4     }复制代码

checkElementIndex方法不用看具体实现,目的是判断当前元素是在链表前半段或者后半段然后决定从哪边遍历,后面的node方法决定了具体取元素的过程实现,源码如下:

1    Node
node(int index) { 2 // assert isElementIndex(index); 3 4 if (index < (size >> 1)) { 5 Node
x = first; 6 for (int i = 0; i < index; i++) 7 x = x.next; 8 return x; 9 } else {10 Node
x = last;11 for (int i = size - 1; i > index; i--)12 x = x.prev;13 return x;14 }15 }复制代码

从代码中看出,在以这种方法在遍历取元素的时候,无论目标元素在哪,都会从头部或者尾部遍历到目标节点然后取出。这种方式在链表遍历中其实是不太合理的,试想一下简单的遍历,加入有10个元素的一个链表需要遍历,那么每次元素的查询次数为 [1,2,3,4,5,5,4,3,2,1]总次数为30,时间复杂度计算方式为(n*1+(n/2)*(n/2-1)*1/1)*2渐进时间复杂度即n趋向于无穷大时约等于O(n^2).当目标数量n越大时,时间复杂度的增长也就越快,从而导致了程序假死。 分析完问题,那么来查看一下如何解决问题,不能使用fori遍历那应该采用什么方式遍历比较好呢,下面采用了3种方式遍历一个10000个元素的链表,比较了不同方式的时间花费:

public class TestLinkedList {    public static void main(String[] args) {        LinkedList
linkedList = getList(); iterateByFori(linkedList); iterateByForEach(linkedList); iterateByIterator(linkedList); } private static LinkedList
getList(){ LinkedList
linkedList = new LinkedList<>(); for (int i = 0; i < 100000; i++) { linkedList.add(i); } return linkedList; } //fori方式 private static void iterateByFori(LinkedList
linkedList){ long time1 = System.currentTimeMillis(); for (int i = 0; i < linkedList.size(); i++) { linkedList.get(i); } long time2 = System.currentTimeMillis(); System.out.println("Fori方式遍历的时间花费为:"+(time2-time1)); } //foreach方式 private static void iterateByForEach(LinkedList
linkedList){ long time1 = System.currentTimeMillis(); for (Integer j:linkedList) { //TODO } long time2 = System.currentTimeMillis(); System.out.println("foreach方式遍历的时间花费为:"+(time2-time1)); } //Iterator方式 private static void iterateByIterator(LinkedList
linkedList){ long time1 = System.currentTimeMillis(); Iterator
iterator = linkedList.iterator(); while (iterator.hasNext()){ iterator.next(); } long time2 = System.currentTimeMillis(); System.out.println("Iterator方式遍历的时间花费为:"+(time2-time1)); }}复制代码

分别一次采用了fori方式、foreach方式以及Iterator方式遍历(自带的removeFirst等方法在这里不做讨论),结果如下:

从图中可以可以看出时间花费的差别大小,所以在链表结构实现的数据集合中,最好采用Iterator或者foreach的方式遍历,效率最高。

转载地址:http://dwmdl.baihongyu.com/

你可能感兴趣的文章
CentOS Rsync服务端与Windows cwRsync客户端实现数据同步
查看>>
TAR包CLONE方式 安装11GR2 RAC数据库 (gril软件root.sh)
查看>>
Office2010 体验之PowerPoint亮点搜索
查看>>
热备份路由协议(HSRP)大型配置之详解
查看>>
修改Active Directory域控制器IP地址
查看>>
千元乐Pad,比奥迪更值得的“A1”
查看>>
Apache服务器htaccess总结
查看>>
DNS的一些实际应用(二)
查看>>
gb2312编码文件转成utf8
查看>>
xen虚拟化实战系列(四)之xen虚拟机扩展磁盘空间一法
查看>>
【算法】二叉查找树(BST)实现字典API
查看>>
通用服务器桩-Receiver使用说明文档
查看>>
使用asp.net 2.0的CreateUserwizard控件如何向自己的数据表中添加数据
查看>>
一次WinRoute后门攻防实况
查看>>
Intel主板支持硬盘热拔插显示图标的原因
查看>>
RHEL6基础三十六之服务器维护基础命令⑥sed
查看>>
浅谈AD RID池系列(三):Server 2008 R2补丁for RID
查看>>
针对桌面云终端做专用的高性价比CPU,吉湾微电子获首轮融资
查看>>
poj2481 树状数组
查看>>
Contrinex为高温应用推出新的RFID标签
查看>>