【发布时间】:2015-03-09 18:34:48
【问题描述】:
我在做硬件问题时发现了一些有趣的东西。
howework 问题要求对中值维护算法进行编码。
正式声明如下:
这个问题的目标是实现“中值维护”算法(在第 5 周的堆应用讲座中介绍)。文本文件包含从 1 到 10000 的整数列表,未排序;您应该将其视为一串数字,一个接一个到达。令 xi 表示文件的第 ith 个编号,则 kth 中位数 mk 定义为数字 x1,…,xk 的中位数。 (所以,如果 k 是奇数,则 mk 是 ((k+1)/2)th x1 中最小的数,... ,xk;如果k是偶数,则m1是x1th个最小的数/sub>,…,xk.)
为了获得O(n)的运行时间,这显然应该使用堆来实现。无论如何,我使用蛮力进行了编码(截止日期太快,需要立即得到答案)(O(n2)),步骤如下:
- 读取 中的数据
- 排序数组
- 求中位数
- 将其添加到运行时间
我通过几个测试用例(具有已知答案)运行该算法并得到正确的结果,但是当我在更大的数据集上运行相同的算法时,我得到了错误的答案。我正在使用 Int64 ro 进行所有操作来表示数据。 然后我尝试切换到 Int32,神奇地我得到了正确的答案,这对我来说毫无意义。
代码在下面,也找到了here(数据在repo里)。算法在 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() 函数对列表中的所有项目求和产生的结果不同。
结果(第三个是错误的):
这些是计算机详细信息:
如果有人能给我一些关于为什么会发生这种情况的见解,我将不胜感激。
谢谢,
【问题讨论】:
-
尽管有这个名字,
Convert类并不是在已知类型之间转换数据的好方法。您是否从Convert.ToInt32和Convert.ToInt64得到不同的结果?如果您改用Int32.TryParse和Int64.TryParse,您会遇到任何故障吗?那么有什么不同吗? -
0f 正在初始化一个 32 位浮点变量,您的意思是 0d 或 0.0 接收 64 位浮点数。
-
@BenVoigt Convert.ToInt32/64 的结果产生相同的数字,总和是不同的。而且我还没有尝试使用 TryParse 进行转换。
-
@jtimperley:他们根本不需要浮点数。所有的数字都是整数,所以他们应该保持整数。他们可能想要
0L,或者,只使用显式类型而不是var。 -
对于 linq,如果你使用强类型列表,你可能会得到更好的结果。新列表
和新列表 。对于最后一条评论,他们不应该需要这么多,但我没有做他们的功课,只是指出他们的错误。
标签: c# algorithm integer int64 int32