LinkedList遍历方式区别

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<E> node(int index) {
 2         // assert isElementIndex(index);
 3
 4         if (index < (size >> 1)) {
 5             Node<E> x = first;
 6             for (int i = 0; i < index; i++)
 7                 x = x.next;
 8             return x;
 9         } else {
10             Node<E> 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<Integer> linkedList = getList();
        iterateByFori(linkedList);
        iterateByForEach(linkedList);
        iterateByIterator(linkedList);
    }

    private static LinkedList<Integer> getList(){
        LinkedList<Integer> linkedList = new LinkedList<>();
        for (int i = 0; i < 100000; i++) {
            linkedList.add(i);
        }
        return linkedList;
    }

    //fori方式
    private static void iterateByFori(LinkedList<Integer> 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<Integer> 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<Integer> linkedList){
        long time1 = System.currentTimeMillis();
        Iterator<Integer> iterator = linkedList.iterator();
        while (iterator.hasNext()){
            iterator.next();
        }
        long time2 = System.currentTimeMillis();

        System.out.println("Iterator方式遍历的时间花费为:"+(time2-time1));
    }
}

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

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

原文地址:https://www.cnblogs.com/gsm340/p/9243916.html

时间: 2024-10-09 18:58:29

LinkedList遍历方式区别的相关文章

Arraylist、Linkedlist遍历方式性能分析

本文主要介绍ArrayList和LinkedList这两种list的常用循环遍历方式,各种方式的性能分析.熟悉java的知道,常用的list的遍历方式有以下几种: 1.for-each List<String> testList = new ArrayList<String>(); for (String tmp : testList) { //use tmp; } 这种遍历方式是最常用的遍历方式,因为书写比较方便,而且不需要考虑数组越界的问题,Effective-Java中推荐使

ArrayList和LinkedList的几种循环遍历方式及性能对比分析

主要介绍ArrayList和LinkedList这两种list的五种循环遍历方式,各种方式的性能测试对比,根据ArrayList和LinkedList的源码实现分析性能结果,总结结论.通过本文你可以了解(1)List的五种遍历方式及各自性能 (2)foreach及Iterator的实现 (3)加深对ArrayList和LinkedList实现的了解.阅读本文前希望你已经了解ArrayList顺序存储和LinkedList链式的结构,本文不对此进行介绍. 相关:HashMap循环遍历方式及其性能对

ArrayList和LinkedList的几种循环遍历方式及性能对比分析(转)

主要介绍ArrayList和LinkedList这两种list的五种循环遍历方式,各种方式的性能测试对比,根据ArrayList和LinkedList的源码实现分析性能结果,总结结论. 通过本文你可以了解(1)List的五种遍历方式及各自性能 (2)foreach及Iterator的实现 (3)加深对ArrayList和LinkedList实现的了解. 阅读本文前希望你已经了解ArrayList顺序存储和LinkedList链式的结构,本文不对此进行介绍. 相关:HashMap循环遍历方式及其性

【转】ArrayList和LinkedList的几种循环遍历方式及性能对比分析

原文网址:http://www.trinea.cn/android/arraylist-linkedlist-loop-performance/ 主要介绍ArrayList和LinkedList这两种list的五种循环遍历方式,各种方式的性能测试对比,根据ArrayList和LinkedList的源码实现分析性能结果,总结结论.通过本文你可以了解(1)List的五种遍历方式及各自性能 (2)foreach及Iterator的实现 (3)加深对ArrayList和LinkedList实现的了解.阅

lua中for循环的四种遍历方式

lua中for的四种遍历方式区别 table.maxn 取最大的整数key #table 从1开始的顺序整数最大值,如1,2,3,6 #table == 3 key,value pairs 取每一个键值对 ipairs 取从key==1开始的顺序整数最大值,每个键值对 参考http://rangercyh.blog.51cto.com/1444712/1032925 不过有一个问题, tbtest = { [1] = 1, [2] = 2, [4] = 4, } print(#(tbtest))

专题三、ArrayList遍历方式以及效率比较

一.遍历方式 ArrayList支持三种遍历方式. 1.第一种,随机访问,它是通过索引值去遍历 由于ArrayList实现了RandomAccess接口,它支持通过索引值去随机访问元素. 代码如下: // 基本的forfor (int i = 0; i < size; i++){    value = list.get(i);} 2.第二种,foreach语句 foreach语句是java5的新特征之一,在遍历数组.集合方面,foreach为开发人员提供了极大的方便. 代码如下: for (In

HashMap、HashTable、ArrayList、LinkedList、Vector区别

HashTable和HashMap区别 ①继承不同. public class Hashtable extends Dictionary implements Map public class HashMap extends AbstractMap implements Map ② Hashtable 中的方法是同步的,而HashMap中的方法在缺省情况下是非同步的.在多线程并发的环境下,可以直接使用Hashtable,但是要使用HashMap的话就要自己增加同步处理了. ③ Hashtable

list的四种遍历方式

1.手先增强for循环和iterator遍历的效果是一样的,也就说 增强for循环的内部也就是调用iteratoer实现的,但是增强for循环 有些缺点,例如不能在增强循环里动态的删除集合内容.不能获取下标等. 2.ArrayList由于使用数组实现,因此下标明确,最好使用普通循环. 3.而对于 LinkedList 由于获取一个元素,要从头开始向后找,因此建议使用 增强for循环,也就是iterator. list,map,set的区别  list,map,set的区别 (首先假定小猪都是同一

重温数据结构:二叉树的常见方法及三种遍历方式 Java 实现

读完本文你将了解到: 什么是二叉树 Binary Tree 两种特殊的二叉树 满二叉树 完全二叉树 满二叉树 和 完全二叉树 的对比图 二叉树的实现 用 递归节点实现法左右链表示法 表示一个二叉树节点 用 数组下标表示法 表示一个节点 二叉树的主要方法 二叉树的创建 二叉树的添加元素 二叉树的删除元素 二叉树的清空 获得二叉树的高度 获得二叉树的节点数 获得某个节点的父亲节点 二叉树的遍历 先序遍历 中序遍历 后序遍历 遍历小结 总结 树的分类有很多种,但基本都是 二叉树 的衍生,今天来学习下二