首页 > 其他分享 >ArrayList和LinkList实现的比较

ArrayList和LinkList实现的比较

时间:2024-08-06 13:50:27浏览次数:16  
标签:index return int ArrayList 元素 LinkList 比较 size

一、ArrayList和LinkList实现的比较

1.使用get()获取元素
1.1 ArrayList.get()

​ 如果希望使用ArrayListget(int index)方法获取元素,实现可以简单地将这项任务委托给其内部数组:

public E get(int index) {
    rangeCheck(index);

    return elementData(index);
}

​ 当然,还会对给定索引执行额外检查(确保它不小于零或大于数组大小)。

我们可以看到这个操作是在常数时间内执行的,即O(1)。这意味着无论数组大小如何,任何请求的元素都将立即返回,而不需要遍历列表。这是因为整个数组存储在内存中的一个唯一位置。

第二个元素的槽正好位于第一个元素之后,第n个元素的槽正好位于第 n+1 个元素之前。依靠这个内部结构,任何元素都可以很容易地通过索引来获取。

1.2.LinkedList.get()

​ 如果希望从 a 中获取元素LinkedList,可以使用该get(int index)方法,但效率很低。

​ 前面我们提到过链表并不存在于内存中的单个位置,而是包含相互连接的不同节点。要获取元素,需要从头(或尾,以较接近者为准)遍历列表,并跟踪每个节点的连接,直到找到所需的元素。

public E get(int index) {
    checkElementIndex(index);
    return node(index).item;
}

private void checkElementIndex(int index) {
    if (!isElementIndex(index))
        throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}

private boolean isElementIndex(int index) {
    return index >= 0 && index < size;
}

Node<E> node(int index) {
    if (index < (size >> 1)) {
        Node<E> x = first;
        for (int i = 0; i < index; i++)
            x = x.next;
        return x;
    } else {
        Node<E> x = last;
        for (int i = size - 1; i > index; i--)
            x = x.prev;
        return x;
    }
}

首先,进行检查以确保索引不大于0或大于LinkedList. 然后,该node()方法遍历列表,直到遇到我们要搜索的列表。

