在不到O(n)的时间内找到最大值,同时在无序列表中快速插入/删除

时间:2019-07-05 23:34:31

标签: c# performance data-structures

代码:

using System;
using System.Diagnostics;

namespace ConsoleApp1
{
    class Program
    {
        const int maxResult = 120; //this can change but hardcoded for this code

        static int poolPos;
        static double[] pool = new double[maxResult * 4];

        static int maxPos;
        static double[] result = new double[maxResult];


        static void Main(string[] args)
        {
            var sw = Stopwatch.StartNew();

            for(int i = 0; i  < 100_000; ++i)
                Unlock();

            Console.WriteLine(sw.ElapsedMilliseconds);

            //Console.Read();
        }

        static void Unlock()
        {
            int total = maxResult;

            //reset array
            poolPos = 0;
            maxPos = 0;

            FindLock(4);


            while (total-- > 0)
            {
                int i = 0;

                double maxWeight = pool[0];
                int pos = 0;

                while (++i < poolPos) //O(n), can it be faster?
                    if (pool[i] >= maxWeight) //can have duplicate value, find latest max inserted
                        (maxWeight, pos) = (pool[i], i); //keep track

                result[maxPos++] = maxWeight; //store the result
                pool[pos] = pool[--poolPos]; //remove from array by swapping it with last item in the array
                FindLock();
            }
        }

        //simulate what feed the array
        //don't look at this unless something should be done at insert time
        static Random rnd = new Random(42); 
        static void FindLock(int add = -1)
        {
            if(add == -1)
            {
                add = rnd.Next(1, 4);
            }

            for(int i = 0;i<add;++i)
            {
                pool[poolPos++] = rnd.Next(-500, 500) / 100d;
            }
        }
    }
}

分析结果: profiling result

基于性能分析,我试图找到一种加快速度的方法,我在网上找到的所有解决方案都使用双栈或双队列,因此它们仅使用数组的头或尾值,上面的代码可以从列表中选择任何符合要求的项目,这样我就不能使用堆栈或队列。

2 个答案:

答案 0 :(得分:1)

使用“优先级队列”或“最大堆”,表会部分排序,并且许多操作都是O(log(N)):

  • 最大(或最小,但不是两个)
  • 插入一行
  • 删除一行

已知项目1大于项目2和3。项目1始终是最大值。
已知项目2大于项目4和5。
已知项目3大于项目6和7。
等一般:
已知项目[k]大于项目[2 * k]和[2 * k + 1]。

插入和删除操作比较麻烦,因为您希望保持表格紧凑。

众多参考文献之一:https://www.techiedelight.com/introduction-priority-queues-using-binary-heaps/

如果物品来回频繁,结构可以很方便,但是重要的动作是获取最大值。访问最大值是O(1),但删除最大值是O(N)。

答案 1 :(得分:0)

根据定义,如果您使用的是无序列表,则找到一个项目在最佳情况下始终为O(1),在最坏情况下始终为O(n)。

您可以使用哈希表来获得更好的查找速度以及插入/删除。但是,哈希算法本身可能与遍历列表一样昂贵,因此请谨慎行事。根据使用情况,可以使用哈希表。