我从一个矩形开始,从中我需要能够调整形状。 (这是bin packing)。
为此,我想使用双向链表,因为描述算法的文章也使用了双向链表。
这将允许我从一个正方形转到此例如:
从给定的向量中,我还需要能够识别北向和东向的点:
我想知道,LinkedList的Java实现对此有利吗? 我怀疑是因为:
没有insertBefore和insertAfter方法与wikipedia explanation一样,这些方法似乎已用完。
无法从某一点开始遍历。这看起来相当重要的原因如果我想在给定向量的边缘向上找到该点,我必须从头开始迭代?
我有一些疑问,但我很难解释。如果我很容易解释那么我可能不会在第一时间问它。
答案 0 :(得分:2)
LinkedList在大多数情况下是列表实现的最差选择,因为它非常慢。 您最有可能想要使用由数组支持的ArrayList(http://docs.oracle.com/javase/7/docs/api/java/util/ArrayList.html)。
这要快得多。
指向1。 你可以使用
list.add(int index, E element);
在给定索引之前/之后插入。要在元素之前/之后插入,请使用
list.indexOf(Object o)
获取该元素的索引。
指向第2点。 这是链接列表特有的。由于数组列表由数组支持,因此您可以开始遍历"没有时间"。
list.get(int index)
答案 1 :(得分:2)
您的问题中有很多要点,我将尝试解决所有问题:
列出实施
Java实际上有许多List
接口的实现。为您的用例选择正确的实现非常重要。一些列表实现。一些List
实现还实现了Deque
或Queue
或RandomAccess
等接口,并提供了额外有用的方法。
如果列表的预期长度很大,那么选择具有适合您的使用模式的性能特征的实现也很重要。一些实现更好地处理随机读取,随机插入等...如果您的列表很小,您可能不会注意到任何性能差异。
最常见的实现是:
的ArrayList
列表中的所有元素都放在一个支持数组中。这很好,因为它提供了对元素的快速随机读取访问。复杂度ArrayList::get(index)
是O(1)(不取决于列表的大小)。在两个方向上迭代也很快。
然而,ArrayList
具有非常糟糕的随机插入/删除性能。在列表末尾添加或删除元素是一个快速的O(1)操作,但是插入或删除列表中的任何其他位置的O(n)要慢得多,因为插入点后面的数组中的所有元素都必须向右/向左移动。 ArrayList
的最坏情况是修改列表的开头。
使用Iterator
进行迭代时逐个删除元素非常糟糕:O(m * n)其中n是列表的长度,m是要删除的元素数。
链表
java LinkedList
实际上是一个双向链表。它具有糟糕的随机访问性能O(n),但迭代速度很快。在列表的头部或尾部添加或删除项目是非常快的O(1),但是在列表中间的随机位置添加元素是O(n),因为实现必须首先遵循所有链接到在插入之前找到插入点。如果要在一个小的随机范围内插入许多元素,则可以在sublist()
上获得很多性能,因此需要遵循的链接数量将减少到子列表。
使用Iterator
进行迭代时逐个删除元素是o(m)其中m是要删除的元素数(请注意,列表的长度不是因素。
insertBefore,insertAfter
您链接的维基百科页面上描述的这些操作实际上是任何链接列表内部的操作,通常不是列表的公共API的一部分。如您所见,这些操作是使用Node
实例描述的,这些实例是典型链表的内部实现细节。
在Java中,您可以使用add()
或addAll()
的各种风格,并将其与indexOf()
或sublist()
结合使用,以获得相同的结果和性能特征。
从任意点迭代
在这两种情况下,从代码的角度来看,从任意点开始迭代列表是微不足道的。您可以使用listIterator()
方法获取可以从任何方向的特定点迭代的迭代器。
您还可以使用sublist(start, end)
方法,该方法返回一个新的List
实例,该实例是基础列表中的视图(即:如果您修改subList()
返回的列表,则实际上修改了原始列表)。因此,要迭代元素2-5,只需执行myList.sublist(2, 6).forEach(el -> doSomething(el))
答案 2 :(得分:1)
仅仅因为您将对象存储在一个结构中并不会阻止您维护其他包含对象的结构。
对于向后和向前遍历,我可能会使用ArrayList来实现RandomAccess。
为了搜索与水平/垂直线相交的线段,我可能会使用两个IntervalTree。