Список <T> Бинарный поиск возвращает неправильное значение

1

Бинарный поиск возвращает неправильное значение, даже если список отсортирован. Вот список:

1707 ABCD
1707 XXXX
1725 DEFG
1725 HIJK
1725 LMNOP

Я получаю этот список из файла, предварительно настроенного по времени (первый столбец), поэтому я не сортирую это в своем коде. Когда я делаю двоичный поиск на 1725 DEFG, он возвращает мне 1725 LMNOP перед поразрядным дополнением. Если я поразрядное дополнение, результат будет 1725 HIJK.

Почему это?

Здесь реализация:

 public class RecComparer: IComparer<MyData>
{
 public  int Compare(MyData x, MyData y)
{
    if (x.DateDetails == null)
    {
        if (y.DateDetails == null)
        {
                           return 0;
        }
        else
        {

            return -1;
        }
    }
    else
    {

        if (y.DateDetails == null)
                      {
            return 1;
        }
        else
        {
            int retval = x.DateDetails.Length.CompareTo(y.DateDetails.Length);

            if (retval != 0)
            {

                return retval;
            }
            else
            {

                return x.DateDetails.CompareTo(y.DateDetails);
            }
        }
    }
}
}

Здесь вызов BinarySearch:

lookAhead = recordList.BinarySearch(lookAheadtime, (IComparer<MyData>)rc);

Любая причина, по которой она ведет себя так.

РЕДАКТИРОВАТЬ:

public class MyData
{
    public string DateDetails { get; set; }
    public string TrackDetails { get; set; }
}
  • 0
    Я не верю, что бинарный поиск работает с неуникальными ключами
  • 0
    что было бы лучшим способом реализовать это тогда.
Показать ещё 4 комментария
Теги:
list
binary-search

2 ответа

0
Лучший ответ

Обновление № 2: двоичный поиск с использованием пользовательского сопоставления в списке с дубликатами.

Предполагая, что в "1707 ABCD", "1707" есть DateDetails а "ABCD" - это TrackDetails, у вас есть массив данных с двумя полями, которые уже отсортированы по порядку одного из двух полей, а именно DateDetails. Таким образом, может быть несколько записей с теми же DateDetails.

Если вы выполните BinarySearch, он вернет одну из записей с указанными DateDetails, не обязательно первой. Затем вы должны отсканировать назад, чтобы найти первый.

public static class ListHelper
{
    /// <summary>
    /// Return the zero-based index of the first matching item in the sorted List, 
    /// if a match for item is found; otherwise, a negative number that is the bitwise 
    /// complement of the index of the next element that is larger than item or, if there is
    /// no larger element, the bitwise complement of Count.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="list"></param>
    /// <param name="item"></param>
    /// <param name="comparer"></param>
    /// <returns>The zero-based index of the first matching item in the sorted List, 
    /// if item is found; otherwise, a negative number that is the bitwise complement 
    /// of the index of the next element that is larger than item or, if there is
    /// no larger element, the bitwise complement of Count.</returns>
    public static int BinarySearchFirst<T>(this List<T> list, T item, IComparer<T> comparer)
    {
        int start = list.BinarySearch(item, comparer);
        for (; start > 0 && comparer.Compare(list[start], list[start - 1]) == 0; start--)
            ;
        return start;
    }
    /// <summary>
    /// Find the zero-based indices of the first and last matching items in the sorted List, 
    /// if a match for item is found; otherwise, a negative number for both that is the bitwise 
    /// complement of the index of the next element that is larger than item or, if there is
    /// no larger element, the bitwise complement of Count.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="list"></param>
    /// <param name="item"></param>
    /// <param name="comparer"></param>
    /// <param name="start">The zero-based index of the first matching item in the List, 
    /// if item is found; otherwise, a negative number that is the bitwise complement 
    /// of the index of the next element that is larger than item or, if there is
    /// no larger element, the bitwise complement of Count.</param>
    /// <param name="end">The zero-based index of the first matching item in the sorted List, 
    /// if item is found; otherwise, a negative number that is the bitwise complement 
    /// of the index of the next element that is larger than item or, if there is
    /// no larger element, the bitwise complement of Count.</param>
    /// <returns>true if found, else false</returns>
    public static bool BinarySearchRange<T>(this List<T> list, T item, IComparer<T> comparer, out int start, out int end)
    {
        start = end = list.BinarySearch(item, comparer);
        if (start < 0)
            return false;
        for (; start > 0 && comparer.Compare(list[start], list[start - 1]) == 0; start--)
            ;
        for (int last = list.Count - 1; end < last && comparer.Compare(list[end], list[end + 1]) == 0; end++)
            ;
        return true;
    }
}
  • 0
    Это работает для меня. Мне нужно было сделать одно изменение, чтобы оно заработало: for (; start> 0 && rc.Compare (recordList [~ lookAhead], recordList [start - 1]) == 0; start--);
0

Я не уверен, понимаю ли я эту проблему, но не можете ли вы просто использовать linq для поиска в списке?

recordList.Where(x=>x.columnName == 1725).First();
  • 0
    нет, это не тот случай, это просто пример выше, где у меня проблемы. Если я использую ваш код с LINQ, я не могу найти ближайшее значение

Ещё вопросы

Сообщество Overcoder
Наверх
Меню