ArrayListO(1)时间相比,这是在O(N)时间内完成的。`

2.使用add()插入元素

​ 本质上,任何类型的插入都可以使用一种通用方法来概括和实现 - 在给定索引处插入。

​ 如果需要在开头插入元素,可以使用索引0调用该方法。如果需要在末尾插入元素,则索引将对应于列表的当前大小。如果需要在中间某处插入元素,则用户必须提供该索引。

2.1ArrayList.add()

​ 在末尾插入元素相当简单,特别是对于像ArrayList. 您只需将长度延长一,然后将元素插入到末尾:

public boolean add(E e) {
    ensureCapacityInternal(size + 1);  // Increments modCount!!
    elementData[size++] = e;
    return true;
}

​ 然而,在给定位置插入有点棘手。您必须在要插入的位置破坏数组 - 复制该点之后的所有内容并将其移动到右侧,在索引处添加新元素:

public void add(int index, E element) {
    rangeCheckForAdd(index);

    ensureCapacityInternal(size + 1);  // Increments modCount!!
    System.arraycopy(elementData, index, elementData, index + 1, size - index);
    elementData[index] = element;
    size++;
}

​ 复制的部分越大,此操作就越慢。这使得添加元素的ArrayList操作效率相对较低。然而,到达应该完成插入的位置确实非常有效。

2.2LinkedList.add()

LinkedList的实现允许我们相当容易地在任何给定索引处添加元素。您只需将前一个元素和后一个元素的head指针tail分别指向新元素即可。如果您在列表的开头或末尾插入,则只需要更新一个指针。

在链表中间插入节点

public boolean add(E e) {
    linkLast(e);
    return true;
}

void linkLast(E e) {
    final Node<E> l = last;
    final Node<E> newNode = new Node<>(l, e, null);
    last = newNode;
    if (l == null)
        first = newNode;
    else
        l.next = newNode;
    size++;
    modCount++;
}

无论列表有多大,只需要更改两个指针。这使得添加元素成为一种LinkedList高效的操作。然而,到达应该插入元素的位置是低效的。

3.使用indexOf0查找元素

​ 查找列表中的元素(无论是ArrayList还是 LinkedList) 应该非常相似。这是因为除非数组已排序且均匀分布,否则无法先验地知道任何特定元素的存储位置。

​ 列表只是记录其元素并提供操作它们的方法。为了准确地知道每个元素的位置,两种实现都需要经历某种迭代过程,直到找到该元素。

3.1ArrayList.indexOf()

在ArrayList实现中,这是通过一个简单的for循环从到0size-1并检查当前索引处的元素是否与给定值匹配来完成的:

public int indexOf(Object o) {
    if (o == null) {
        for (int i = 0; i < size; i++)
            if (elementData[i]==null)
                return i;
    } else {
        for (int i = 0; i < size; i++)
            if (o.equals(elementData[i]))
                return i;
    }
    return -1;
}

这实际上是一种线性搜索,效率不是很高,但实际上是在打乱的集合中搜索元素的唯一方法(如果我们忽略元启发式算法和近似值)。

3.2LinkedList.indexOf()

LinkedList有些不同。它不必遍历数组,而是必须使用指针从一个元素跳转到下一个元素来遍历列表。最终,结果是相同的 - 逐一访问每个元素,直到找到要搜索的元素:

public int indexOf(Object o) {
    int index = 0;
    if (o == null) {
        for (Node<E> x = first; x != null; x = x.next) {
            if (x.item == null)
                return index;
            index++;
        }
    } else {
        for (Node<E> x = first; x != null; x = x.next) {
            if (o.equals(x.item))
                return index;
            index++;
        }
    }
    return -1;
}

复制的部分越大,此操作就越慢。同样,这使得ArrayList从操作中删除元素变得低效。不过,ArrayList 的一个好处是您可以非常轻松地获得该元素。elementData(index)返回您希望在O(1)时间内删除的元素。

4.使用rremove()删除元素
4.1ArrayList.remove()

​ 与在给定索引处添加元素非常相似,删除它们需要ArrayList复制自身的一部分并重新初始化没有值的数组,将复制的部分向左移动:

public E remove(int index) {
    rangeCheck(index);

    modCount++;
    E oldValue = elementData(index);

    int numMoved = size - index - 1;
    if (numMoved > 0)
        System.arraycopy(elementData, index+1, elementData, index, numMoved);
        elementData[--size] = null; // clear to let GC do its work

    return oldValue;
}

复制的部分越大,此操作就越慢。同样,这使得ArrayList从操作中删除元素变得低效。不过,ArrayLists的一个好处是您可以非常轻松地获得该元素。elementData(index)返回您希望在O(1)时间`内删除的元素。

4.2LinkedList.remove()

LinkedList通过取消我们要删除的元素的前一个和后一个指针的链接,可以从 a 中删除一个元素。之后,前一个元素链接到行中的下一个元素。这样,旧元素就“搁浅”了,没有对其的引用,GC 会处理它:

public boolean remove(Object o) {
    if (o == null) {
        for (Node<E> x = first; x != null; x = x.next) {
            if (x.item == null) {
                unlink(x);
                return true;
            }
        }
    } else {
        for (Node<E> x = first; x != null; x = x.next) {
            if (o.equals(x.item)) {
                unlink(x);
                return true;
            }
        }
    }
    return false;
}

这使得LinkedList删除元素的操作变得``高效,因为同样只需要更改几个点。不过,列表越长,到达需要删除的元素所需的时间就越长,因为我们无法通过索引访问元素。

参考连接: https://stackabuse.com/difference-between-arraylist-and-linkedlist-in-java-code-and-performance/#performancecomparison

