C# 排序子序列的最有效排序算法

C# 排序子序列的最有效排序算法,c#,algorithm,sorting,quicksort,mergesort,C#,Algorithm,Sorting,Quicksort,Mergesort,我有几个按长升序排序的数字序列,希望生成一个主序列,其中包含相同顺序的所有元素。我寻找最有效的排序算法来解决这个问题。我的目标是C、.NET4.0,因此也欢迎针对并行性的想法 以下是一个例子: s1=1,2,3,5,7,13 s2=2,3,6 s3=4,5,6,7,8 结果序列=1,2,2,3,3,4,5,5,6,6,7,7,8,13 编辑:当有两个或多个相同的值时,这两个或多个值的顺序无关紧要。只需合并序列即可。您不必再次对它们进行排序。只需合并序列即可。您不必再次对它们进行排序。您只需像合并

我有几个按长升序排序的数字序列,希望生成一个主序列,其中包含相同顺序的所有元素。我寻找最有效的排序算法来解决这个问题。我的目标是C、.NET4.0,因此也欢迎针对并行性的想法

以下是一个例子: s1=1,2,3,5,7,13 s2=2,3,6 s3=4,5,6,7,8 结果序列=1,2,2,3,3,4,5,5,6,6,7,7,8,13


编辑:当有两个或多个相同的值时,这两个或多个值的顺序无关紧要。

只需合并序列即可。您不必再次对它们进行排序。

只需合并序列即可。您不必再次对它们进行排序。

您只需像合并排序一样合并序列

这是可并行的:

在1/2中合并序列1和2,在3/4中合并序列3和4… 将序列1/2和3/4合并到1/2/3/4,5/6和7/8合并到5/6/7/8… … 以下是合并函数:

int j = 0;
int k = 0;
for(int i = 0; i < size_merged_seq; i++)
{
  if (j < size_seq1 && seq1[j] < seq2[k])
  {
    merged_seq[i] = seq1[j];
    j++;
  }
  else
  {
    merged_seq[i] = seq2[k];
    k++;
  }
}

你只需要像合并排序那样合并序列

这是可并行的:

在1/2中合并序列1和2,在3/4中合并序列3和4… 将序列1/2和3/4合并到1/2/3/4,5/6和7/8合并到5/6/7/8… … 以下是合并函数:

int j = 0;
int k = 0;
for(int i = 0; i < size_merged_seq; i++)
{
  if (j < size_seq1 && seq1[j] < seq2[k])
  {
    merged_seq[i] = seq1[j];
    j++;
  }
  else
  {
    merged_seq[i] = seq2[k];
    k++;
  }
}

据我所知,没有.NETFramework方法可以进行K-way合并。通常,它是通过优先级队列(通常是堆)完成的。这不难做到,而且效率很高。给定K个已排序的列表,共包含N个项,复杂性在日志K上


我在文章中展示了一个简单的二进制堆类。在中,我介绍了如何创建多个已排序的子文件,并使用堆执行K-way合并。给你一个小时的学习时间,你也许可以在你的程序中使用它。

据我所知,没有.NET Framework方法可以进行K-way合并。通常,它是通过优先级队列(通常是堆)完成的。这不难做到,而且效率很高。给定K个已排序的列表,共包含N个项,复杂性在日志K上


我在文章中展示了一个简单的二进制堆类。在中,我介绍了如何创建多个已排序的子文件,并使用堆执行K-way合并。给你一个小时的学习时间,你也许可以在你的程序中使用它。

简单的方法是将它们一个接一个地合并。然而,这将需要*k^2时间,其中k是序列的数量,n是序列中项目的平均数量。然而,使用分而治之的方法,您可以将此时间降低到*k*log k。算法如下:

将k个序列分成k/2组,每个组有2个元素,如果k为奇数,则每个组有1个元素。 合并每组中的序列。因此,您将获得k/2个新组。 重复,直到得到一个序列。
简单的方法是将它们逐一合并。然而,这将需要*k^2时间,其中k是序列的数量,n是序列中项目的平均数量。然而,使用分而治之的方法,您可以将此时间降低到*k*log k。算法如下:

