如何使用下一个和上一个节点引用有效地对节点列表进行排序?

时间:2011-07-22 14:21:47

标签: c# algorithm sorting language-agnostic

我在 random 中有一组项目,每个项目都有以下数据结构:

// NOTE: Was "Vertex" in the comments...
public class Item
{
    public string Data { get; set; }
}

public class Node
{
    public Item Next { get; set; }
    public Item Previous { get; set; }
}

示例:

var a = new Item();
var b = new Item();
var c = new Item();
var d = new Item();

var nodeA = new Node() { Previous = null };
var nodeB = new Node() { Previous = a };
nodeA.Next = b;
var nodeC = new Node() { Previous = b };
nodeB.Next = c;
var nodeD = new Node() { Previous = c, Next = null };
nodeC.Next = d;

// This would be input to the sort method (completely random order).
var items = new []{ nodeC, nodeA, nodeD, nodeB };

// Execute sort

// Result: nodeA, nodeB, nodeC, nodeD.

显然,O(n 2 )解决方案是可行的。但是,我想以小于O(n 2 )的正确顺序对它们进行排序。这可能吗?

3 个答案:

答案 0 :(得分:1)

看着它...假设你没有使用循环列表,你不能只是迭代你的随机顺序数组,直到你找到起始节点(.Previous == null的那个),然后返回节点?我的意思是,链表的一个优点是你不必存储对单独数据结构中所有节点的引用,只需将它们各自相互连接即可。 (嗯,取决于您使用的语言实现如何引用计数和垃圾收集,如果它完全执行它们。)

但基本上,除非你在操作之后立即需要访问距离起始节点一定距离的元素,我建议在遇到时立即返回起始节点然后懒洋洋地分配给适当大小的数组当你使用每个连续的节点。事实上,即使您创建一个新数组并分配给它,最坏情况下的情况也不仅仅是O(n),n是节点数吗? O(n)找到起始节点,然后另一个O(n)n遍历列表,将每个节点分配给与输入数组大小相同的数组中的相应索引。


根据您更新的问题,您可能最好实现一组临时链接列表。当您最初遍历列表时,您需要检查每个节点的NextPrevious元素,然后将NextPrevious es存储在Dictionary-esque中对象(我不确定哪种.NET对象最适合它)作为键,其中链接列表节点包含引用Node s作为值的现有Item。这样你就可以在没有任何实际排序的情况下构建链接,并最终只是遍历你的临时列表,将listnodes包装的Node分配给一个新的数组返回。

这应该优于O(n ^ 2),因为字典访问通常平均是恒定时间(尽管最坏情况渐近行为仍然是O(n)),我相信。

答案 1 :(得分:0)

Merge Sort浮现在脑海中......我认为这应该适用于此,它在O(n log n)中执行(最坏情况)。

  

合并排序通常是排序链表的最佳选择:在此   在这样的情况下,实现合并排序相对容易   它只需要Θ(1)额外空间和慢随机访问的方式   链表的性能会产生一些其他算法(例如   quicksort)表现不佳,而其他人(如heapsort)完全表现不佳   不可能的。

重新阅读你的问题之后

编辑,它再也没有多大意义了。基本上你想要排序,以便项目按列表给出的顺序排列?这在线性O(n)时间是可行的:首先你向后旅行到列表中的第一个项目(通过参考)然后你只是向前产生每个项目。或者您的Next / Previous没有引用?

答案 2 :(得分:0)

我认为合并排序可以起作用。有点像...

  merge_sort_list(list, chain_length)
  1. if chain_length > 1 then
  2.    merge_sort_list(list, chain_length/2)
  3.    middle_node = step_into_by(list, chain_length)
  4.    merge_sort_list(middle, chain_length - chain_length/2)
  5.    merge_list_halves(list, middle, chain_length)

  merge_list_halves(list, middle, chain_length)
  1. ... you get the idea