Что словарь.NET поддерживает, “находят ближайшую ключевую” операцию?

Самым близким, что я могу придумать, будет Xz-utils , который использует общедоступный LZMA SDK. Это не zip, per se , и при этом он не использует алгоритм deflate, но это одна из немногих библиотек сжатия в открытом доступе.

11
задан Qwertie 6 November 2009 в 23:33
поделиться

6 ответов

Проблема в том, что словарь / хеш-таблица предназначена для получения уникального места в памяти на основе входного значения, поэтому вам понадобится структура данных, которая предназначена для размещения связанных с диапазоном для каждого значения, которое вы сохраняете, и в то же время правильно обновляйте каждый интервал

Я думаю, что списки пропуска (или сбалансированные бинарные деревья) могут вам помочь. Хотя они не могут выполнять поиск за O (n), они могут выполнять поиск в логарифмическом масштабе и по-прежнему быстрее, чем деревья.

Я знаю, что это неправильный ответ, поскольку я не могу сказать, что .NET BCL уже содержит такой класс, вы к сожалению, придется реализовать его самостоятельно или найти стороннюю сборку, которая поддерживает его для вас. Хотя, похоже, есть хороший пример на , CodeProject здесь .

1
ответ дан 3 December 2019 в 11:36
поделиться

Вы можете попробовать код, который я написал ниже. он использует двоичный поиск, поэтому предполагается, что список / массив предварительно отсортирован.

public static class ListExtensions
{
    public static int GetAtMostIndex<TItem, TValue>(/*this*/ IList<TItem> list, TValue value, Func<TItem, TValue, int> comparer)
    {
        return GetAtMostIndex(list, value, comparer, 0, list.Count);
    }

    public static int GetAtLeastIndex<TItem, TValue>(/*this*/ IList<TItem> list, TValue value, Func<TItem, TValue, int> comparer)
    {
        return GetAtLeastIndex(list, value, comparer, 0, list.Count);
    }

    public static int GetAtMostIndex<TItem, TValue>(/*this*/ IList<TItem> list, TValue value, Func<TItem, TValue, int> comparer, int index, int count)
    {
        if (count == 0)
        {
            return -1;
        }

        int startIndex = index;
        int endIndex = index + count - 1;
        int middleIndex = 0;
        int compareResult = -1;

        while (startIndex < endIndex)
        {
            middleIndex = (startIndex + endIndex) >> 1; //  / 2
            compareResult = comparer.Invoke(list[middleIndex], value);

            if (compareResult > 0)
            {
                endIndex = middleIndex - 1;
            }
            else if (compareResult < 0)
            {
                startIndex = middleIndex + 1;
            }
            else
            {
                return middleIndex;
            }
        }

        if (startIndex == endIndex)
        {
            compareResult = comparer.Invoke(list[startIndex], value);

            if (compareResult <= 0)
            {
                return startIndex;
            }
            else
            {
                int returnIndex = startIndex - 1;

                if (returnIndex < index)
                {
                    return -1;
                }
                else
                {
                    return returnIndex;
                }
            }
        }
        else
        {
            //todo: test
            return startIndex - 1;
        }
    }

    public static int GetAtLeastIndex<TItem, TValue>(/*this*/ IList<TItem> list, TValue value, Func<TItem, TValue, int> comparer, int index, int count)
    {
        if (count == 0)
        {
            return -1;
        }

        int startIndex = index;
        int endIndex = index + count - 1;
        int middleIndex = 0;
        int compareResult = -1;

        while (startIndex < endIndex)
        {
            middleIndex = (startIndex + endIndex) >> 1; //  / 2
            compareResult = comparer.Invoke(list[middleIndex], value);

            if (compareResult > 0)
            {
                endIndex = middleIndex - 1;
            }
            else if (compareResult < 0)
            {
                startIndex = middleIndex + 1;
            }
            else
            {
                return middleIndex;
            }
        }

        if (startIndex == endIndex)
        {
            compareResult = comparer.Invoke(list[startIndex], value);

            if (compareResult >= 0)
            {
                return startIndex;
            }
            else
            {
                int returnIndex = startIndex + 1;

                if (returnIndex >= index + count)
                {
                    return -1;
                }
                else
                {
                    return returnIndex;
                }
            }
        }
        else
        {
            return endIndex + 1;
        }
    }
}
1
ответ дан 3 December 2019 в 11:36
поделиться

найти ближайший к K:

dict.Keys.Where(i => i >= K).OrderBy(i => i).First();

или намного быстрее:

public int? GetNearestKey(dict, K) 
{
    int? lowerK = null;
    foreach (int key in dict.Keys)
    {
        if (key == K) 
        {
            lowerK = K;
            break; 
        }
        else if (key >= K && (!lowerK.HasValue || key < lowerK))
        {
            lowerK = key;
        }
    }
    return lowerK;
}
0
ответ дан 3 December 2019 в 11:36
поделиться

В базовой структуре нет реализации коллекции двоичного дерева поиска, поэтому вам придется либо создать ее, либо найти реализацию. Как вы заметили, SortedList наиболее близок с точки зрения поиска, но медленнее (из-за своей базовой реализации массива) для вставки / удаления.

0
ответ дан 3 December 2019 в 11:36
поделиться

Я думаю, что есть ошибка в вопросе о сложности SortedList .

SortedList имеет амортизированную сложность O (log (n)) для вставки новинка. Если вы заранее знаете емкость, это можно сделать за O (Log (n)) в худшем случае.

0
ответ дан 3 December 2019 в 11:36
поделиться

Потребовалось несколько месяцев работы, но наконец я могу предложить хотя бы частичное решение этой проблемы ... Я называю это Compact Patricia Trie , отсортированный словарь, предлагающий операцию «найти следующий больший ключ».

http://www.codeproject.com/KB/recipes/cptrie.aspx

Это лишь частичное решение, поскольку поддерживаются только определенные типы ключей, а именно байт [] , строка и все примитивные целочисленные типы (Int8..UInt64). Кроме того, сортировка строк чувствительна к регистру.

2
ответ дан 3 December 2019 в 11:36
поделиться
Другие вопросы по тегам:

Похожие вопросы: