【问题标题】:Simultaneous Sorting/Removing data from a List从列表中同时排序/删除数据
【发布时间】:2013-05-04 06:32:47
【问题描述】:

目前我有一个整数列表。此列表包含指向另一个更大列表中的“活动”对象的索引值。如果较小的“活动”值列表变得太大,它会触发循环遍历小列表并删除已变为非活动的值。目前,它通过简单地忽略不活动的值并将它们添加到第二个列表来删除它们(当第二个列表再次变满时,重复相同的过程,将它们放回第一个列表等等)。

发生此触发器后,列表将使用快速排序实现进行排序。这一切都很好。

-------问题------

但是,我看到了速度的潜在提升。我正在想象在进行排序的同时删除非活动值。不幸的是,我找不到以这种方式实现快速排序的方法。仅仅因为快速排序与枢轴一起使用,这意味着如果从列表中删除值,枢轴最终将尝试访问列表中不存在的插槽等。(除非我只是想错了) .

那么,关于如何结合这两个操作的任何想法?我似乎找不到任何可以处理这个问题的快速排序算法,或者我只是没有看到如何将它实现到快速排序中......任何提示都表示赞赏!

用于更好地了解当前情况的代码: (当前条件:值的范围可以从 0 到 200 万,没有两个值是相同的,并且通常它们大多是排序的,因为它们经常被排序)

if (deactive > 50000)//if the number of inactive coordinates is greater than 50k
{
    for (int i = 0; i < activeCoords1.Count; i++)
    {
         if (largeArray[activeCoords[i]].active == true)//if coordinate is active, readd to list
         {
             activeCoords2.Add(activeCoords1[i]);
         }
    }
    //clears the old list for future use
    activeCoords1.Clear();
    deactive = 0;
    //sorts the new list
    Quicksort(activeCoords2, 0, activeCoords2.Count() - 1);
 }    

    static void Quicksort(List<int> elements, int left, int right)
    {
        int i = left, j = right;
        int pivot = elements[(left + right) / 2];

        while (i <= j)
        {
            // p < pivot
            while (elements[i].CompareTo(pivot) < 0)
            {
                i++;
            }

            while (elements[j].CompareTo(pivot) > 0)
            {
                j--;
            }

            if (i <= j)
            {
                // Swap
                int tmp = elements[i];
                elements[i] = elements[j];
                elements[j] = tmp;

                i++;
                j--;
            }
        }

        // Recursive calls
        if (left < j)
        {
            Quicksort(elements, elements, left, j);
        }

        if (i < right)
        {
            Quicksort(elements, elements, i, right);
        }
    }

【问题讨论】:

  • 如果列表大部分是排序的,使用快速排序不是一个好主意,因为在排序列表上快速排序变成 O(n^2)。
  • 因为数字范围在0到2000000之间,所以可以使用计数排序,似乎不需要过多的合并操作。
  • 不幸的是,我相信计数排序会撤消某些连接,因为值似乎是重新生成而不是移动。我需要保持每个值引用完好无损,因为对象还需要保持它们的指针指向正确的值......它有点晦涩,但它需要保持这种状态。 ://
  • 我遗漏了一些东西 - 如果您要从中删除项目 (activeCoords1) 的列表已经排序,那么您要复制项目的列表 (activeCoords2) 也将排序因为您以与activeCoords 相同的顺序向其中添加项目。我错过了什么?
  • 另外:(1) 您的 Quicksort 示例无法编译(oldList? 是什么)和 (2) 它使用的是 List&lt;int&gt;,因此要比较的元素是 ints,但您有调用.CompareTo() 来比较它们的巨大开销——为什么不直接比较呢?哦,(3)如果你真的,真的需要让它尽可能快,你将不得不使用普通数组而不是List&lt;T&gt;...

标签: c# algorithm sorting


【解决方案1】:

听起来您可能会受益于使用red-black tree(或其他平衡二叉树),您的搜索、插入和删除时间将是 O(log n)。这棵树将始终被排序,因此不会有任何人因大命中而重新排序。

您在访问类型(搜索、插入、删除)方面的划分是什么?您的访问限制是什么?

【讨论】:

  • 目前只有一个列表,不需要搜索,我只在末尾添加值,而删除,我有两个列表设置,不需要删除。相反,它只是将值重新添加到仍然处于活动状态的相反列表中......不幸的是,我稍后将不得不接受这个。对此很抱歉,但一旦有机会了解您的树,我会尽快回复您!
  • 我指的是您列表的消费者的需求,而不是列表本身的需求。
  • 是的,这就是我要解释的大部分内容。 “消费者”只是一个从 0 移动到最大值的 for 循环,在索引处获取值。所以不需要搜索等。是这个意思吗?
  • 好的,所以你只对列表进行遍历,并且在遍历时列表必须始终是排序的。
  • 是的,它的排序主要是为了让内存调用更紧密。因此,当它遍历列表时,找到的下一个值应该是数组中最近的值。 (所以我只需要每隔几秒钟进行一次排序,但是当我这样做时,额外的速度会很有帮助。)
【解决方案2】:

我会使用List&lt;T&gt;SortedDictionary&lt;TKey, TValue&gt; 作为您的数据结构。

由于您进行排序的原因(“基于感觉的微优化”)不是一个好的原因,我会避免这样做。一个很好的理由是“它对性能有可衡量的影响”。

在那种情况下(或者你只是想这样做),我推荐一个 SortedDictionary。所有的分类工作都已经为你完成了,没有理由重新发明轮子。

如果一个合适的数据结构就足够了,就没有必要同时处理两个列表。红黑树似乎很合适,并且显然在 SortedDictionary according to this

中使用

【讨论】:

  • 我认为您的意思是 SortList?尽管如此,我还是在处理两个列表,否则我将无法快速删除数据。无需删除一条数据,等待列表“将所有内容下移”,然后重复,我可以简单地取我需要的内容,本质上“下移所有内容”过程只需完成一次。
  • 另外,如果按顺序跳转到 200 万个内存空间,它们总是会更快。在以前的测试中,我节省了一半以上的时间,所以这很可能是值得的,并且在需要时将它们按顺序排列还可以提供更好的操作水平(例如,如果从最低到最高更新成为问题)。
  • 好的,在这种情况下使用排序的数据结构。 SortedList 和 SortedDictionary 用途相似,但性能不同。使用前者,您可以获得更快的操作(在 O(log n) 中添加/删除),而后者使用更少的内存但具有 O(n) 操作。 (geekswithblogs.net/BlackRabbitCoder/archive/2011/06/16/…)
猜你喜欢
  • 2018-01-10
  • 1970-01-01
  • 2016-01-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-05-05
  • 1970-01-01
相关资源
最近更新 更多