【问题标题】:Binary Search with List in c#在 C# 中使用列表进行二进制搜索
【发布时间】:2015-10-31 12:18:11
【问题描述】:

我正在使用 c# WPF 开发 Windows 应用程序。 该应用程序需要一个类如下

public class Limits
{

    public String col1
    {
        get;
        set;
    }


    public String col2
    {
        get;
        set;
    }

    public String col3
    {
        get;
        set;
    }
}

我正在使用列表来存储对象,例如:-

List myList<Limits> = new List<Limits>();

“myList”有大约 15000 个对象。

现在,我想在这个 myList 中搜索特定属性。 例如:我想找出将 col1 设置为“abc”的对象。

如何使用二分搜索解决这个问题?

【问题讨论】:

  • 使用二分查找需要列表已经排序。是吗?如果没有,为什么不使用 LINQ?
  • 如何在 LINQ 中搜索字符串?
  • 这里不需要二分查找。使用 LINQ。
  • @ChrisKnight Linq 将有时间复杂性 O(n) 二进制搜索 O(log(n))
  • @Eser,但二进制搜索需要对列表进行排序。它将根据 col1、col2 或 col3 进行排序,但不是全部...

标签: c# algorithm list binary-search


【解决方案1】:

首先,列表必须按col1 属性排序,您才能使用二分查找。

您需要一个比较 col1 属性的比较器:

public class LimitsComparer : IComparer<Limits> {

  public int Compare(Limits x, Limits y) {
    return x.col1.CompareTo(y.col1);
  }

}

然后你可以用它来做二分查找:

int index = myList.BinarySearch(new Limits { col1 = "abc" }, new LimitsComparer());

返回的索引是:

如果找到项目,则排序列表中项目的从零开始的索引; 否则,负数是 下一个大于 item 的元素的索引,或者,如果没有 较大的元素,Count 的按位补码。


您还可以使用Where 方法来获取具有该属性的对象:

List<Limits> result = myList.Where(x => x.col1 == "abc").ToList();

虽然效率不高,但您仍然应该考虑这是否是一个更好的解决方案,因为它更易于实施并且提供的结果更易于处理。此外(这可能更重要),即使列表未按col1 排序,它也可以工作。

【讨论】:

  • 列表必须在调用BinarySearch之前进行排序:List&lt;T&gt;必须已经根据比较器实现进行排序;否则结果不正确。
  • @MarcinJuraszek:是的,这就是为什么我在答案的第一段中这么说。
  • 抱歉,我不清楚。我可以想象一个BinarySearch 进行内联排序的方法,尤其是在提供比较器时。不过可能只有我一个人。
  • @MarcinJuraszek:这将违背二分搜索的目的,因为它会使其效率低于线性搜索。
【解决方案2】:

你可以使用这样的东西。

myList.Where(i => i.col1 == "abc").ToList();

【讨论】:

    【解决方案3】:

    使用将键存储在哈希表中的字典。 Linq 将轻松创建字典。

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    
    namespace ConsoleApplication41
    {
        class Program
        {
            static void Main(string[] args)
            {
                List<Limits> myList = new List<Limits>();
    
                //dictionary with unique keys
                Dictionary<string, Limits> dict1 = myList.AsEnumerable()
                    .GroupBy(x => x.col2, y => y)
                    .ToDictionary(x => x.Key, y => y.FirstOrDefault());
    
                //dictionary with keys having multiple values
                Dictionary<string, List<Limits>> dict2 = myList.AsEnumerable()
                    .GroupBy(x => x.col2, y => y)
                    .ToDictionary(x => x.Key, y => y.ToList());
    
                Limits abc = dict1["abc"];
    
            }
        }
        public class Limits
        {
            public String col1 { get; set; }
            public String col2 { get; set; }
            public String col3 { get; set; }
        }
    }
    

    【讨论】:

      【解决方案4】:

      除非您明确要使用二进制搜索,否则您应该使用您可用的标准 Linq 函数。除非您的列表已经排序,否则这可能比二进制排序更有效。

        var myList = new List<Limits> {....}
        var entry = myList.Where(l => l.col1== "abc").FirstOrDefault();
        if(entry == null)
        { // no match found }
      

      如果你真的想要二分查找,请参考Can LINQ use binary search when the collection is ordered?

      【讨论】:

      • 如果输入序列包含多个元素,则会抛出 InvalidOperationException。
      • 如果您的列表包含重复项,您可以使用 FirstOrDefault 或没有重复项的 SingleOrDefault
      猜你喜欢
      • 1970-01-01
      • 2010-10-05
      • 2021-04-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-07-06
      • 2015-07-29
      相关资源
      最近更新 更多