这个应该怎么求啊??
解决方案 »
- 双显卡,用WinForm怎样可以前后台切换呢?
- 一个数据库ED,让ED“分离”和“脱机”有什么区别,这两个SQL语句如何写
- 百度的农历日历,为什么拉到我的网页上汉字都变方框?
- 这个是什么语句是什么意思
- 关于TreeView的图标ImageIndex问题,请高手指点!
- Grid列隐藏的问题
- 100分求DataGrid,DataList,Repeater的写法,还有这几个控件有没有不绑定的写法??
- SQLSERVER如何得到某一天星期几
- 有两个小问题
- 请问如何获得一个Web窗体上点击的事件?
- 遍历指定文件夹中的文件,查看文件是否被修改(用修改日期标志)
- 关于Excel表格数据导入到Access数据库表中的问题
int[] Integer32 = 32亿个int;
int[] integer = new int[Integer32.Length];
int couter;for (uint i = 0 ; i <= 320000000;i++)
{
couter = 0;
foreach (int j in Integer32)
{
if (Integer32[i] == j)
{
couter++;
if (couter >1)
{
integer[couter-2] = j;
}
}
}
}
不过即到这一步只有往下走了。1. 如果重复的数特别多,可以用三楼的办法,分段。重复的数不多的话,不行。
2. 如果某数特别多,直接删除这个数。
3. 想想有没有其它的规律。
4. 如果实在没有什么规律,可以新建一个文件,大小是0xffffffff*4,正好能装下所有的32位整数, 从原文件中取数,存到这个数对应的位置。完成后把所有的零删掉。(保留第一个零)。
5. 借鉴排序算法。
6. 前面的路走错了,后面就不好办了,把前面的程序改一改吧。
因为只需要知道哪些数是重复的,而不需要知道重复多少次,所以,我们可以利用bit来记录。首先创建一个390625K大小的文件(称为bit文件),也就是32亿个bit(如果内存够大,也可以直接开1亿个int型数组,在内存里操作速度要快得多)。
然后开始读取文件中的数值,读取到一个数值后,根据这个数值定位到指定bit的位置,设置该bit的值为1(初始值都是0),循环执行,直到全部读完。
最后,从bit文件(或内存数组)中一次读取bit信息,根据bit的位置即可知道相应的数值是多少,如果该bit的值为1,则输出该数字(表示该数字重复)。完成。
结果[32亿]for ( i=0;i<32亿;i++)
{
结果[数据[i]]++;
}结果[32亿]=所有数字重复数 只要有硬盘空间没什么大问题。
不要说在文件里,即使是放在本地sql server的表里,用sql语句查重复数也会死上N久的吧
const int Groups = 10000; // 将32亿数据分组,这个数可以调整,但应当能够被32亿整除byte exist[32亿 / Groups]; // 0: 不存在;1:找到1个;2找到多个// 分组后(注:将32位整数看做无符号的,不会影响计算结果)
// 第0组范围exist.Length * 0 ~ exist.Length * 1 (不包含右边的值)
// 第1组范围exist.Length * 1 ~ exist.Length * 2 (不包含右边的值)
// ....
// 最后1组的范围exist.Length * (Groups - 1) ~ exist.Length * Groups (不包含右边的值)for (int g = 0; g < Groups; g++)
{
for (int n = 0; n < result.Length; n++)
{
exist[n] = 0;
} // 第g组的范围
uint minValue = exist.Length * g;
uint maxValue = (exist.Length * g - 1) + exist.Length; // 不要用exist.Length * (g + 1) - 1,否则运算结果会溢出 // 每次从磁盘读入1MB的数据,并转换为256 * 1024个无符号整数(数量同样可以调整)
[byte buffer[1024 * 1024] => uint data[256 * 1024]] foreach (int value in data)
{
// 分析本次分组范围内的数据
if ((value >= minValue) && (value <= maxValue))
{
// 找到第1个
if (exist[value - minValue] == 0)
{
exist[value - minValue] = 1;
continue;
} // 找到第2个(后面再找到不需要再处理了)
if (exist[value - minValue] == 1)
{
exist[value - minValue] = 2; output: value
continue;
}
}
}
}[/Code]上面的算法中核心概念是分组处理,并且有两处可调整的大小,能够很好的平衡时间和空间的关系。
const int Groups = 10000; // 将32亿数据分组,这个数可以调整,但应当能够被32亿整除 byte exist[32亿 / Groups]; // 0: 不存在;1:找到1个;2找到多个 // 分组后(注:将32位整数看做无符号的,不会影响计算结果)
// 第0组范围exist.Length * 0 ~ exist.Length * 1 (不包含右边的值)
// 第1组范围exist.Length * 1 ~ exist.Length * 2 (不包含右边的值)
// ....
// 最后1组的范围exist.Length * (Groups - 1) ~ exist.Length * Groups (不包含右边的值) for (int g = 0; g < Groups; g++)
{
for (int n = 0; n < [Color:#00000FF]exist.Length[/Color]; n++)
{
exist[n] = 0;
} // 第g组的范围
uint minValue = exist.Length * g;
uint maxValue = (exist.Length * g - 1) + exist.Length; // 不要用exist.Length * (g + 1) - 1,否则运算结果会溢出 // 每次从磁盘读入1MB的数据,并转换为256 * 1024个无符号整数(数量同样可以调整)
[byte buffer[1024 * 1024] => uint data[256 * 1024]] foreach ([Color:#00000FF]uint[/Color] value in data)
{
// 分析本次分组范围内的数据
if ((value >= minValue) && (value <= maxValue))
{
// 找到第1个
if (exist[value - minValue] == 0)
{
exist[value - minValue] = 1;
continue;
} // 找到第2个(后面再找到不需要再处理了)
if (exist[value - minValue] == 1)
{
exist[value - minValue] = 2; output: value
continue;
}
}
}
} [/C# Code] 上面的算法中核心概念是分组处理,并且有两处可调整的大小,能够很好的平衡时间和空间的关系。
因为只需要知道哪些数是重复的,而不需要知道重复多少次,所以,我们可以利用bit来记录。 首先创建一个512M大小的文件(称为bit文件),也就是32亿个bit(如果内存够大,也可以直接开2亿个int型数组,在内存里操作速度要快得多)。
然后开始读取文件中的数值,读取到一个数值后,根据这个数值定位到指定bit的位置,读取该位置的bit值,如果设置该bit的值为1(初始值都是0),则输出该数字(或保存到另一个文件中),否则设置该bit的值为1,循环执行,直到全部读完,重复数字也就出来了。 完成。至于说用排序的办法,我觉得是浪费资源。一是在这里顺序无意义,二是排序需要多次的倒来倒去,需要的时间更多,而且排完序以后,仍然要将这些数据重新读一遍,并判重和输出,多干了很多事。
这个方法是有问题的,因为BIT的2个状态是不够用的,请参考我在22楼写的代码。实际上需要保持3个状态:
(1) 计数为0个;(2) 计数为1个;(3)计数为多个按照Foxer的算法,计数1个时置1,计数2个时输出,那么计数3个、4个时同样也只能输出,因为你不知道自己是第几次重复,是不是这样?
const int Groups = 10000; // 将32亿数据分组,这个数可以调整,但应当能够被32亿整除 byte exist[32亿 / Groups]; // 0: 不存在;1:找到1个;2找到多个 // 分组后(注:将32位整数看做无符号的,不会影响计算结果)
// 第0组范围exist.Length * 0 ~ exist.Length * 1 (不包含右边的值)
// 第1组范围exist.Length * 1 ~ exist.Length * 2 (不包含右边的值)
// ....
// 最后1组的范围exist.Length * (Groups - 1) ~ exist.Length * Groups (不包含右边的值) for (int g = 0; g < Groups; g++)
{
for (int n = 0; n < exist.Length; n++)
{
exist[n] = 0;
} // 第g组的范围
uint minValue = exist.Length * g;
uint maxValue = (exist.Length * g - 1) + exist.Length; // 不要用exist.Length * (g + 1) - 1,否则运算结果会溢出 // 每次从磁盘读入1MB的数据,并转换为256 * 1024个无符号整数(数量同样可以调整)
[byte buffer[1024 * 1024] => uint data[256 * 1024]] foreach (int value in data)
{
// 分析本次分组范围内的数据
if ((value >= minValue) && (value <= maxValue))
{
// 找到第1个
if (exist[value - minValue] == 0)
{
exist[value - minValue] = 1;
continue;
} // 找到第2个(后面再找到不需要再处理了)
if (exist[value - minValue] == 1)
{
exist[value - minValue] = 2; output: value
continue;
}
}
}
} 上面的算法中核心概念是分组处理,并且有两处可调整的大小,能够很好的平衡时间和空间的关系。
吧你的数字都当做KEY,ADD进去(ADD前判断下KEY是否存在,存在就下一个)
hehe 也可以分段。
(2) 在该整型列上创建索引
(3) 剩下的事情就简单了,大家都会,不管你是去重,还是找重,数据库都能做得很好。海量数据如何存储?如何检索?数据库就是干这个的,不用我去动脑子。
如果本来就有序的话,那还是比较容易的从原文件里,一个INT 一个INT的读一遍就是了, 遇到重复的扔掉, 当原,两个INT一读,三个INT一读 都未尝不可
数据量很大的时候 Dictrinary会更慢的
32亿个啊
好像除了HashedTable,Dictionary<>应该是最快的了,SortedList在各种排序表里倒是最慢的
不排序的话 DIC数据量小的时候是快
但是数据量很大的话 查询和索引KEY的时候 SORTED才是快的
这么简单的问题不用费劲吧