点:将问题抽象,对应到能完成功能的数据结构算法
题意:如rpc server,rpcid是从1-N的正整数不重复,先后接收到rpcid为3、1、5、2、4、8、6、7的消息,即乱序接收,但它必须做到按顺序返回相应部分的返回,
比如对于3、1、5、2、4、8、6、7的接收顺序,rpc server的返回顺序应该是1、2、3(接收到2时)和4、5(接收到4时)和6、7、8(接收到7时)
来自程序员代码面试指南
思路:即接收到哪个id时,要判断它之前的部分是否已经接收过,如果接收过就全部打印,否则要等”连成片“后,比如初始接收到了3不能返回,因为1、2都没出现过呢,再出现了1也不能返回,因为2还没出现,当出现2时,判断1、2、3已经是从1开始的连续区间,此时可以返回1、2、3,后面最小输出起点是4,而出现5时不能返回,因为4还未出现,当出现4,则4、5可返回
基于这个情况,可见rpc server需要能够先暂存不能输出的,并且接收到新的时候要判断是否符合返回条件,以及暂存的数据是否形成连续空间需要连续输出,直到出现断点为止
一个很简单的办法就是,stl的set,set基于二叉排序树(红黑树),将需要暂存不能返回的rpcid保存在这里,并初始化时记录一个当前返回起点标志,每次接收到数据时:
1、塞入set
2、判断set的最小元素,是否比当前返回起点标志大1
如果不符合:结束
如果已符合:将set内的rpcid挨个返回,同时每返回一个rpcid时(返回后要在set中删除掉这个元素),更新当前返回起点标志,下次遍历set时要判断是否符合比当前返回起点标志大1
代码:
#include <iostream>
#include <set>
class MessageProcesser {
int lastprint;
std::set<int> rangemap;
public:
MessageProcesser():lastprint(0) {}
~MessageProcesser () {
rangemap.clear();
}
void recv (int rpcid) {
if (rpcid < 1) {
return;
}
rangemap.insert(rpcid);
std::set<int>::iterator it = rangemap.begin();
if (*it - lastprint == 1) {
send();
}
}
void send () {
std::set<int>::iterator it = rangemap.begin();
for (; it != rangemap.end();) {
if (*it - lastprint == 1) {
std::cout << *it << "\t";
++lastprint;
it = rangemap.erase(it);
} else {
it++;
}
}
std::cout << std::endl;
}
};
int main () {
MessageProcesser mp;
mp.recv(5);
mp.recv(2);
mp.recv(3);
mp.recv(1);
mp.recv(7);
mp.recv(4);
mp.recv(6);
return 0;
}