我在做HW问题时发现了一些有趣的东西。
howework问题要求编码中位数维护算法。
正式声明如下:
此问题的目标是实施"中位维护"算法(在关于堆应用程序的第5周讲座中介绍)。文本文件包含未排序顺序的1到10000之间的整数列表;你应该把它视为一个数字流,一个接一个地到达。令x i 表示文件的i th 编号,k th 中间m k 定义为数字的中位数x 1 ,...,x k 。 (所以,如果k是奇数,那么m k 是(
th x 1 中的最小数,... ,x k ;如果k是偶数,那么m 1 是x 1 <中的(k / 2) th 最小数/子>,...,X <子>ķ子>。)
为了获得 O(n)运行时间,这应该明显地使用堆来实现。无论如何,我使用Brute Force编写了这个(截止日期太快,需要立即回答)( O(n 2 )),步骤如下:
我通过几个测试用例(已知答案)运行算法并得到了正确的结果,但是当我在更大的数据集上运行相同的算法时,我得到了错误的答案。我正在使用Int64 ro进行所有操作代表数据。 然后我尝试切换到Int32并且神奇地得到了正确的答案,这对我来说毫无意义。
代码如下,并且还找到here(数据在回购中)。该算法在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"));
}
更有趣的是,运行总和(在sum64变量中)产生的结果与使用LINQ的Sum()函数对列表中的所有项进行求和不同。
结果(第一个是错误的结果):
这些是计算机详细信息:
如果有人能给我一些关于为什么会发生这种情况的见解,我将不胜感激。
谢谢,
答案 0 :(得分:1)
0f正在初始化32位浮点变量,你的意思是0d或0.0来接收64位浮点数。
至于linq,如果你使用强类型列表,你可能会得到更好的结果。
new List<int>()
new List<long>()
答案 1 :(得分:1)
我注意到的第一件事是评论者做了什么:var sum64 = 0f
将sum64初始化为浮点数。由于Int64集合的中值本身就是Int64(指定的规则不使用偶数基数集合中两个中点值之间的平均值),您应该明确地将此变量声明为long
。实际上,我会继续在此代码示例中替换var
的所有用法; var
的便利性在这里导致与类型相关的错误。