首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >SortedList性能

SortedList性能
EN

Code Review用户
提问于 2020-10-25 14:25:59
回答 1查看 686关注 0票数 5

我发现我的应用程序(使用SortedList )性能很差。所以我决定努力提高我的应用程序的性能。我创建了FastSortedList类,我认为它比原来的类要快。

代码语言:javascript
复制
public class FastSortedList
{
    IComparer _comparer;
    List> _list = new List>();
    Dictionary _dict = new Dictionary();
    public FastSortedList(IComparer comparer)
    {
        _comparer = comparer ?? Comparer.Default;
    }

    public int Count => _list.Count;

    public IEnumerable Values => _list.Select(i => i.Value);

    public void Add(TKey key, TValue value)
    {
        if (_dict.ContainsKey(key))
            throw new ArgumentException("An entry with the same key already exists.");
        int index = BinarySearch(key);
        if (index < 0)
        {
            _list.Insert(~index, new KeyValuePair(key, value));
        }
        else
        {
            _list.Insert(index, new KeyValuePair(key, value));
        }
        _dict[key] = value;
    }

    public int IndexOfKey(TKey key)
    {
        if (_dict.ContainsKey(key))
            return BinarySearch(key);
        return -1;
    }

    public void RemoveAt(int index)
    {
        if (index < 0)
            return;
        var item = _list[index];
        _list.RemoveAt(index);
        _dict.Remove(item.Key);
    }

    private int BinarySearch(TKey key)
    {
        int lo = 0;
        int hi = _list.Count - 1;
        while (lo <= hi)
        {
            int i = GetMedian(lo, hi);
            int c = _comparer.Compare(_list[i].Key, key);
            if (c == 0)
                return i;
            if (c < 0)
            {
                lo = i + 1;
            }
            else
            {
                hi = i - 1;
            }
        }
        return ~lo;
    }

    private int GetMedian(int lo, int hi)
    {
        return lo + ((hi - lo) >> 1);
    }
}

用过的比较器:

代码语言:javascript
复制
public class TestComparer : IComparer
{
    public int Compare(string x, string y)
    {
        return string.Compare(x, y);
    }
}

Stopwatch:

的比较

代码语言:javascript
复制
private static void CompareWithStopwatch()
{
    int index;
    IEnumerable values;

    FastSortedList fast = new FastSortedList(new TestComparer());

    Stopwatch sw = new Stopwatch();
    sw.Start();
    for (int i = 0; i < 1000000; i++)
    {
        fast.Add($"test{i}", i);
    }
    sw.Stop();
    Console.WriteLine($"FastSortedList: Populate records: elapsed time: {sw.Elapsed.TotalSeconds} sec, total records: {fast.Count}");

    sw.Start();
    index = fast.IndexOfKey("test745723");
    sw.Stop();
    Console.WriteLine($"FastSortedList: IndexOfKey: key: 'test745723', index: {index}, elapsed time: {sw.Elapsed.TotalSeconds} sec");

    sw.Start();
    fast.RemoveAt(index);
    sw.Stop();
    Console.WriteLine($"FastSortedList: RemoveAt: key: 'test745723', index: {index} elapsed time: {sw.Elapsed.TotalSeconds} sec");

    sw.Start();
    values = fast.Values;
    sw.Stop();
    Console.WriteLine($"FastSortedList: Get values, elapsed time: {sw.Elapsed.TotalSeconds} sec");


    SortedList sorted = new SortedList(new TestComparer());

    sw.Start();
    for (int i = 0; i < 1000000; i++)
    {
        sorted.Add($"test{i}", i);
    }
    sw.Stop();
    Console.WriteLine($"SortedList: Populate records: elapsed time: {sw.Elapsed.TotalSeconds} sec, total records: {sorted.Count}");

    sw.Start();
    index = sorted.IndexOfKey("test745723");
    sw.Stop();
    Console.WriteLine($"SortedList: IndexOfKey: key: 'test745723', index: {index}, elapsed time: {sw.Elapsed.TotalSeconds} sec");

    sw.Start();
    sorted.RemoveAt(index);
    sw.Stop();
    Console.WriteLine($"SortedList: RemoveAt: key: 'test745723', index: {index} elapsed time: {sw.Elapsed.TotalSeconds} sec");

    sw.Start();
    values = sorted.Values;
    sw.Stop();
    Console.WriteLine($"SortedList: Get values, elapsed time: {sw.Elapsed.TotalSeconds} sec");

    FastSortedList fastRevrese = new FastSortedList(new TestComparer());

    sw.Start();
    for (int i = 999999; i >= 0; i--)
    {
        fastRevrese.Add($"test{i}", i);
    }
    sw.Stop();
    Console.WriteLine($"FastSortedList: fastRevrese - Populate records: elapsed time: {sw.Elapsed.TotalSeconds} sec, total records: {fastRevrese.Count}");

    sw.Start();
    index = fastRevrese.IndexOfKey("test745723");
    sw.Stop();
    Console.WriteLine($"FastSortedList: fastRevrese - IndexOfKey: key: 'test745723', index: {index}, elapsed time: {sw.Elapsed.TotalSeconds} sec");

    sw.Start();
    fastRevrese.RemoveAt(index);
    sw.Stop();
    Console.WriteLine($"FastSortedList: fastRevrese - RemoveAt: key: 'test745723', index: {index} elapsed time: {sw.Elapsed.TotalSeconds} sec");

    sw.Start();
    values = fastRevrese.Values;
    sw.Stop();
    Console.WriteLine($"SortedList: fastRevrese - Get values, elapsed time: {sw.Elapsed.TotalSeconds} sec");

    SortedList sortedRevrese = new SortedList(new TestComparer());

    sw.Start();
    for (int i = 999999; i >= 0; i--)
    {
        sortedRevrese.Add($"test{i}", i);
    }
    sw.Stop();
    Console.WriteLine($"SortedList: sortedRevrese Populate records: elapsed time: {sw.Elapsed.TotalSeconds} sec, total records: {sortedRevrese.Count}");

    sw.Start();
    index = sortedRevrese.IndexOfKey("test745723");
    sw.Stop();
    Console.WriteLine($"SortedList: sortedRevrese - IndexOfKey: key: 'test745723', index: {index}, elapsed time: {sw.Elapsed.TotalSeconds} sec");

    sw.Start();
    sortedRevrese.RemoveAt(index);
    sw.Stop();
    Console.WriteLine($"SortedList: sortedRevrese - RemoveAt: key: 'test745723', index: {index} elapsed time: {sw.Elapsed.TotalSeconds} sec");

    sw.Start();
    values = sortedRevrese.Values;
    sw.Stop();
    Console.WriteLine($"SortedList: sortedRevrese - Get values, elapsed time: {sw.Elapsed.TotalSeconds} sec");
}

