Java 删除(int索引)LinkedList自身实现

Java 删除(int索引)LinkedList自身实现,java,linked-list,doubly-linked-list,Java,Linked List,Doubly Linked List,我试图学习LinkedList和ArrayList的性能对比 我已经制定了如下移除方法 LinkedList中被删除的数据大约有100万个元素。 我的问题是,删除所有项目后:这是时间记录。 如果我使用Java LinkedList删除(int索引)时间:2000纳秒 如果使用自定义删除(int索引)时间:34407000纳秒 有人能看看我的代码,告诉我哪里出了问题吗。实际上,我假设按索引位置删除数据,因为我试图实现的比较是按ArrayList的索引位置进行的 public Object remo

我试图学习LinkedList和ArrayList的性能对比 我已经制定了如下移除方法

LinkedList中被删除的数据大约有100万个元素。 我的问题是,删除所有项目后:这是时间记录。 如果我使用Java LinkedList删除(int索引)时间:2000纳秒 如果使用自定义删除(int索引)时间:34407000纳秒

有人能看看我的代码,告诉我哪里出了问题吗。实际上,我假设按索引位置删除数据,因为我试图实现的比较是按ArrayList的索引位置进行的

public Object remove(int index)
{
    checkElementIndex(index);
    return unlink(getNode(index));
}

private Object unlink(ListNode node)
{
    final Object element = node.item;
    final ListNode next = node.next;
    final ListNode prev = node.prev;

    if (prev == null)
    {
        first = next;
    } else
    {
        prev.next = next;
        node.prev = null;
    }

    if (next == null)
    {
        last = prev;
    } else
    {
        next.prev = prev;
        node.next = null;
    }

    node.item = null;
    size--;
    return element;
}

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

private void checkElementIndex(int index)
{
    if (index < 0 || index >= size)
    {
        throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size);
    }
}

    // BOTH THE LIST CONTAIN 1million items.

    startTime = System.nanoTime();
    for (int i = linkedList.size()-1; i >= 0; i--)
    {
        linkedList.remove(i);
    }
    endTime = System.nanoTime();
    duration = endTime - startTime;
    System.out.println("LinkedList Removal Time:  " + duration);

    // This is the Java Collection LinkedList
    startTime = System.nanoTime();
    for (int i = linkedList.size()-1; i >= 0; i--)
    {
        javaLinkedList.remove(i);

    }
    endTime = System.nanoTime();
    duration = endTime - startTime;
    System.out.println("My Removal Time:  " + duration);
public对象删除(int索引)
{
checkElementIndex(索引);
返回取消链接(getNode(index));
}
私有对象取消链接(ListNode节点)
{
最终对象元素=node.item;
final ListNode next=node.next;
最终列表node prev=node.prev;
if(prev==null)
{
第一个=下一个;
}否则
{
上一个=下一个;
node.prev=null;
}
if(next==null)
{
最后=上一个;
}否则
{
next.prev=prev;
node.next=null;
}
node.item=null;
大小--;
返回元素;
}
私有ListNode getNode(int索引)
{
如果(索引<(大小>>1))
{
ListNode=第一个节点;
对于(int i=0;iindex;i--)
{
node=node.prev;
}
返回节点;
}
}
私有void checkElementIndex(int-index)
{
如果(索引<0 | |索引>=大小)
{
抛出新的IndexOutOfBoundsException(“索引:+Index+”,大小:+Size);
}
}
//这两个列表都包含100万项。
startTime=System.nanoTime();
对于(int i=linkedList.size()-1;i>=0;i--)
{
linkedList.remove(i);
}
endTime=System.nanoTime();
持续时间=结束时间-开始时间;
System.out.println(“LinkedList删除时间:+持续时间”);
//这是Java集合链接列表
startTime=System.nanoTime();
对于(int i=linkedList.size()-1;i>=0;i--)
{
javaLinkedList.remove(i);
}
endTime=System.nanoTime();
持续时间=结束时间-开始时间;
System.out.println(“我的删除时间:+持续时间”);
我很感激你的每一个建议。谢谢。

(接评论)

没问题!第一步是下载一个剖析器(我使用。还有其他的,但不幸的是我不熟悉它们…),一旦下载完成,继续启动它

下一步是确定如何将探查器附加到流程。启动VisualVM后,您应该会在右侧看到正在运行的Java程序列表。你现在可以忽略这一点。诀窍在于,您需要一个长时间运行的程序,以便有足够的时间将探查器连接到进程。对于类似于您的代码的内容,更简单的方法是使用
Scanner.nextLine()
在循环之间阻止程序,有点像这样:

Scanner scanner = new Scanner(System.in);
scanner.nextLine(); // This stops the program and waits for user input.
                    // This will give us all the time in the world to attach the profiler.

// Your code
for (int i = linkedList.size()-1; i >= 0; i--)
{
    linkedList.remove(i);
}

scanner.nextLine(); // Same thing here
for (int i = linkedList.size()-1; i >= 0; i--)
{
    javaLinkedList.remove(i);
}
现在,开始你的程序。如果您回到VisualVM,您应该能够看到您的程序

现在双击你的程序。您应该会在程序的控制台中看到一些消息,并且VisualVM中的视图应该会更改。转到“采样器”选项卡,单击“CPU”,然后返回到您的程序并按enter键

你所看到的应该是不言自明的。左侧是带有package+类的完全限定方法名,以及表示方法使用的CPU时间部分的条形图。使用它来确定您的程序在哪里花费了所有的时间。就这样!如果需要更多的时间来分析,只需向链接列表中添加更多元素即可


不过,还是要谨慎一点;分析可能是骗人的,因为如果另一种方法弄乱了你的链表结构,它会使一个完美的方法比它必须的要难得多。例如,作为学校作业的一部分,我必须实现
HashMap
。当我分析时,我注意到在bucket中查找的代码占用了97%以上的CPU时间,尽管它没有什么问题。事实证明,获取适当存储桶的测试使用的是
>
而不是
。一个自己解决这个问题的好方法是使用VisualVM之类的探查器。您能发布checkElementIndex的实现吗?嗯。。。这段代码几乎是Java的
LinkedList
实现的复制品,这意味着这些方法可能不是问题所在。@Kakarot我在上面的代码中添加了checkElementIndex。@user3580294这非常重要。但是我有一些其他的方法,这些方法与这些方法没有联系,但是仍然有很大的时差,我无法理解。我只是读了一下,它确实很有意义。我只是下载了VisualVM,并将附加与您所说相同的内容。我相信情况会好得多。它肯定会给我一些关于我的方法和我未来项目的细节。奇怪的是,在预热或初始化相同的代码(通过Java或MyCode for LinkedList)后,代码运行得更快。事实上,这一点都不奇怪。Java有所谓的即时编译器(JIT编译器),它监视您运行的代码。如果它检测到一些“热”代码(占用大量CPU时间或频繁运行的代码),它会将Java字节码重新编译为本机代码。与Java字节码相比,这几乎总是导致加速。预热期背后的原因是让JVM重新编译您想要测试的所有代码,从基准测试中删除JIT何时激活的因素。我想我应该记住这一点,我将在未来的项目中尝试使用handy特性。我将看看我的代码是否会加快速度:-/。如果性能是您需要的,那么探查器是非常宝贵的