已知一个消息流会不断地吐出整数1~N,但不一定按照顺序吐出。如果上次打印的数为i,那么当i+1出现时,请打印i+1及其之后接收过的并且连续的所有数,直到1~N全部接收并打印完,请设计这种接收并打印的结构。
消息流吐出 2,一种结构接收而不打印 2,因为 1 还没出现。
消息流吐出 1,一种结构接收 1,并且打印:1,2。
思路:维护一组连续的链,以及每个链的头和尾的map, 每次收到一个新的包,创建一个单元素的链,然后看有没有可以接上的。
class TCPReceiver {
private:
int last;
struct Node {
int seq;
Node* next;
Node(int seq) : seq(seq), next(NULL) {}
};
unordered_map<int, Node*> headMap, tailMap;
public:
TCPReceiver() : last(0) {};
void receive(int seq) {
Node* node = new Node(seq);
headMap[seq] = node;
tailMap[seq] = node;
auto it = tailMap.find(seq - 1);
if (it != tailMap.end()) {
it->second->next = node;
tailMap.erase(it);
headMap.erase(seq);
}
it = headMap.find(seq + 1);
if (it != headMap.end()) {
node->next = it->second;
tailMap.erase(seq);
headMap.erase(it);
}
if (headMap.find(last + 1) != headMap.end()) {
auto p = headMap[last + 1];
headMap.erase(last + 1);
for (; p; ++last) {
cout << p->seq << ' ';
auto next = p->next;
delete p;
p = next;
}
tailMap.erase(last);
cout << endl;
}
}
};
后续:之前的讨论太面向过程了。这个问题没那么玄,就是维护一堆连续的段,两个索引,使得通过头、尾都能查找到段,新来一个 seq, 用seq - 1查 段尾索引,用seq + 1去查 段头索引,找到相邻的段做合并。