简体   繁体   English

SortedList键的二分查找<k, v></k,>

[英]Binary Search on Keys of SortedList<K, V>

I need to write some code for linear interpolation and I am trying to figure out the most efficient way to search the Keys of a SortedList<K, V> for the upper and lower keys that surround my target key.我需要为线性插值编写一些代码,并且我试图找出最有效的方法来搜索SortedList<K, V>的键以查找围绕我的目标键的上下键。

SortedList<int, double> xyTable = new SortedList<int, double>()
{
    {1, 10}, {2, 20}, {3, 30}, {4,40}
};

double targetX = 3.5;

What is the most efficient way to search the list and determine that 3.5 is between 3 and 4?搜索列表并确定 3.5 在 3 和 4 之间的最有效方法是什么? I have a method / cheat that works for integers (temporarily insert the target Key into the list then find the index) but I figured I'd ask the pros so I could produce quality code.我有一个适用于整数的方法/作弊(暂时将目标键插入列表然后找到索引),但我想我会问专业人士,这样我就可以生成高质量的代码。

Thanks.谢谢。

A binary search gives you decent performance on a list.二进制搜索可以在列表上为您提供不错的性能。 However the Keys property on SortedList is of type IList , whereas BinarySearch is defined on List .但是SortedList上的 Keys 属性是IList类型,而BinarySearch是在List上定义的。 Fortunately, you can find an implementation of binary search for IList in this related question:幸运的是,您可以在这个相关问题中找到IList的二进制搜索实现:

How to perform a binary search on IList<T>? 如何对 IList<T> 执行二进制搜索?

In my case the source SortedList is not changing much, since its being used as a lookup table.在我的情况下,源SortedList没有太大变化,因为它被用作查找表。 So in this case it makes sense to convert the SortedList to a List<T> once.所以在这种情况下,将SortedListList<T>一次是有意义的。 After that it is quite easy to use the built-in BinarySearch method of List<T> ...之后使用List<T>的内置 BinarySearch 方法就很容易了...

double targetX = 3.5;

// Assume keys are doubles, may need to convert to doubles if required here.
// The below line should only be performed sparingly as it is an O(n) operation.
// In my case I only do this once, as the list is unchanging.
List<double> keys = xyTable.Keys.ToList();

int ipos = keys.BinarySearch(targetX);

if (ipos >= 0)
{
    // exact target found at position "ipos"
}
else
{
    // Exact key not found: BinarySearch returns negative when the 
    // exact target is not found, which is the bitwise complement 
    // of the next index in the list larger than the target.
    ipos = ~ipos;
    if (ipos >= 0 && ipos < keys.Count)
    {
        if (ipos > 0)
        {
            // target is between positions "ipos-1" and "ipos"
        }
        else
        {
            // target is below position "ipos"
        }
    }
    else
    {
        // target is above position "ipos"
    }
}

From MSDN,来自 MSDN,

The elements of a SortedList object are sorted by the keys either according to a specific IComparer implementation specified when the SortedList is created, or according to the IComparable implementation provided by the keys themselves. SortedList object 的元素根据创建 SortedList 时指定的特定 IComparer 实现或根据键本身提供的 IComparable 实现按键排序。 The index sequence is based on the sort sequence.索引序列基于排序序列。 When an element is added, it is inserted into SortedList in the correct sort order, and the indexing adjusts accordingly.添加元素时,它会以正确的排序顺序插入到 SortedList 中,并且索引会相应调整。 When an element is removed, the indexing also adjusts accordingly.当一个元素被删除时,索引也会相应地调整。 Therefore, the index of a specific key/value pair might change as elements are added or removed from the SortedList.因此,特定键/值对的索引可能会随着从 SortedList 中添加或删除元素而更改。

*****This method uses a binary search algorithm; *****此方法使用二分查找算法; therefore, this method is an O(log n) operation, where n is Count.*****因此,此方法是 O(log n) 操作,其中 n 是 Count.*****

Starting with the .NET Framework 2.0, this method uses the collection's objects' Equals and CompareTo methods on item to determine whether item exists.从 .NET 框架 2.0 开始,此方法使用集合对象的 Equals 和对 item 的 CompareTo 方法来确定 item 是否存在。 In the earlier versions of the .NET Framework, this determination was made by using the Equals and CompareTo methods of the item parameter on the objects in the collection.在早期版本的 .NET 框架中,此确定是通过对集合中的对象使用 item 参数的 Equals 和 CompareTo 方法进行的。

In other words, the method IndexOfKey in SortedList is actually using a binarySearch algorithm already, so there is no need to convert form SortedList to List in your case.换句话说,SortedList 中的 IndexOfKey 方法实际上已经使用了 binarySearch 算法,因此在您的情况下,无需将表单 SortedList 转换为 List。

Hope it helps..希望能帮助到你..

public class Bounds
{
    int lower;
    int upper;

    public Bounds(int lower, int upper)
    {
       this.lower = lower;
       this.upper = upper;
    }
}

public Bounds BinarySearch(List<int> keys, double target)
{
    // lower boundary case returns the smallest key as the lower and upper bounds
    if (target < keys[0])
        return new Bounds(0, 0);

    else if (target < keys[1])
        return new Bounds(0, 1);

    // upper boundary case returns the largest key as the lower and upper bounds
    else if (target > keys[keys.Length - 1])
        return new Bounds(keys.Length - 1, keys.Length - 1);

    else if (target > keys[keys.Length - 2])
        return new Bounds(keys.Length - 2, keys.Length - 1);

    else
        return BinarySearch(keys, target, 0, keys.Length - 1);

}

// 'keys' is a List storing all of the keys from your SortedList.
public Bounds BinarySearch(List<int> keys, double target, int lower, int upper)
{
    int middle = (upper + lower)/2;

    // target is equal to one of the keys
    if (keys[middle] == target)
        return new Bounds(middle - 1, middle + 1);

    else if (keys[middle] < target && keys[middle + 1] > target)
        return new Bounds(middle, middle + 1);

    else if (keys[middle] > target && keys[middle - 1] < target)
        return new Bounds(middle - 1, middle);

    if (list[middle] < target)
         return BinarySearch(list, target, lower, upper/2 - 1);

    if (list[middle] > target)
         return BinarySearch(list, target, upper/2 + 1, upper);
}

This might work..I didn't test it out.这可能有效..我没有测试过。 If not, hopefully it's close enough that you can use it with minor tweaks.如果没有,希望它足够接近,您可以通过细微的调整来使用它。 This is a strange problem, so I handled all of the boundary cases so I didn't have to think about what the algorithm would do when the range was down to 2 elements or less.这是一个奇怪的问题,所以我处理了所有的边界情况,所以我不必考虑当范围下降到 2 个元素或更少时算法会做什么。

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

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