我在下面有这个代码,我将一个新的整数插入到一个有序的LinkedList中,但我不认为这是“正确”的做事方式,因为我知道有单一的链表和指向下一个值的指针带有指向下一个和上一个值的指针的双向链表。我尝试使用Nodes来实现以下情况,但Java正在导入这个导入org.w3c.dom.Node(文档对象模型),所以卡住了。
插入案例
如果值小于/大于LL中的某些值,则可以介于
之间import java.util.*;
public class MainLinkedList {
public static void main(String[] args) {
LinkedList<Integer> llist = new LinkedList<Integer>();
llist.add(10);
llist.add(30);
llist.add(50);
llist.add(60);
llist.add(90);
llist.add(1000);
System.out.println("Old LinkedList " + llist);
//WHat if you want to insert 70 in a sorted LinkedList
LinkedList<Integer> newllist = insertSortedLL(llist, 70);
System.out.println("New LinkedList " + newllist);
}
public static LinkedList<Integer> insertSortedLL(LinkedList<Integer> llist, int value){
llist.add(value);
Collections.sort(llist);
return llist;
}
}
答案 0 :(得分:18)
如果我们使用listIterator,那么get的复杂性将是O(1)。
public class OrderedList<T extends Comparable<T>> extends LinkedList<T> {
private static final long serialVersionUID = 1L;
public boolean orderedAdd(T element) {
ListIterator<T> itr = listIterator();
while(true) {
if (itr.hasNext() == false) {
itr.add(element);
return(true);
}
T elementInList = itr.next();
if (elementInList.compareTo(element) > 0) {
itr.previous();
itr.add(element);
System.out.println("Adding");
return(true);
}
}
}
}
答案 1 :(得分:6)
这可能完全符合您的目的:
使用此代码:
import java.util.*;
public class MainLinkedList {
private static LinkedList<Integer> llist;
public static void main(String[] args) {
llist = new LinkedList<Integer>();
addValue(60);
addValue(30);
addValue(10);
addValue(-5);
addValue(1000);
addValue(50);
addValue(60);
addValue(90);
addValue(1000);
addValue(0);
addValue(100);
addValue(-1000);
System.out.println("Linked List is: " + llist);
}
private static void addValue(int val) {
if (llist.size() == 0) {
llist.add(val);
} else if (llist.get(0) > val) {
llist.add(0, val);
} else if (llist.get(llist.size() - 1) < val) {
llist.add(llist.size(), val);
} else {
int i = 0;
while (llist.get(i) < val) {
i++;
}
llist.add(i, val);
}
}
}
这一方法将以排序的方式管理List中的插入,而不使用Collections.sort(list)
答案 2 :(得分:1)
@Atrakeur
“每次添加新元素时对所有列表进行排序都不高效”
这是真的,但如果您需要列表始终处于已排序状态,那么它实际上是唯一的选择。
“最好的方法是将元素直接插入到必要的位置(在正确的位置)。为此,您可以循环所有位置以查找此数字所属的位置”
这正是示例代码所做的。
“或使用Collections.binarySearch让这个高度优化的搜索算法为您完成这项工作”
二进制搜索很有效,但仅适用于随机访问列表。因此,您可以使用数组列表而不是链接列表,但随着列表的增长,您必须处理内存副本。如果列表的容量高于实际的元素数(这很常见),你也会消耗比你需要的更多的内存。
因此,采用哪种数据结构/方法将在很大程度上取决于您的存储和访问要求。
[编辑] 实际上,示例代码存在一个问题:它在循环时导致列表的多次扫描。
int i = 0;
while (llist.get(i) < val) {
i++;
}
llist.add(i, val);
对get(i)的调用将遍历列表一次以到达第i个位置。然后对add(i,val)的调用再次遍历它。所以这将非常缓慢。
更好的方法是使用ListIterator遍历列表并执行插入。此接口定义了一个add()方法,可用于在当前位置插入元素。
答案 3 :(得分:1)
查看com.google.common.collect.TreeMultiset。
这实际上是一个排序集,允许多个具有相同值的实例。
对于您要做的事情,这是一个很好的妥协。插入比ArrayList便宜,但您仍然可以获得二进制/树搜索的搜索优势。
答案 4 :(得分:0)
您必须通过了解订单标准来找到插入数据的位置。
简单的方法是强制搜索插入位置(通过列表,二进制搜索......)。
如果您知道数据的性质,另一种方法是估计插入位置以减少检查次数。例如,如果您插入'Zorro'并且列表按字母顺序排列,您应该从列表的后面开始...或估计您的信件可能在哪里(可能在结尾)。 如果您知道它们的来源以及它们的分布方式,这也适用于数字。 这称为插值搜索:http://en.wikipedia.org/wiki/Interpolation_search
还要考虑批量插入: 如果您快速插入大量数据,您可以考虑一次性进行多次插入,之后只进行一次排序。
答案 5 :(得分:0)
链接列表不是SortedList
的更好实现此外,每次添加新元素时对所有列表进行排序效率不高。 最好的方法是将元素直接插入到必要的位置(在正确的位置)。 为此,您可以循环所有位置以查找此数字所属的位置,然后插入它,或使用Collections.binarySearch让这个高度优化的搜索算法为您完成此任务。
如果在列表中找到对象,BinarySearch将返回对象的索引(如果需要,可以在此处检查重复项)或( - (插入点) - 1)如果对象未在列表中已全部(并且插入点是需要放置对象以维护顺序的索引)
答案 6 :(得分:0)
您可以简单地在log(N)时间复杂度中执行此操作。无需遍历所有值。您可以使用二进制搜索将值添加到已排序的链接列表。只需在该函数的上限位置添加值。 检查代码......你可能会更好理解。
public static int ubound(LinkedList<Integer> ln, int x) {
int l = 0;
int h = ln.size();
while (l < h) {
int mid = (l + h) / 2;
if (ln.get(mid) <= x) l = mid + 1;
else h = mid;
}
return l;
}
public void solve()
{
LinkedList<Integer> ln = new LinkedList<>();
ln.add(4);
ln.add(6);
ln.add(ubound(ln, 5), 5);
out.println(ln);
}
输出:[4,5,6]
您可以在https://www.topcoder.com/community/data-science/data-science-tutorials/binary-search/
了解二进制搜索