繁体   English   中英

C#fast除了排序列表的方法

[英]C# fast Except method for sorted list

我正在研究一个瓶颈为list1.Except(list2)的应用程序。 从这篇文章: 我应该在处理HashSet时使用Except或Contains左右,Linq的复杂性除外是O(m + n)(m和n代表列表的大小)。 但是,我的列表已排序。 这可以帮忙吗?

我能想到的第一个实现:

foreach element in list2 (m operations)
    look for it in list1 (ln(n) operations)
    if present 
        set it to null (O(1), removing has a O(n))
    else continue

它具有复杂度O(m * ln(n)),当m很小而n很大时非常有趣(这与我的数据集完全相同:m约为50,n约为1 000 000)。 然而,它产生null的事实可能对使用它的函数有很多影响...有没有办法保持这种复杂性,而不必写空(然后跟踪它们)

任何帮助将不胜感激!

如果两个列表都已排序,那么您可以轻松实现自己的解决方案:

listA算法除listB算法外,其工作原理如下:

1. Start from the beginning of both lists
2. If listA element is smaller than the listB element,
   then include the listA element in the output and advance listA
3. If listB element is smaller than the listA element, advance listB
4. If listA and listB elements are equal,
   advance both lists and do not push the element to the output

重复直到listA用尽。 请特别注意listA可能会在listA之前耗尽。

using System;
using System.Collections.Generic;

public class Test
{
    public static void Main()
    {
        var listM = new List<int>();
        var listN = new List<int>();
        for(int i = 0, x = 0; x < 50; i+=13, x++) { 
            listM.Add(i);
        }
        for(int i = 0, x = 0; x < 10000; i+=7, x++) { 
            listN.Add(i);
        }
        Console.WriteLine(SortedExcept(listM, listN).Count);
    }

    public static List<T> SortedExcept<T>(List<T> m, List<T> n) {
        var result = new List<T>();
        foreach(var itm in m) {
            var index = n.BinarySearch(itm);
            if(index < 0) { 
                result.Add(itm); 
            }
        }
        return result;
    }
}

编辑这里也是O(M + N)版本

public static List<T> SortedExcept2<T>(List<T> m, List<T> n) where T : IComparable<T> {
    var result = new List<T>();
    int i = 0, j = 0;
    if(n.Count == 0) {
        result.AddRange(m);
        return result;
    }
    while(i < m.Count) {
        if(m[i].CompareTo(n[j]) < 0) {
            result.Add(m[i]);
            i++;
        } else if(m[i].CompareTo(n[j]) > 0) {
            j++;
        } else {
            i++;
        }
        if(j >= n.Count) {
            for(; i < m.Count; i++) { 
                result.Add(m[i]); 
            }
            break;
        }
    }
    return result;
}

快速而肮脏的基准http://ideone.com/Y2oEQD即使N为1000万,M + N总是更快。 BinarySearch受到惩罚,因为它以非线性方式访问数组内存; 这会导致缓存未命中,从而减慢算法速度,因此较大的N会使用BinarySearch获得更多的内存访问权限。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM