分布式系统中的RPC请求经常出现乱序的情况。
写一个算法来将一个乱序的序列报序输出,列如,假设起始序号是1,对于(1,2,5,8,10,4,3,6,9,7)这个序列,输出是
1
2
3,4,5
6
7,8,9,10
上述例子中,3到来的时候发现4,5已经在了,因此将已经满足顺序的整个序列(3,4,5)输出为一行。
要求:
1.写一个高效的算法完成上述功能,实现要求尽可能的健壮,易于维护
2.为该算法完成单元测试。
我的思路肯定不是最佳的,只是实现了而已,如果有更好的思路和优化请发送到评论区,谢谢~
先说下我的思路:
题目说了是RPC请求,那么在发送过程中发送的包序号应该是1,2,3,4...,这里应该不用考虑丢包吧 - -。
那么这个乱序的序号,实际上就是顺序的序号打乱了,所以按顺序输出后不可能出现1,2,4,5...类似这种情况。
接着看给出的序列是1到10乱序,输出却是顺序的,只不过分块输出了。
看看输出结果可能没什么头绪,但是重点的一句话:
3到来发现4,5已经存在了,因此将满足顺序的整个序列(3,4,5) 输出为一行。
更重点的词:已经,满足顺序,一行。
已经存在说明3是在叫后面录入(分析的意思),4,5已经分析过了但是不满足输出条件而已。这里有个问题是为什么3到来发现4,5存在了输出,而不是4到来了发现
5已经存在了输出?
我认为1,2输出后,根据输出结果来看,是顺序输出的,肯定要输出3,所以一定要的等待3的出现才能顺序输出3,4,5。
那么我假设规则:依次读取每个数据,若读到的其中一个数据可以和前面输出过的符合顺序则输出。
后面就好解释了,1,2,3,4,5输出后剩余序列8,10,6,9,7。
读入8,10,不符合,到6了,和已经输出过的3,4,5符合顺序序列,单独输出6。
剩余序列8,10,9,7。
很简单直到读到7符合条件输出顺序序列7,8,9,10。
以上就是我思考的过程。罗嗦了...
我的解决方案:
每次选择开头元素和此刻最小元素的一个区间,在这个区间的元素和最小的元素可以构成顺序序列则输出。
举个例子,假设序列剩余(5,8,10,4,3,6,9,7),那么最小的元素是3。
区间是(5,8,10,4,3)。
分析可得3,4,5顺序序列,输出即可。然后删除元素3,4,5,再次选取最小元素和区间就是6了。每次选取最小元素的区间就可以连接上已经输出过的,保证是顺序的。
代码:
#include <iostream>
#include <vector>
#include <algorithm>
#include <set>
int main()
{
std::vector<int>ivec = {1,2,5,8,10,4,3,6,9,7};
std::set<int>iset;
while(!ivec.empty())
{
/* 选取最小元素 */
auto mid = min_element(ivec.begin(), ivec.end());
iset.insert(*mid);
/* 定义最小元素区间 */
std::vector<int>tmp(ivec.begin(), mid+1);
int t = *mid;
int del = *mid;
/* 查找和最小元素顺序的元素 */
while(1)
{
auto iter = find(tmp.begin(), tmp.end(), ++t);
if(iter != tmp.end())
{
iset.insert(*iter);
ivec.erase(remove(ivec.begin(), ivec.end(), t));
}
else
{
break;
}
}
ivec.erase(remove(ivec.begin(), ivec.end(), del));
/* 输出序列 */
auto end = --iset.end();
for(auto it = iset.begin(); it != end; ++it)
{
std::cout << *it << ",";
}
std::cout << *end << std::endl;;
iset.clear();
}
}