求一道百度面试题的解 给你a、b两个文件,各存放50亿条url,每条url各占用64字节,内存限制是4G,让 你找出a、b文件共同的url。 解决方案 » 免费领取超大流量手机卡,每月29元包185G流量+100分钟通话, 中国电信官方发货 数量巨大~不知道存储格式是什么样的,如果是XML格式的,用XPATH查找比较应该比其它格式快点! 个人认为比较简单的(也容易讲清楚):1、先对a、b两个文件先进行外排序(计算复杂度约NLog(N),空间可限制在4G内)。2、对a、b两个文件用Streaming的方式找相同记录(计算复杂度为N,空间可限制在4G内)。ExternalSort("a.txt");ExternalSort("b.txt");//注,ReadLine可改成ReadBlock64之类。using( StreamReader aReader = new StreamReader("a.txt"))using (StreamReader bReader = new StreamReader("b.txt")){ string aLine = aReader.ReadLine(); string bLine = bReader.ReadLine(); while (aLine != null && bLine != null) { int diff = string.Compare(aLine, bLine); if (diff < 0) { aLine = aReader.ReadLine(); } else if(diff > 0) { bLine = bReader.ReadLine(); } else { Console.WriteLine(aLine); // output the matched line aLine = aReader.ReadLine(); bLine = bReader.ReadLine(); } }} 关键是排序 4G = 1024 * 1024 * 1024 * 4 byte 40亿 * 8 bit 比较的文件是 50亿 * 16bit 大概单个文件是 10G不能直接排序 需要分割文件 利用归并排序的方法1. 先分成10个小文件. 把每个小文件读入内存排序后写回去. 2. 对10个有序的文件再做一个多路归并的排序. C/C++ code //多路归并的外排序 //思路如下: //1.按各输入文件中下一个读到的元素的大小构造一个输入流最小堆. //2.从堆顶文件里读一个元素并写入输出文件. //3.同时按读的那个文件的下一个元素的值调整堆. //4.若第3步已到达文件结尾.则从堆中删除该输入流 //5 如果堆中还有元素. 回到第2步#include<iostream>#include<fstream>#include<vector>#include<algorithm>#include<iterator>#include<functional> using namespace std; //这个类主要用来管理一个输入流. //它知道流中还有没有元素. //可以查看下一个将读出来的元素的值. //可以读出一个元素. template <class T> class Yudu { private: istream & _istream; T _next; bool _have_next; public: Yudu( istream & x) : _istream(x) { if (_istream >> _next) _have_next = true; else _have_next = false; } inline bool have_next() { return _have_next; } //读出流中下一个元素 T read_next() { if (! _have_next) { cout << "读取错误! 退出" << endl; exit(1); } T temp = _next; if (_istream >> _next) _have_next = true; else _have_next = false; return temp; } //看看下一个元素但不读出来 inline const T& look_next() const { return _next; } }; //比较两个Yudu对象下一个元素的大小 //提供给paixu函数中的堆操作时使用 class bijiao { public: template <typename T> bool operator() (const Yudu<T>* a, const Yudu<T>* b) { return a->look_next() > b->look_next() ; } }; //文件排序函数 template <typename T> void paixu(vector<Yudu<T>* >& v , ostream& out){ //先删除数组中的"没有下一个元素"的Yudu对象.例如一个空的文件构造的Yudu对象. v.erase( remove_if(v.begin(),v.end(), not1(mem_fun(& Yudu<T>::have_next))), v.end() ); make_heap(v.begin(), v.end(), bijiao()); while (! v.empty() ){ pop_heap(v.begin(),v.end(), bijiao()); out << v.back()->read_next() << " "; // out 以文本方式打开. 如果是其它方式这里要改. if (! v.back()->have_next() ) v.pop_back(); else push_heap(v.begin(), v.end(), bijiao()); } } int main() { ifstream in[3]; in[0].open("1.txt"); in[1].open("2.txt"); in[2].open("3.txt"); vector<Yudu<int>* > v; v.push_back(new Yudu<int>(in[0])); //实际使用时要释放new出的对象.或者用boost的智能指针. v.push_back(new Yudu<int>(in[1])); v.push_back(new Yudu<int>(in[2])); ofstream o("out.txt"); paixu(v, o); cin.get(); return 0; } /* 测试(三个文件中是已经有序的数) 1.txt: 1 5 9 12 21 2.txt: 3 4 5 7 8 3.txt: 2 3 5 10 11 14 19 25 27 执行归并后 out.txt: 1 2 3 3 4 5 5 5 7 8 9 10 11 12 14 19 21 25 27 */排序后比较很简单 从两个文件慢慢读出来比较大小就好了呵呵,,我乱说的。。 牛人真多 继续学习ing... 使用线程分开读就成比如可以按字符顺序a线程读 以 字符 "a"开头滴 同时条件说明每条url各占用64字节,那么隐含着你可以使用 字节比较方式,可以做一些掩码判断工作 嗯,如果没有时间限制,就两个文件,一行一个行地读。从A中取一条url,然后再去遍历B每一条url,将相同的就放在C文件中。两个文件都是一条一条地读,这样功能能实现,内存限制可以忽视!以前见过类似的一题,不过没有内布限制,而是有时间限制,记得是先把文件分成若干个小文件,多线程来比,然后各个线程中又用hashtable来做比较的。当时不是url,而是话单 为什么是50亿 * 16bit呢?50亿 * 64byte,算出来是接近300G的一个数字不过这么大的文件的话,具体大小已经没有意义了 1.这是个除去冗余url的问题(假设50亿里面没有重复的A[50亿],B[50亿])。2.url全部可以视为2进制编码,不管什么东西,都是512个0,13.将50亿条按照前N位排序(N取决于经验值,比如前5位可以将50亿分成M组,每组最大1G或者更小,并创建索引,指示每组的起始位置。4.每次取A[50亿],B[50亿]进行交叉查找,除去相同的。———————————————————————————————— RPC 服务器不可用 150分求 C#做的在线邮件群发系统源码 C#代码重用 如何动态的把dbf数据库文件转换为mdf格式的文件? DateTimePicker的颜色设定 神奇的速度,C#导出到Excel,真的不是一般的慢啊。 纸张设置对话框,为什么一点确定页边距就会自动减小一点直到变为零 如何改变程序的启动顺序 C# 怎么取消一个事件 希望大家帮我解决, (已经附程序,请看一下) 谢谢!!!!!!!!!!!!!!!! 多线程同步读写文件怎么控制 跨越线程操作无效
1、先对a、b两个文件先进行外排序(计算复杂度约NLog(N),空间可限制在4G内)。
2、对a、b两个文件用Streaming的方式找相同记录(计算复杂度为N,空间可限制在4G内)。
ExternalSort("a.txt");
ExternalSort("b.txt");//注,ReadLine可改成ReadBlock64之类。
using( StreamReader aReader = new StreamReader("a.txt"))
using (StreamReader bReader = new StreamReader("b.txt"))
{
string aLine = aReader.ReadLine();
string bLine = bReader.ReadLine(); while (aLine != null && bLine != null)
{
int diff = string.Compare(aLine, bLine);
if (diff < 0)
{
aLine = aReader.ReadLine();
}
else if(diff > 0)
{
bLine = bReader.ReadLine();
}
else
{
Console.WriteLine(aLine); // output the matched line
aLine = aReader.ReadLine();
bLine = bReader.ReadLine();
}
}
}
关键是排序 4G = 1024 * 1024 * 1024 * 4 byte 40亿 * 8 bit
比较的文件是 50亿 * 16bit 大概单个文件是 10G
不能直接排序 需要分割文件 利用归并排序的方法1. 先分成10个小文件. 把每个小文件读入内存排序后写回去.
2. 对10个有序的文件再做一个多路归并的排序. C/C++ code
//多路归并的外排序
//思路如下:
//1.按各输入文件中下一个读到的元素的大小构造一个输入流最小堆.
//2.从堆顶文件里读一个元素并写入输出文件.
//3.同时按读的那个文件的下一个元素的值调整堆.
//4.若第3步已到达文件结尾.则从堆中删除该输入流
//5 如果堆中还有元素. 回到第2步
#include<iostream>
#include<fstream>
#include<vector>
#include<algorithm>
#include<iterator>
#include<functional>
using namespace std;
//这个类主要用来管理一个输入流.
//它知道流中还有没有元素.
//可以查看下一个将读出来的元素的值.
//可以读出一个元素.
template <class T>
class Yudu {
private:
istream & _istream;
T _next;
bool _have_next;
public:
Yudu( istream & x) : _istream(x) {
if (_istream >> _next) _have_next = true;
else _have_next = false;
}
inline bool have_next() { return _have_next; }
//读出流中下一个元素
T read_next() {
if (! _have_next) {
cout << "读取错误! 退出" << endl;
exit(1);
}
T temp = _next;
if (_istream >> _next)
_have_next = true;
else
_have_next = false;
return temp;
}
//看看下一个元素但不读出来
inline const T& look_next() const { return _next; }
};
//比较两个Yudu对象下一个元素的大小
//提供给paixu函数中的堆操作时使用
class bijiao
{
public:
template <typename T>
bool operator() (const Yudu<T>* a, const Yudu<T>* b) {
return a->look_next() > b->look_next() ;
}
};
//文件排序函数
template <typename T>
void paixu(vector<Yudu<T>* >& v , ostream& out){
//先删除数组中的"没有下一个元素"的Yudu对象.例如一个空的文件构造的Yudu对象.
v.erase( remove_if(v.begin(),v.end(),
not1(mem_fun(& Yudu<T>::have_next))), v.end() ); make_heap(v.begin(), v.end(), bijiao()); while (! v.empty() ){
pop_heap(v.begin(),v.end(), bijiao());
out << v.back()->read_next() << " "; // out 以文本方式打开. 如果是其它方式这里要改.
if (! v.back()->have_next() )
v.pop_back();
else
push_heap(v.begin(), v.end(), bijiao());
}
} int main() {
ifstream in[3];
in[0].open("1.txt");
in[1].open("2.txt");
in[2].open("3.txt"); vector<Yudu<int>* > v;
v.push_back(new Yudu<int>(in[0])); //实际使用时要释放new出的对象.或者用boost的智能指针.
v.push_back(new Yudu<int>(in[1]));
v.push_back(new Yudu<int>(in[2])); ofstream o("out.txt"); paixu(v, o); cin.get();
return 0;
} /*
测试(三个文件中是已经有序的数)
1.txt: 1 5 9 12 21
2.txt: 3 4 5 7 8
3.txt: 2 3 5 10 11 14 19 25 27 执行归并后
out.txt:
1 2 3 3 4 5 5 5 7 8 9 10 11 12 14 19 21 25 27
*/排序后比较很简单 从两个文件慢慢读出来比较大小就好了
呵呵,,我乱说的。。
以前见过类似的一题,不过没有内布限制,而是有时间限制,记得是先把文件分成若干个小文件,多线程来比,然后各个线程中又用hashtable来做比较的。当时不是url,而是话单
为什么是50亿 * 16bit呢?
50亿 * 64byte,算出来是接近300G的一个数字
不过这么大的文件的话,具体大小已经没有意义了
2.url全部可以视为2进制编码,不管什么东西,都是512个0,1
3.将50亿条按照前N位排序(N取决于经验值,比如前5位可以将50亿分成M组,每组最大1G或者更小,并创建索引,指示每组的起始位置。
4.每次取A[50亿],B[50亿]进行交叉查找,除去相同的。————————————————————————————————