簡體   English   中英

中位數維護算法-根據Int32或Int64,相同的實現產生不同的結果

[英]Median Maintenance Algorithm - Same implementation yields different results depending on Int32 or Int64

我在做硬件問題時發現了一些有趣的東西。

howework問題要求對中位數維護算法進行編碼。

正式聲明如下:

這個問題的目標是實現“中位數維護”算法(在第5周關於堆應用程序的講座中介紹)。 文本文件包含從1到10000的整數列表(未排序)。 您應該將此視為一連串的數字,一一到達。 令x i表示文件的 i 數字,第k 中位數m k定義為數字x 1 ,…,x k的中值 (因此,如果k為奇數,則m k為x 1 ,…,x k中的 ((k + 1)/ 2) 最小數;如果k為偶數,則m 1為第(k / 2) 最小數x 1 ,…,x k中的數字 。)

為了獲得O(n)的運行時間,顯然應該使用堆來實現。 無論如何,我使用“蠻力”(截止日期太早,需要立即回答)( O(n 2 ))進行編碼,並執行以下步驟:

  1. 讀入數據
  2. 排序數組
  3. 查找中位數
  4. 將其添加到運行時間

我通過幾個測試用例(具有已知答案)運行了該算法,並獲得了正確的結果,但是當我在更大的數據集上運行相同的算法時,卻得到了錯誤的答案。 我正在使用Int64 ro代表數據進行所有操作。 然后我嘗試切換到Int32,神奇地得到了正確的答案,這對我來說毫無意義。

代碼在下面,也可以在此處找到(數據位於存儲庫中)。 在3810索引之后,該算法開始給出錯誤的結果:

    private static void Main(string[] args)
    {
        MedianMaintenance("Question2.txt");
    }

    private static void MedianMaintenance(string filename)
    {
        var txtData = File.ReadLines(filename).ToArray();
        var inputData32 = new List<Int32>();
        var medians32 = new List<Int32>();
        var sums32 = new List<Int32>();
        var inputData64 = new List<Int64>();
        var medians64 = new List<Int64>();
        var sums64 = new List<Int64>();
        var sum = 0;
        var sum64 = 0f;
        var i = 0;
        foreach (var s in txtData)
        {
            //Add to sorted list
            var intToAdd = Convert.ToInt32(s);

            inputData32.Add(intToAdd);
            inputData64.Add(Convert.ToInt64(s));

            //Compute sum
            var count = inputData32.Count;
            inputData32.Sort();
            inputData64.Sort();
            var index = 0;

            if (count%2 == 0)
            {
                //Even number of elements
                index = count/2 - 1;
            }
            else
            {
                //Number is odd
                index = ((count + 1)/2) - 1;
            }
            var val32 = Convert.ToInt32(inputData32[index]);
            var val64 = Convert.ToInt64(inputData64[index]);
            if (i > 3810)
            {
                var t = sum;
                var t1 = sum + val32;
            }
            medians32.Add(val32);
            medians64.Add(val64);
            //Debug.WriteLine("Median is {0}", val);
            sum += val32;
            sums32.Add(Convert.ToInt32(sum));
            sum64 += val64;
            sums64.Add(Convert.ToInt64(sum64));
            i++;
        }
        Console.WriteLine("Median Maintenance result is {0}", (sum).ToString("N"));
        Console.WriteLine("Median Maintenance result is {0}", (medians32.Sum()).ToString("N"));

        Console.WriteLine("Median Maintenance result is {0} - Int64", (sum64).ToString("N"));
        Console.WriteLine("Median Maintenance result is {0} - Int64", (medians64.Sum()).ToString("N"));
    }

更有意思的是,與使用LINQ的Sum()函數對列表中的所有項目求和相比,運行總和(在sum64變量中)產生的結果有所不同。

結果(第三個是錯誤的): 控制台應用程序結果

這些是計算機的詳細信息: 電腦詳情

如果有人可以給我一些見解,我將不勝感激。

謝謝,

0f正在初始化32位浮點變量,這意味着0d或0.0會接收64位浮點。

至於linq,如果使用強類型列表,可能會得到更好的結果。

new List<int>()
new List<long>()

我注意到的第一件事是注釋程序執行的操作: var sum64 = 0f將sum64初始化為浮點型。 由於Int64s集合的中位數本身就是Int64(指定的規則不使用偶數基數集合中兩個中點值之間的均值),因此您應該改為將變量明確聲明為long 實際上,我將繼續在此代碼示例中替換var所有用法; var的便利性在這里丟失了,導致了與類型相關的錯誤。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM