对 SortedList的键进行二分查找

发布于 2024-11-08 21:19:09 字数 381 浏览 4 评论 0原文

我需要编写一些用于线性插值的代码,并且我正在尝试找出最有效的方法来搜索 SortedList 的键以查找目标键周围的上下键。

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

double targetX = 3.5;

搜索列表并确定 3.5 介于 3 和 4 之间的最有效方法是什么?我有一个适用于整数的方法/作弊(暂时将目标键插入列表中,然后找到索引),但我想我应该询问专业人士,以便我可以生成高质量的代码。

谢谢。

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<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? 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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

山有枢 2024-11-15 21:19:10

二分搜索可以在列表上提供不错的性能。但是,SortedList 上的 Keys 属性是 IList 类型,而 BinarySearch 是在 List 上定义的。幸运的是,您可以在此相关问题中找到 IList 的二分搜索实现:

如何对 IList执行二分查找?

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. Fortunately, you can find an implementation of binary search for IList in this related question:

How to perform a binary search on IList<T>?

深海里的那抹蓝 2024-11-15 21:19:10

就我而言,源 SortedList 变化不大,因为它被用作查找表。因此,在这种情况下,将 SortedList 转换为 List 一次是有意义的。之后就很容易使用 List 内置的 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"
    }
}

In my case the source SortedList is not changing much, since its being used as a lookup table. So in this case it makes sense to convert the SortedList to a List<T> once. After that it is quite easy to use the built-in BinarySearch method of List<T>...

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"
    }
}
长途伴 2024-11-15 21:19:10
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);
}

这可能有效..我没有测试过。如果没有,希望它足够接近,您可以通过细微的调整来使用它。这是一个奇怪的问题,因此我处理了所有边界情况,因此我不必考虑当范围降至 2 个元素或更少时算法会做什么。

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.

零時差 2024-11-15 21:19:10

根据 MSDN,

SortedList 对象的元素根据创建 SortedList 时指定的特定 IComparer 实现或根据键本身提供的 IComparable 实现按键排序。
索引顺序基于排序顺序。添加元素时,它会以正确的排序顺序插入到 SortedList 中,并且索引也会相应调整。当删除元素时,索引也会相应调整。因此,当在 SortedList 中添加或删除元素时,特定键/值对的索引可能会发生变化。

*****该方法使用二分查找算法;因此,此方法是一个 O(log n) 操作,其中 n 是 Count。*****

从 .NET Framework 2.0 开始,此方法使用集合对象的 item 的 Equals 和 CompareTo 方法来确定 item 是否存在。在 .NET Framework 的早期版本中,此确定是通过对集合中的对象使用 item 参数的 Equals 和 CompareTo 方法来做出的。

换句话说,SortedList 中的 IndexOfKey 方法实际上已经使用了二元搜索算法,因此在您的情况下不需要将 SortedList 转换为 List。

希望有帮助..

From 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.
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. 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.

*****This method uses a binary search algorithm; therefore, this method is an O(log n) operation, where n is 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. 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.

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.

Hope it helps..

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文