将k个序列分成k/2组,每个组有2个元素,如果k为奇数,则每个组有1个元素。 合并每组中的序列。因此,您将获得k/2个新组。 重复,直到得到一个序列。 更新:

事实证明,所有的算法。。。通过简单的方法,速度更快:

private static List<T> MergeSorted<T>(IEnumerable<IEnumerable<T>> sortedBunches)
{
    var list = sortedBunches.SelectMany(bunch => bunch).ToList();

    list.Sort();

    return list;
}
为了遗产的目的

以下是按优先级排列的最终版本:

    private static IEnumerable<T> MergeSorted<T>(IEnumerable<IEnumerable<T>> sortedInts) where T : IComparable<T>
    {
        var enumerators = new List<IEnumerator<T>>(sortedInts.Select(ints => ints.GetEnumerator()).Where(e => e.MoveNext()));

        enumerators.Sort((e1, e2) => e1.Current.CompareTo(e2.Current));

        while (enumerators.Count > 1)
        {
            yield return enumerators[0].Current;

            if (enumerators[0].MoveNext())
            {
                if (enumerators[0].Current.CompareTo(enumerators[1].Current) == 1)
                {
                    var tmp = enumerators[0];
                    enumerators[0] = enumerators[1];
                    enumerators[1] = tmp;
                }
            }
            else
            {
                enumerators.RemoveAt(0);
            }
        }

        do
        {
            yield return enumerators[0].Current;
        } while (enumerators[0].MoveNext());
    }
更新:

事实证明,所有的算法。。。通过简单的方法,速度更快:

private static List<T> MergeSorted<T>(IEnumerable<IEnumerable<T>> sortedBunches)
{
    var list = sortedBunches.SelectMany(bunch => bunch).ToList();

    list.Sort();

    return list;
}
为了遗产的目的

以下是按优先级排列的最终版本:

    private static IEnumerable<T> MergeSorted<T>(IEnumerable<IEnumerable<T>> sortedInts) where T : IComparable<T>
    {
        var enumerators = new List<IEnumerator<T>>(sortedInts.Select(ints => ints.GetEnumerator()).Where(e => e.MoveNext()));

        enumerators.Sort((e1, e2) => e1.Current.CompareTo(e2.Current));

        while (enumerators.Count > 1)
        {
            yield return enumerators[0].Current;

            if (enumerators[0].MoveNext())
            {
                if (enumerators[0].Current.CompareTo(enumerators[1].Current) == 1)
                {
                    var tmp = enumerators[0];
                    enumerators[0] = enumerators[1];
                    enumerators[1] = tmp;
                }
            }
            else
            {
                enumerators.RemoveAt(0);
            }
        }

        do
        {
            yield return enumerators[0].Current;
        } while (enumerators[0].MoveNext());
    }

节省时间?节省空间?其他一些效率参数?时间效率还是空间效率?你可以使用一个简单的for循环在复杂性上实现两个子的合并。Lol,似乎不像早期评论者所暗示的那样是一个微不足道的问题,因为出现了4个完全相反的答案@Freddy刚刚认为值得一提,有一些通用排序算法确实考虑到了这一点,例如Java和Python默认排序算法,但没有.NET。如果你感兴趣的话,你可以在维基百科上查找TimSort,但这对你来说可能太过分了,因为你已经确定了已排序的子集。节省时间?节省空间?其他一些效率参数?时间效率还是空间效率?你可以使用一个简单的for循环在复杂性上实现两个子的合并。Lol,似乎不像早期评论者所暗示的那样是一个微不足道的问题,因为出现了4个完全相反的答案@Freddy刚刚认为值得一提,有一些通用排序算法确实考虑到了这一点,例如Java和Python默认排序算法,但没有.NET。如果你感兴趣的话,你可以在维基百科上查找TimSort,但这对你来说可能太过分了,因为你已经确定了已排序的子集。如果他按原样合并它们,他将得到1,2,3,5,7,

