使用归并排序对双向链表进行排序
我在互联网上找到了这段代码,它是用于数组的,我想将其更改为双向链表(我们应该使用指针而不是索引),请您帮助我如何更改合并方法(我已经更改了排序方法)我自己)这也不是我的家庭作业,我喜欢使用链表!
public class MergeSort {
private DoublyLinkedList LocalDoublyLinkedList;
public MergeSort(DoublyLinkedList list) {
LocalDoublyLinkedList = list;
}
public void sort() {
if (LocalDoublyLinkedList.size() <= 1) {
return;
}
DoublyLinkedList listOne = new DoublyLinkedList();
DoublyLinkedList listTwo = new DoublyLinkedList();
for (int x = 0; x < (LocalDoublyLinkedList.size() / 2); x++) {
listOne.add(x, LocalDoublyLinkedList.getValue(x));
}
for (int x = (LocalDoublyLinkedList.size() / 2) + 1; x < LocalDoublyLinkedList.size`(); x++) {`
listTwo.add(x, LocalDoublyLinkedList.getValue(x));
}
//Split the DoublyLinkedList again
MergeSort sort1 = new MergeSort(listOne);
MergeSort sort2 = new MergeSort(listTwo);
sort1.sort();
sort2.sort();
merge(listOne, listTwo);
}
private void merge(DoublyLinkedList a, DoublyLinkedList b) {
int x = 0;
int y = 0;
int z = 0;
while (x < first.length && y < second.length) {
if (first[x] < second[y]) {
a[z] = first[x];
x++;
} else {
a[z] = second[y];
y++;
}
z++;
}
//copy remaining elements to the tail of a[];
for (int i = x; i < first.length; i++) {
a[z] = first[i];
z++;
}
for (int i = y; i < second.length; i++) {
a[z] = second[i];
z++;
}
}
}
I have found this code in the internet and it was for arrays ,I want to change it for doubly linked list(instead of index we should use pointer) would you please help me that how can i change merge method(I have changed sort method by myself) also this is not my home work ,I love working with linked list!!
public class MergeSort {
private DoublyLinkedList LocalDoublyLinkedList;
public MergeSort(DoublyLinkedList list) {
LocalDoublyLinkedList = list;
}
public void sort() {
if (LocalDoublyLinkedList.size() <= 1) {
return;
}
DoublyLinkedList listOne = new DoublyLinkedList();
DoublyLinkedList listTwo = new DoublyLinkedList();
for (int x = 0; x < (LocalDoublyLinkedList.size() / 2); x++) {
listOne.add(x, LocalDoublyLinkedList.getValue(x));
}
for (int x = (LocalDoublyLinkedList.size() / 2) + 1; x < LocalDoublyLinkedList.size`(); x++) {`
listTwo.add(x, LocalDoublyLinkedList.getValue(x));
}
//Split the DoublyLinkedList again
MergeSort sort1 = new MergeSort(listOne);
MergeSort sort2 = new MergeSort(listTwo);
sort1.sort();
sort2.sort();
merge(listOne, listTwo);
}
private void merge(DoublyLinkedList a, DoublyLinkedList b) {
int x = 0;
int y = 0;
int z = 0;
while (x < first.length && y < second.length) {
if (first[x] < second[y]) {
a[z] = first[x];
x++;
} else {
a[z] = second[y];
y++;
}
z++;
}
//copy remaining elements to the tail of a[];
for (int i = x; i < first.length; i++) {
a[z] = first[i];
z++;
}
for (int i = y; i < second.length; i++) {
a[z] = second[i];
z++;
}
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
合并排序需要经常拆分列表。迭代到 LinkedList 的中间不是可以对其执行的最昂贵的操作(好吧,除了排序之外)?我可以看到合并步骤运行得很好(您正在两个链接列表上向前迭代),但我不确定这个实现在没有 O(1) 拆分操作的情况下是否值得。
后续
正如我所指出的,当您在合并期间已经执行了 O(n) 操作时,O(n) 拆分操作并不会真正增加太多复杂性阶段。尽管如此,您仍然会遇到像您正在做的迭代那样的麻烦(不使用
Iterator
而是在List
上使用get
> 随机访问特性较差)。我在调试其他一些问题时感到无聊,所以给你写了我认为是该算法的一个不错的 Java 实现。我逐字遵循维基百科的伪代码,并加入了一些泛型和打印语句。如果您有任何问题或疑虑,请尽管询问。
运行 将
MergeSort.java
javac MergeSort.java
java MergeSort
javadoc -private MergeSort.java
来创建文档。打开它创建的index.html 文件。Merge sort requires splitting the list quite often. Isn't iterating to the middle of a LinkedList pretty much the most expensive operation you can perform on it (well, short of sorting it)? I could see the merge step working pretty well (you're iterating forwards over two linked lists), but I'm not sure that this implementation is worth the trouble without an O(1) split operation.
Followup
As pointed out to me, the O(n) split operation doesn't really add much to complexity when you're already doing O(n) things during the merge phase. Nevertheless, you're still going to run into trouble doing iteration like you're doing (not using an
Iterator
but instead usingget
on aList
with poor random-access characteristics).I was bored while debugging some other issue so wrote you what I consider to be a decent Java implementation of this algorithm. I followed Wikipedia's pseudocode verbatim and sprinkled in some generics and print statements. If you have any questions or concerns, just ask.
To Run
MergeSort.java
javac MergeSort.java
java MergeSort
javadoc -private MergeSort.java
to create the documentation. Open the index.html file it creates.这取决于
DoublyLinkedList
是什么 - 它是具体的用户定义类型,还是只是链接列表类型的别名?在第一种情况下,您应该在其中定义索引 get/set 方法和/或迭代器,这使任务变得简单。
在后一种情况下,为什么不使用标准
java.util.LinkedList
?就
List
接口而言,操作可以这样实现:这种实现比数组更乏味,主要是因为迭代器被
next< /code> 操作,因此必须记录每个列表中的当前项目。使用
get
,代码会更简单,与数组解决方案非常相似,但对于大列表来说,速度会慢得多,正如 @sepp2k 指出的那样。还有一些注意事项:
localDoublyLinkedList
It depends on what
DoublyLinkedList
is - is it a concrete user-defined type, or just an alias name for a linked list type?In the first case, you should have indexed get/set methods and/or an iterator defined in it, which make the task simple.
In the latter case, why not use the standard
java.util.LinkedList
?In terms of the
List
interface, the operation could be implemented like this:This implementation is a bit more tedious than it would be with arrays, mostly since iterators are "consumed" by the
next
operation, so one must keep account of the current item in each list. Withget
, the code would be simpler, quite similar to the array solution, however it would be way slower for big lists, as @sepp2k pointed out.A couple more notes:
localDoublyLinkedList
我昨天遇到了这个问题。以下是一些想法。
对
DoublyLinkedList
进行排序与对Array
进行排序不同,因为您无法对列表中的任意项目进行基于索引的引用。相反,您需要记住每个递归步骤中的项目,然后将它们传递给合并函数。对于每个递归步骤,您只需要记住每个列表一半的第一项。如果您不记得这些项目,您很快就会得到索引,但这会导致您遇到一个问题,在您的merge
函数中,您需要使用for
-循环查找要合并的项目。这反过来意味着您的复杂度为O(n^2)
。另一个重要的点是递归到列表并将列表分成两半的步骤。您可以使用
for
循环在递归部分中执行此步骤。与此步骤中的merge
部分相反,for
循环只会产生O(log(n) * n/2)
这仍然低于总体O(n*log(n))
复杂度。原因如下:您总是需要找到列表部分每一半的第一项。
在第一个递归步骤中,您需要传递
first
项和位置n/2
处的项。这需要n/2
步骤才能找到。在接下来的每个步骤中,您需要找到列表两半中每一个的中间项,这让我们
n/4
找到前半部分中的项,并且n/ 4 在另一半中。总共是
n/2
。在以下每个递归步骤中,列表部分的数量加倍,长度除以二:
4 * n/8
在第三个递归深度8 * n/16
在第四个递归深度,依此类推...递归深度为
log(n)
,在每一步中我们执行n/2< /代码> 步骤。这等于
O(log(n)*n/2)
最后是一些代码:
mergeSort:
和 merge:
使用的最大内存量也相当低(不包括列表本身)。如果我错了请纠正我,但它应该小于 400 字节(在 32 位上)。每次调用 mergeSort 需要 12 字节乘以 log(n) 的递归深度加上合并变量的 20 字节,因此:12*log(n)+20 字节。
PS Code 对 100 万个项目进行了测试(需要 1200 毫秒)。另外,
DoublyLinkedList
是一个存储列表的第一个ListElement
的容器。更新:
我已经使用相同的数据结构回答了关于 Quicksort 的类似问题,然而,与此合并排序实现相比,它的运行速度要慢得多。以下是一些更新的时间供参考:
合并排序:
快速排序:
请注意,时间特定于我的硬件,您可能会得到不同的结果。
I came across this problem yesterday. Here are some thoughts.
Sorting a
DoublyLinkedList
is different from sorting anArray
as you can not make index based references to any arbitrary item in the List. Instead you need to remember the items during each recursive step and then pass them on to the merge function. For each recursion step you only need to remember the first item of each list half. If you do not remember these items you will quickly end up with indexes, but this leads you to the problem that in yourmerge
-function you need to traverse the whole list withfor
-loops to find the items to merge. That in turn means you get a complexity ofO(n^2)
.Another important point is the step of recursing into the list and dividing the list in two halves. You can do this step in the recursive part by using
for
-loops. Contrary to themerge
-part at this step thefor
-loops will only yield a complexity ofO(log(n) * n/2)
and this is still below the overallO(n*log(n))
complexity. Here is why:You always need to find the first item of each half of list part.
In the first recursion step you need to pass the
first
item and the item at positionn/2
. This takesn/2
steps to find.In each following step you need to find the middle item for each of the two halves of the list which gives us
n/4
to find the item in the first halve andn/4
in the other halve. In total thatsn/2
.In each following recursive step the amount of list parts double and the lengths is divided by two:
4 * n/8
in the 3rd recursion depth8 * n/16
in the 4th recursion depth, and so on...The recursion depth is
log(n)
and in each step we performn/2
steps. This equalsO(log(n)*n/2)
Finally here is some code:
mergeSort:
and merge:
The maximum amount of memory used is also pretty low (not including the list itself). Correct me if I'm wrong but it should be less than 400 bytes (on 32bit). It would be 12 byte per call on mergeSort times the recursion depth of log(n) plus 20 bytes for the variables of merge thus: 12*log(n)+20 bytes.
P.S. Code tested on 1 million items (takes 1200ms). Also
DoublyLinkedList
is a container that stores the firstListElement
of the list.Update:
I have answered a similar question about Quicksort using the same data structures, however in comparison to this Mergesort implementation it runs much slower. Here are some updated timings for reference:
Mergesort:
Quicksort:
Note the timings are specific to my hardware and you might get different results.
首先,在处理链表时一定不能使用索引。这样做:
对于合并
这样它仍然是 O(n log n)
First of all, you must NOT use indexes when dealing with linked lists. Do it like this:
And for merging
This way it will still be O(n log n)
另一个想法是创建一个包含列表中所有元素的数组,对数组进行排序,然后再次将元素插入到列表中。
优点:实现起来非常简单,如果列表合并排序的实现不佳,速度会更快(也许也比好的实现更快)
缺点:使用一些额外的空间(O(n))
Another idea is to create an array with all the elements of the list, sort the array and then insert the elements to the list again.
Pro: very simple to implement, faster if poor implementation of list mergesort (maybe also faster than good implementations)
Contra: uses some extra space (O(n))