我需要有关算法的帮助。我随机生成了6位数字。等;
123654 109431
它们中大约有100万个逐行保存在文件中。我必须按照我试着在下面描述的规则对它们进行过滤。
取一个数字,逐个数字地与其他数字进行比较。如果一个数字出现一个比较数字值大一的数字,则将其删除。让我用数字来表示。
我们的电话号码是:123456 使用1增加第一个数字,因此数字变为:223456。从文件中删除所有223456。 将第二个数字增加1,数字变为:133456。从文件中删除所有133456,依此类推......
我可以像我描述的那样去做,但我需要它是“快”。
所以有人可以帮我这个吗?
感谢。
答案 0 :(得分:5)
首先,由于它大约有1M亿,你最好在RAM中执行算法,而不是在磁盘上,即首先将内容加载到数组中,然后修改数组,然后将结果粘贴回文件中。
我建议使用以下算法 - 一个简单的算法。预先计算所有目标数字,在本例中为223456,133456,124456,123556,123466,123457。现在传递数组,如果数字不是其中任何一个,则将其写入另一个数组。或者,如果是其中一个数字,则将其删除(如果您的数据结构有O(1)删除,则建议使用
)答案 1 :(得分:1)
将文件中的所有数字转换为arrayList,然后:
将线程数作为位数
在第一个线程中增加第一个数字,在第二个线程中增加第二个数字,然后将其与其余数字进行比较,
通过并行处理将会很快......
答案 2 :(得分:1)
此算法会在内存中保留大量数字,但它会一次处理一个数字,因此您实际上不需要一次读取所有数据。您只需提供IEnumerable<int>
即可进行操作。
public static IEnumerable<int> FilterInts(IEnumerable<int> ints)
{
var removed = new HashSet<int>();
foreach (var i in ints)
{
var iStr = i.ToString("000000").ToCharArray();
for (int j = 0; j < iStr.Length; j++)
{
var c = iStr[j];
if (c == '9')
iStr[j] = '0';
else
iStr[j] = (char)(c + 1);
removed.Add(int.Parse(new string(iStr)));
iStr[j] = c;
}
if (!removed.Contains(i))
yield return i;
}
}
您可以使用此方法从文件中创建IEnumerable<int>
:
public static IEnumerable<int> ReadIntsFrom(string path)
{
using (var reader = File.OpenText(path))
{
string line;
while ((line = reader.ReadLine()) != null)
yield return int.Parse(line);
}
}
答案 3 :(得分:1)
所有建议(到目前为止)都要求每个输入行进行六次比较,这是不必要的。数字以字符串形式出现,因此请使用字符串比较。
从@Armen Tsirunyan的想法开始:
预先计算所有目标数字, 在这种情况下,223456,133456,124456, 123556,123466,123457。
但不是单一比较,而是将其变成一个字符串:
string arg = "223456 133456 124456 123556 123466 123457";
然后读取输入(来自文件或内存)。伪代码:
foreach (string s in theBigListOfNumbers)
if (arg.indexOf(s) == -1)
print s;
这只是每个输入行的一个比较,没有字典,地图,迭代器等。
已编辑添加:
在x86指令集处理器(不仅仅是英特尔品牌)中,像这样的子字符串搜索是非常快。例如,要搜索字符串中的字符,只需要一条机器指令。
我必须要求其他人权衡其他架构。
答案 4 :(得分:0)
对于初学者,我只是将所有数字读入数组。
当你最终完成时,重写文件。
答案 5 :(得分:0)
您所描述的规则似乎是您想要查找包含+ 1,b + 1,c + 1,d + 1,e + 1或f + 1的所有数字的目标编号abdcef在适当的地方。您可以在O(n)中通过循环文件中的行并将六位数中的每一位与目标数字中的数字进行比较(如果没有数字匹配),将数字写入输出文件。
答案 6 :(得分:0)
这听起来像是多维数组的潜在情况,也可能是不安全的c#代码,因此您可以使用指针数学来迭代如此大量的数字。
我将不得不深入研究它,但如果你要比较不按顺序排列的数字,我也可能会使用字典进行非线性查找。
答案 7 :(得分:0)
从文件中读取所有数字并将其存储在数字为键的地图中,布尔值表示该值尚未删除。 (True表示存在,false表示删除)。
然后遍历你的密钥。对于每个键,将映射设置为false,以表示要从列表中删除的值。
再次遍历列表并获取值为true的所有键。这是剩余数字的列表。
public List<int> FilterNumbers(string fileName)
{
StreamReader sr = File.OpenTest(fileName);
string s = "";
Dictionary<int, bool> numbers = new Dictionary<int, bool>();
while((s = sr.ReadLine()) != null)
{
int number = Int32.Parse(s);
numbers.Add(number,true);
}
foreach(int number in numbers.Keys)
{
if(numbers[number])
{
if(numbers.ContainsKey(100000+number))
numbers[100000+number]=false;
if(numbers.ContainsKey(10000+number))
numbers[10000+number]=false;
if(numbers.ContainsKey(1000+number))
numbers[1000+number]=false;
if(numbers.ContainsKey(100+number))
numbers[100+number]=false;
if(numbers.ContainsKey(10+number))
numbers[10+number]=false;
if(numbers.ContainsKey(1+number))
numbers[1+number]=false;
}
}
List<int> validNumbers = new List<int>();
foreach(int number in numbers.Keys)
{
validNumbers.Add(number);
}
return validNumbers;
}
这可能需要测试,因为我在这台计算机上没有C#编译器,而且我有点生疏。该算法将在线性时间内运行一些内存位。
**编辑** 只要其中一个数字为9,就会遇到问题。我稍后会更新代码。
答案 8 :(得分:0)
这个怎么样?您逐个处理数字。数字将存储在哈希表NumbersOK
和NumbersNotOK
中。
NumbersNotOK
中,则将其置于NumbersOK
NumbersNotOK
。NumbersOK
成员,如果它们与任何差异匹配。NumbersOK
保存到文件中。这样您只需传递一次列表。哈希表仅用于此类目的,并且速度非常快(没有昂贵的比较方法)。
这个算法并不完整,因为当有一些数字重复时它没有处理,但它可以通过一些调整来处理......
答案 9 :(得分:0)
仍然听起来像是一个家庭作业问题......一百万个数字的最快排序将是n log(n),即1000000log(1000000),即6 * 1000000,这与将6个数字与每个数字中的每一个进行比较相同数字。因此,直接比较将比排序和删除更快,因为在排序之后,您仍然需要比较以删除。除非,当然,我的计算完全错过了目标。
还有其他想法。当你拿起号码时,把它读作十六进制而不是基数10.然后也许一些按位运算符可能会以某种方式帮助。 还在考虑使用这个可以做些什么。如果有效则会更新
编辑:目前正在思考灰色代码。 123456(我们的原始号码)和223456或133456将只关闭一位数,灰色代码转换器将快速捕获它。现在已经很晚了,所以如果其他人觉得这很有用,可以给出解决方案......