13,2,3,6,4,5,6,7,8肯定吗?为什么不将3个单独排序,然后尝试合并它们,将所有3个按任意顺序粘在一起,然后只对最后一个长的排序一次呢?这取决于合并算法。@RhysW:n向合并与追加不同。@RhysW您给出的数字将是对序列进行合并的结果,不合并它们。@RhysW您所描述的称为追加。Google Mergesort对合并的定义进行了排序。如果他按原样合并它们,他肯定会得到1,2,3,5,7,13,2,3,6,4,5,6,7,8?为什么不将3个单独排序,然后尝试合并它们,将所有3个按任意顺序粘在一起,然后只对最后一个长的排序一次呢?这取决于合并算法。@RhysW:n向合并与追加不同。@RhysW您给出的数字将是对序列进行合并的结果,不合并它们。@RhysW您所描述的称为追加。Google Mergesort获取合并的定义。当您到达任意一个输入序列的末尾时,您需要添加剩余内容。@Thomash,感谢您的输入,我实现了一个非常类似的东西,尽管更通用于处理n序列。当您到达任意一个输入序列的末尾时,您需要添加剩余内容。@Thomash,感谢您的输入,我实现了一个非常类似的东西,尽管它更通用于处理n序列。如果你使用优先级队列和K路合并算法,它会出现在日志K上。@JimMischel:是的!我刚注意到你的回答,投了赞成票!如果您使用优先级队列和K路合并算法,它会记录在日志K上。@JimMischel:是的!我刚注意到你的回答,投了赞成票!这听起来很有趣,一定要看看,谢谢你的提示和链接。Jim,谢谢你的宝贵意见,我用优先级队列实现了一个k路合并,它执行得非常好。我不得不将另一个提议的解决方案标记为答案,因为它提供了相应的代码。但我一直在阅读你的文章,并从中获得很多价值,因为我不在这个领域工作,因此我为使用的术语不正确表示歉意。这听起来很有趣,一定会看一看,谢谢你的提示和链接。Jim,谢谢你的宝贵意见,我用优先级队列实现了一个k路合并,它执行得非常好。我不得不将另一个提议的解决方案标记为答案,因为它提供了相应的代码。但我一直在阅读你的文章,并从中获得了很多价值,因为我不在这个领域工作,因此我为使用的术语不正确表示歉意。谢谢你的代码,我尝试了它,但它没有按预期工作。我用一个数组测试它,该数组由两个long类型的数组组成,每个数组包含数十万个值。它似乎被困在一个无限循环中,或者对于少量序列(但每个序列有许多元素)来说效率极低……或者……可能存在错误?请粘贴您使用的数组好吗?对于数十万个元素来说几乎不可能,但这里有一个小子集:634398912001540000 634398912002130000634398912003100000 634398912003120000 634398912003120000 634398912003120000 634398912003130000您希望它们如何合并?这是一个简单的长排序数组。要合并数字吗?什么?我希望long类型的值按升序排序。每个序列都包含long类型的类似值。正如你所看到的,我粘贴的样本是按严格升序排列的long类型的值。我不确定你在问什么,因为我认为这很清楚。你能解释一下什么是不清楚的吗?谢谢你的代码,我试过了,但没有达到预期效果。我用一个数组测试它,该数组由两个long类型的数组组成,每个数组包含数十万个值。它似乎被困在一个无限循环中,或者对于少量序列(但每个序列有许多元素)来说效率极低……或者……可能存在错误?请粘贴您使用的数组好吗?对于数十万个元素来说几乎不可能,但这里有一个小子集:634398912001540000 634398912002130000634398912003100000 634398912003120000 634398912003120000 634398912003120000 634398912003130000您希望它们如何合并?这是一个简单的长排序数组。要合并数字吗?什么?我希望long类型的值按升序排序。每个序列都包含long类型的类似值。正如你所看到的,我粘贴的样本是按严格升序排列的long类型的值。我不确定你在问什么,因为我认为这很清楚。你能解释一下什么不清楚吗?