Why is insertion into my tree faster on sorted input than random input?

前端 未结 8 1256
慢半拍i
慢半拍i 2021-02-02 12:33

Now I\'ve always heard binary search trees are faster to build from randomly selected data than ordered data, simply because ordered data requires explicit rebalancing to keep t

8条回答
  •  暗喜
    暗喜 (楼主)
    2021-02-02 13:02

    I added calculation of the standard deviation, and changed your test to run at the highest priority (to reduce noise as much as possible). This are the results:

    Random                                   Ordered
    0,2835 (stddev 0,9946)                   0,0891 (stddev 0,2372)
    0,1230 (stddev 0,0086)                   0,0780 (stddev 0,0031)
    0,2498 (stddev 0,0662)                   0,1694 (stddev 0,0145)
    0,5136 (stddev 0,0441)                   0,3550 (stddev 0,0658)
    1,1704 (stddev 0,1072)                   0,6632 (stddev 0,0856)
    1,4672 (stddev 0,1090)                   0,8343 (stddev 0,1047)
    3,3330 (stddev 0,2041)                   1,9272 (stddev 0,3456)
    7,9822 (stddev 0,3906)                   3,7871 (stddev 0,1459)
    18,4300 (stddev 0,6112)                  10,3233 (stddev 2,0247)
    44,9500 (stddev 2,2935)                  22,3870 (stddev 1,7157)
    110,5275 (stddev 3,7129)                 49,4085 (stddev 2,9595)
    275,4345 (stddev 10,7154)                107,8442 (stddev 8,6200)
    667,7310 (stddev 20,0729)                242,9779 (stddev 14,4033)
    

    I've ran a sampling profiler and here are the results (amount of times the program was in this method):

    Method           Random        Ordered
    HeapifyRight()   1.95          5.33
    get_IsEmpty()    3.16          5.49
    Make()           3.28          4.92
    Insert()         16.01         14.45
    HeapifyLeft()    2.20          0.00
    

    Conclusion: the random has a fairly reasonable distribution between left and right rotation, while the ordered never rotates left.

    Here is my improved "benchmark" program:

        static void Main(string[] args)
        {
            Thread.CurrentThread.Priority = ThreadPriority.Highest;
            Process.GetCurrentProcess().PriorityClass = ProcessPriorityClass.RealTime;
    
            List rndTimes = new List();
            List orderedTimes = new List();
    
            rndTimes.Add(TimeIt(50, RandomInsert));
            rndTimes.Add(TimeIt(100, RandomInsert));
            rndTimes.Add(TimeIt(200, RandomInsert));
            rndTimes.Add(TimeIt(400, RandomInsert));
            rndTimes.Add(TimeIt(800, RandomInsert));
            rndTimes.Add(TimeIt(1000, RandomInsert));
            rndTimes.Add(TimeIt(2000, RandomInsert));
            rndTimes.Add(TimeIt(4000, RandomInsert));
            rndTimes.Add(TimeIt(8000, RandomInsert));
            rndTimes.Add(TimeIt(16000, RandomInsert));
            rndTimes.Add(TimeIt(32000, RandomInsert));
            rndTimes.Add(TimeIt(64000, RandomInsert));
            rndTimes.Add(TimeIt(128000, RandomInsert));
            orderedTimes.Add(TimeIt(50, OrderedInsert));
            orderedTimes.Add(TimeIt(100, OrderedInsert));
            orderedTimes.Add(TimeIt(200, OrderedInsert));
            orderedTimes.Add(TimeIt(400, OrderedInsert));
            orderedTimes.Add(TimeIt(800, OrderedInsert));
            orderedTimes.Add(TimeIt(1000, OrderedInsert));
            orderedTimes.Add(TimeIt(2000, OrderedInsert));
            orderedTimes.Add(TimeIt(4000, OrderedInsert));
            orderedTimes.Add(TimeIt(8000, OrderedInsert));
            orderedTimes.Add(TimeIt(16000, OrderedInsert));
            orderedTimes.Add(TimeIt(32000, OrderedInsert));
            orderedTimes.Add(TimeIt(64000, OrderedInsert));
            orderedTimes.Add(TimeIt(128000, OrderedInsert));
            var result = string.Join("\n", (from s in rndTimes
                            join s2 in orderedTimes
                                on rndTimes.IndexOf(s) equals orderedTimes.IndexOf(s2)
                            select String.Format("{0} \t\t {1}", s, s2)).ToArray());
            Console.WriteLine(result);
            Console.WriteLine("Done");
            Console.ReadLine();
        }
    
        static double StandardDeviation(List doubleList)
        {
            double average = doubleList.Average();
            double sumOfDerivation = 0;
            foreach (double value in doubleList)
            {
                sumOfDerivation += (value) * (value);
            }
            double sumOfDerivationAverage = sumOfDerivation / doubleList.Count;
            return Math.Sqrt(sumOfDerivationAverage - (average * average));
        }
        static String TimeIt(int insertCount, Action f)
        {
            Console.WriteLine("TimeIt({0}, {1})", insertCount, f.Method.Name);
    
            List times = new List();
            for (int i = 0; i < ITERATION_COUNT; i++)
            {
                Stopwatch sw = Stopwatch.StartNew();
                f(insertCount);
                sw.Stop();
                times.Add(sw.Elapsed.TotalMilliseconds);
            }
    
            return String.Format("{0:f4} (stddev {1:f4})", times.Average(), StandardDeviation(times));
        }
    

提交回复
热议问题