结果:

与Benchmark.NET:

的比较

代码语言:javascript
复制
public class RaceBenchmark
{
    const int LENGTH = 100000;

    [Benchmark]
    public void InsertToSortedList()
    {
        SortedList sorted = new SortedList(new TestComparer());
        for (int i = 0; i < LENGTH; i++)
        {
            sorted.Add($"test{i}", i);
        }
    }

    [Benchmark]
    public void InsertToFastSortedList()
    {
        FastSortedList fast = new FastSortedList(new TestComparer());
        for (int i = 0; i < LENGTH; i++)
        {
            fast.Add($"test{i}", i);
        }
    }

    [Benchmark]
    public void SortedListIndexOfKey()
    {
        SortedList sorted = new SortedList(new TestComparer());
        for (int i = 0; i < LENGTH; i++)
        {
            sorted.Add($"test{i}", i);
        }
        var sortedListIndex = sorted.IndexOfKey("test4321");
    }

    [Benchmark]
    public void FastSortedListIndexOfKey()
    {
        FastSortedList fast = new FastSortedList(new TestComparer());
        for (int i = 0; i < LENGTH; i++)
        {
            fast.Add($"test{i}", i);
        }
        var fastIndex = fast.IndexOfKey("test4321");
    }

    [Benchmark]
    public void SortedListRemoveAt()
    {
        SortedList sorted = new SortedList(new TestComparer());
        for (int i = 0; i < LENGTH; i++)
        {
            sorted.Add($"test{i}", i);
        }
        var sortedListIndex = sorted.IndexOfKey("test4321");
        sorted.RemoveAt(sortedListIndex);
    }

    [Benchmark]
    public void FastSortedListRemoveAt()
    {
        FastSortedList fast = new FastSortedList(new TestComparer());
        for (int i = 0; i < LENGTH; i++)
        {
            fast.Add($"test{i}", i);
        }
        var fastIndex = fast.IndexOfKey("test4321");
        fast.RemoveAt(fastIndex);
    }


    [Benchmark]
    public void SortedListGetValues()
    {
        SortedList sorted = new SortedList(new TestComparer());
        for (int i = 0; i < LENGTH; i++)
        {
            sorted.Add($"test{i}", i);
        }
        var values = sorted.Values;
    }

    [Benchmark]
    public void FastSortedLisGetValues()
    {
        FastSortedList fast = new FastSortedList(new TestComparer());
        for (int i = 0; i < LENGTH; i++)
        {
            fast.Add($"test{i}", i);
        }
        var values = fast.Values;
    }
}

结果:

我将很高兴得到这个实现的代码审查。

EN

回答 1

Code Review用户

发布于 2021-03-31 18:33:38

GetMedian -- (请不要称它为“中位数”;虽然它是索引的中值,但它不是中间键。)

代码语言:javascript
复制
return lo + ((hi - lo) >> 1);

-->

代码语言:javascript
复制
return (hi + lo) >> 1;

你知道你的编译是否会自动“内联”函数吗?如果没有,那就自己做吧:

代码语言:javascript
复制
int i = GetMedian(lo, hi);

-->

代码语言:javascript
复制
int i = (hi + lo) >> 1;

想想频率..。

代码语言:javascript
复制
        if (c == 0) ...
        if (c < 0) ...
        else ...

如果项目数量较低,最好先测试0,但我不认为这是“典型的”情况。所以,重新安排两个测试和其他测试。

此外,特定的"test745723“键每次都会下降N个级别。当N很小时,您的代码就“快”了。因此,我对只涉及一个键的基准测试结果表示怀疑。

票数 -1
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/251127

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档