在C#中进行范围查找 - 如何实现PART DEUX

时间:2012-01-23 22:37:02

标签: c# generics interface

鉴于下面显示的'原始代码'(来自主题Doing a range Lookup

我正在尝试实现一个将包装BinarySearch例程的TableLookUp方法。我更改了Range类以接受value属性。我创建了TableLookUp例程,但我知道这是错误的。我不知道如何调用BinarySearch方法来实现这一点。仿制药让我感到困惑。

提前Tx!

调用的值可能如下:

var ranges = new Range<int>[]
            {
                new Range<int>(1, 10000, 22),
                new Range<int>(10001, 40000, 33),
                new Range<int>(40001, int.MaxValue, 44)
            };

使用以下代码替换Range类:

    public class Range<TValue>
        where TValue : IComparable<TValue>
    {
        public TValue Min { get; set; }
        public TValue Max { get; set; }
        public int Value { get; set; }

        public Range(TValue min, TValue max, int value)
        {
            this.Min = min;
            this.Max = max;
            this.Value = value;
        }
    }

将包装器添加到二进制搜索:

public static int LookUpTable<TRange, TValue>(IList<TRange> ranges, TValue value, IRangeComparer<TRange, TValue> comparer)
    {
        int indexToTable = BinarySearch(ranges, value, comparer);
        Range<TRange> lookUp = ranges[indexToTable];
        return lookUp.Value;
    }

将main中的调用代码替换为以下内容:

Console.WriteLine(LookUpTable(ranges, 7, rangeComparer));
Console.WriteLine(LookUpTable(ranges, 10007, rangeComparer));
Console.WriteLine(LookUpTable(ranges, 40007, rangeComparer));
Console.WriteLine(LookUpTable(ranges, 1, rangeComparer));   

原始代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace TestConsole
{
    class Program
    {

        public interface IRangeComparer<TRange, TValue>
        {
            /// <summary>
            /// Returns 0 if value is in the specified range;
            /// less than 0 if value is above the range;
            /// greater than 0 if value is below the range.
            /// </summary>
            int Compare(TRange range, TValue value);
        }


        /// <summary>
        /// See contract for Array.BinarySearch
        /// </summary>
        public static int BinarySearch<TRange, TValue>(IList<TRange> ranges,
                                                       TValue value,
                                                       IRangeComparer<TRange, TValue> comparer)
        {
            int min = 0;
            int max = ranges.Count - 1;

            while (min <= max)
            {
                int mid = (min + max) / 2;
                int comparison = comparer.Compare(ranges[mid], value);
                if (comparison == 0)
                {
                    return mid;
                }
                if (comparison < 0)
                {
                    min = mid + 1;
                }
                else if (comparison > 0)
                {
                    max = mid - 1;
                }
            }
            return ~min;
        }

        public class Range<TValue>
            where TValue : IComparable<TValue>
        {
            public TValue Min { get; set; }
            public TValue Max { get; set; }

            public Range(TValue min, TValue max)
            {
                this.Min = min;
                this.Max = max;
            }
        }

        public class RangeComparer<TValue> : IRangeComparer<Range<TValue>, TValue>
            where TValue : IComparable<TValue>
        {
            /// <summary>
            /// Returns 0 if value is in the specified range;
            /// less than 0 if value is above the range;
            /// greater than 0 if value is below the range.
            /// </summary>
            public int Compare(Range<TValue> range, TValue value)
            {
                // Check if value is below range (less than min).
                if (range.Min.CompareTo(value) > 0)
                    return 1;

                // Check if value is above range (greater than max)
                if (range.Max.CompareTo(value) < 0)
                    return -1;

                // Value is within range.
                return 0;
            }
        }


        static void Main(string[] args)
        {

            var ranges = new Range<int>[]
            {
                new Range<int>(1, 10000),
                new Range<int>(10001, 40000),
                new Range<int>(40001, int.MaxValue),
            };

            var rangeComparer = new RangeComparer<int>();

            Console.WriteLine(BinarySearch(ranges, 7, rangeComparer));       // gives 0
            Console.WriteLine(BinarySearch(ranges, 10007, rangeComparer));   // gives 1
            Console.WriteLine(BinarySearch(ranges, 40007, rangeComparer));   // gives 2
            Console.WriteLine(BinarySearch(ranges, 1, rangeComparer));       // gives 0
            Console.WriteLine(BinarySearch(ranges, 10000, rangeComparer));   // gives 0
            Console.WriteLine(BinarySearch(ranges, 40000, rangeComparer));   // gives 1
            Console.WriteLine(BinarySearch(ranges, 40001, rangeComparer));   // gives 2

            Console.WriteLine("Press any key to continue...");
            Console.ReadKey(true);
        }
    }
}

1 个答案:

答案 0 :(得分:1)

public static int LookUpTable<TRange, TValue>(IList<TRange> ranges, TValue value, IRangeComparer<TRange, TValue> comparer)
    where TRange : Range<TValue> // Specify what you know about TRange and TValue
    where TValue : IComparable<TValue>
{
    int indexToTable = BinarySearch(ranges, value, comparer);
    TRange lookUp = ranges[indexToTable]; // lookUp is TRange, not Range<TRange>
    return lookUp.Value;
}