有没有一种方法可以快速地将项目插入(log(n))到任何IList <T>

时间:2020-05-19 14:32:31

标签: c# list performance generics

在WPF中,我想让我的ObservableCollection保持排序。项目是随机添加的,不是批量添加的。我不想每次对整个IList进行排序。我想在每个插入物的适当位置插入。

有没有一种方法可以将项目快速(log(n))插入到T的任何IList中。

有人为它写过代码吗?

注意:是的,在调用此方法之前,列表应该已经排序。

注2:有时您必须使用IList,并且不能将其替换为SortedList,并且不想维护2个集合:例如:在WPF中使用ObservableCollection。

更新,是的,有一种方法可以做到。通过使用二分法。我问这个问题可以节省时间。我正在编写它,调试后将立即显示它。

2 个答案:

答案 0 :(得分:1)

好的...我是在有人关闭我的问题之前完成的(这几乎要2票才能完成)...

尽管有2个人投票关闭,但我认为这是个好问题,我也认为代码值得保留。

我花了大约5个小时来进行调试。似乎工作正常。节省5个小时...这就是为什么我问这个问题。为了节省时间。

/// <summary>
/// Insert item in list in log(n). The list should already be sorted.
/// Item will be inserted and there will be duplicate if comparer return 0.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="list"></param>
/// <param name="item"></param>
/// <param name="comparer"></param>
/// <returns></returns>
public static int InsertInSortedList<T>(this IList<T> list, T item, Func<T, T, int> comparer = null)
{
    if (comparer == null)
    {
        comparer = Comparer<T>.Default.Compare;
    }

    int first = 0;
    int last = list.Count;
    int middle = 0;
    int compareResult = 0;

    if (last > 0)
    {
        while (true)
        {
            middle = first + ((last - first) / 2);

            compareResult = comparer(item, list[middle]);

            if (compareResult > 0)
            {
                first = middle + 1;

                if (first >= last)
                {
                    middle++;
                    break;
                } 

                continue;
            }

            if (compareResult < 0)
            {
                last = middle;

                if (first == last)
                {
                    break;
                }

                continue;
            }

            break;
        }
    }

    if (middle == list.Count)
    {
        list.Add(item);
    }
    else
    {
        list.Insert(middle, item);
    }

    return middle;

}

答案 1 :(得分:1)

以下是一些有用的扩展方法,用于分类的IList<T>集合(SortedBinarySearchSortedIndexOfSortedInsertSortedRemove)。二进制搜索算法从ArraySortHelper<T>.InternalBinarySearch方法的源代码中被盗。

/// <summary>Searches within the sorted <see cref="IList{T}"/> for the
/// specified item and returns the zero-based index of the item if found;
/// otherwise, a negative number that is the bitwise complement of the index of
/// the next item that is larger than item or, if there is no larger item,
/// the bitwise complement of <see cref="IList{T}.Count"/>.</summary>
public static int SortedBinarySearch<T>(this IList<T> list, T item,
    IComparer<T> comparer = null)
{
    if (list == null) throw new ArgumentNullException(nameof(list));
    comparer = comparer ?? Comparer<T>.Default;

    int lo = 0;
    int hi = list.Count - 1;
    while (lo <= hi)
    {
        int i = lo + ((hi - lo) >> 1);
        int order = comparer.Compare(list[i], item);

        if (order == 0) return i;
        if (order < 0)
        {
            lo = i + 1;
        }
        else
        {
            hi = i - 1;
        }
    }
    return ~lo;
}

/// <summary>Searches for the specified item within the sorted
/// <see cref="IList{T}"/> and returns the zero-based index of the item
/// if found; otherwise, -1.</summary>
public static int SortedIndexOf<T>(this IList<T> list, T item,
    IComparer<T> comparer = null)
{
    int index = SortedBinarySearch(list, item, comparer);
    if (index < 0) return -1;
    return index;
}

/// <summary>Inserts an item into the sorted <see cref="IList{T}"/>.</summary>
public static int SortedInsert<T>(this IList<T> list, T item,
    IComparer<T> comparer = null)
{
    int index = SortedBinarySearch(list, item, comparer);
    if (index < 0) index = ~index;
    list.Insert(index, item);
    return index;
}

/// <summary>Removes an item from the sorted <see cref="IList{T}"/> and returns
/// true if the item is successfully removed; otherwise, false.</summary>
public static bool SortedRemove<T>(this IList<T> list, T item,
    IComparer<T> comparer = null)
{
    int index = SortedBinarySearch(list, item, comparer);
    if (index < 0) return false;
    list.RemoveAt(index);
    return true;
}