标签:index,return,int,ArrayList,元素,LinkList,比较,size
From: https://www.cnblogs.com/reubenche/p/18344984

相关文章

  • Java集合:Collection and Map;ArrayList;LinkList;HashSet;TreeSet;HashMap;TreeMap;Iterator:
        集合介绍:                        是一组变量类型(容器),跟数组很像。一,引用集合的原因(必要性):                  A:数组的空间长度固定,一旦确定不可以更改。多了浪费,少了报错。          B:使用数......
  • 面试考点分析( ArrayList和LinkedList对比)
    1.ArrayList是实现了基于动态数组的数据结构,LinkedList基于链表的数据结构。2.两者都是线程不安全,都实现了Collection接口。3.数据结构:ArrayList是基于动态数组的数据结构,LinkedList是基于双向链表的数据结构。性能:ArrayList支持随机访问,查询快,增删慢,查询的时间复杂度为O(1),插......
  • for、foreach、stream性能比较
    1、for循环publicstaticvoidmain(String[]args){ LongstartTime=System.currentTimeMillis();formMethod();LongendTime=System.currentTimeMillis();System.out.println("result:"+(endTime-startTime));}publicstaticvoid......
  • 开源文档协作平台比较:哪个最适合你?
    国内外主流的10款开源文档协作平台对比:PingCode、Worktile、蚂蚁笔记(Leanote)、Wizard、Kooteam、ShowDoc、MrDoc、DooTask、语雀、WookTeam。在今天的数字化时代,寻找一个能够提高团队合作效率并确保信息共享流畅的解决方案,成了许多企业和个人的迫切需求。开源文档协作平台以其......
  • 了解 Databricks 文件系统 (DBFS) 中的文件访问与使用 Python 和 Spark 的卷的比较
    我当前正在尝试从Databricks文件系统(DBFS)读取和显示文件,但遇到了问题。这是我使用的代码:file_path="/dbfs/cluster-logs/use_case/default_job_cluster/cluster_id/init_scripts/cluster_id/20240801_proxy-init.sh.stderr.log"withopen(file_path,'r')asfile:......
  • 模拟实现 strcmp(字符串比较) --浅谈C语言
    C库函数-strcmp()描述C库函数intstrcmp(constchar*str1,constchar*str2)把str1所指向的字符串和str2所指向的字符串进行比较。声明下面是strcmp()函数的声明。intstrcmp(constchar*str1,constchar*str2)参数str1--要进行比较的第一个字符串。......
  • ABAP数据类型转换和不同数据类型比较
    DATA:lv_strTYPEstring,lv_str2TYPEstring,lv_charTYPEchar10,lv_iTYPEiVALUE1,lv_fTYPEpDECIMALS1VALUE'1.1'.lv_str='1.11'.lv_char='1.11'."TRUEIFlv_str=1.WRITE:1......
  • 迟滞比较器
    1. 迟滞比较器2. 比较器与迟滞:优化电路稳定性的关键所在......
  • FFmpeg在游戏视频录制中的应用:画质与文件大小的综合比较
    我们游戏内的视频录制目前只支持avi固定码率,在玩家见面会上有玩家反馈希望改善录制画质,我最近在研究了有关视频画质的一些内容并做了一些统计。录制视频大小对比首先在游戏引擎中增加了对录制mp4格式的支持,并且使用h246编码可以直接在网页上播放无法再做转码测试场景:视频尺寸固......
  • 搞定Java ArrayList,就看这一篇!
    大家好,我是小欧!今天我们来聊聊Java中的ArrayList。作为一个Java新手,初次接触ArrayList可能会觉得有点懵,不过不用担心,这篇文章会带你从零开始一步步搞定ArrayList。我们会从基础概念开始,然后逐步深入,最后通过几个实际案例来巩固学习成果。ArrayList是什么?简单来说,ArrayLis......