【问题标题】:Time Complexity Theory not matching up with practical experiment for Linear Search时间复杂度理论与线性搜索的实际实验不匹配
【发布时间】:2013-08-04 18:43:39
【问题描述】:

我正在使用线性搜索算法,从该算法的理论来看,它的时间复杂度为 O(n)。现在我必须使用实际代码来证明这一点,并创建一个图表来证明该算法实际上是 O(n)。但有些实际的结果根本没有体现出来。

这是我使用的编码方法:

  1. 我有一个循环,它根据循环号动态创建一个数组。
  2. 然后我用数字随机填充这个数组。
  3. 然后我实现线性搜索算法。现在在算法运行之前,我记下时间,一旦找到我要搜索的值,我就会停止时钟并保存时间,并在循环结束时将值写入文本文件。
  4. 然后我将 text'file 导入到 excel 中并创建一个图表。但是结果并不能证实算法是O(n)的事实

这是我的java代码:

 public static void main(String[] args) 
    {
        
        long[] ArrayTimeTaken = new long[10000];
        String Display = "";
        
        //Code that runs the linear search
        for (int i = 2; i < 10000; i++) 
        {
            int[] arrayExperimentTest = new int[i];
            arrayExperimentTest = FillArray(i);
            int ValuetoSearchfor = Math.round(((arrayExperimentTest.length)/2));
            System.out.println(ValuetoSearchfor);
            ArrayTimeTaken[i] = LinearSearch(arrayExperimentTest,ValuetoSearchfor);
            Display = Display+ System.getProperty("line.separator") + ArrayTimeTaken[i]; 
           
        }
        PrintWriter writer;
        try {
            writer = new PrintWriter("C:/Users/Roberto/Desktop/testing.txt", "UTF-8");
            writer.println(Display);
            writer.close();
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (UnsupportedEncodingException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        //ChartCreate(ArrayTimeTaken);  
        System.out.println("Done");
    }

这里是用随机数填充数组和线性搜索的代码:

 //This code simply populates our array with numbers in each of the array positions
    static int[] FillArray(int number)
    {
        int[] ArrayofValues = new int[number];
        for (int i = 0; i < number; i++) 
        {
            Random randomGenerator = new Random();
            boolean flag = true;
            while (flag) 
            {                
                int index = randomGenerator.nextInt(number);
                if (ArrayofValues[index] == 0)
                {
                    ArrayofValues[index] = i;
                    flag = false;
                }
            }
        }
        return ArrayofValues;
    }
    
    //This function does a linear search on an array with integers
    static long LinearSearch(int[] ArraySearch,int ValueFind)
    {
        long TimeTaken = 0;
        long startTime = System.currentTimeMillis();
        System.gc();
        
        for (int i = 0; i < ArraySearch.length; i++) 
        {
            if (ArraySearch[i] == ValueFind) 
            {
                TimeTaken = System.currentTimeMillis() - startTime;
                break;
            }
            
        }
        return TimeTaken;
        
    }

这是结果图。我不应该得到一个直线图吗?

【问题讨论】:

  • 这样的基准测试很难,运行时/编译器可能会优化掉。
  • "结果并不能证实算法是 O(n)"。您能详细说明一下吗??
  • 为什么要在获取起始时间戳之后明确启动垃圾收集运行?
  • 我添加了上面的图表,使问题更加清晰。我也认为我打算在开始计时之前实施垃圾收集?
  • 只是我通过查看图表的一个想法。你不觉得数组太小了吗?当它们都以毫秒为单位时,您可能不会注意到差异。使用更大的数组并多次运行测试,这样操作至少需要几秒钟,并且受计算机上“噪音”的影响较小。

标签: java computer-science


【解决方案1】:

您无法从一次运行中推断出结果。使用 Google Caliper 之类的东西正确地进行微基准测试,这将为您生成各种有用的指标(标准偏差等),以及许多重要的技术内容(预热 JVM,以便字节码可能得到优化)。

除了 assylias 的回答 - 做 IO 可能会对您的结果产生巨大影响。在没有图形 UI 且运行的服务数量最少的操作系统上运行也是一种很好的做法。

阅读Caliper wiki 了解最佳实践微基准测试并查看source for examples

编辑:对于 1.0-beta-1 版本,请检查 branch for examples,API 正在更改,并且 master 与文档不匹配)

【讨论】:

    【解决方案2】:

    您的测试方法存在几个问题,但主要是:

    • System.currentMillis() 的分辨率不是很好,所以考虑到你的结果都是 12ms,我不相信他们
    • 测量期间运行完整的 GC,这没有任何意义:GC 本身可能需要几毫秒

    所以:

    • 使您的数组显着变大 - 例如,您可以运行大小从 10,000 到 10,000,000 的测试,以 10,000 为增量进行测试
    • 将 GC 移到 之前 long startTime = System.currentTimeMillis();

    【讨论】:

    • 感谢您的回复,您是对的,我在开始计时后正在进行垃圾收集,因此我在上图中得到了结果。我在计时之前移动了 gc 并针对非常大的数组数(1000 万 + )运行循环并获得了有用的结果!谢谢
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-08
    • 1970-01-01
    • 2021-08-22
    • 2017-05-16
    相关资源
    最近更新 更多