区间划分操作
区间划分操作
输入几个区间,根据已知区间的边界,划分成更小的区间,比如有区间:
[1,1] [2,2] [3,8] [5,7] [7,9]
我们希望重新划分得到的结果为:
[1,1] [2,2] [3,5] [5,7] [7,7] [7,8] [8,9]
我们的基本做法是首先定义边界结构体,边界分为两种情况:左边界和右边界。
区间划分函数,我们是首先按照各个边界在数轴上的排序,从小到大依次排列,然后顺序检测当前区间边界为左边界还是右边界,然后再检测上一个边界是左边界还是右边界。根据各种情况进行相应的操作。
程序中,我们的区间划分函数有两个版本,其中第二个版本是严格按照上述思想进行的实现。第一个版本,同样是想记录上一个边界,但是我们还设定了UNKNOWN状态,既然是记录上一个边界,那么状态只有LEFT和RIGHT两种状态,不可能有UNKNOWN状态。这里的UNKNOWN其实是指未来下一个边界的状态。我们用来记录上一个边界的变量充当了两个角色:上一个边界和未来下一个边界。但是,实质上完全可以由只记录上一个边界来替代。
该算法首先对原来的边界进行了排序,排序的时间复杂度为O(NlogN),其中N为区间个数,进行当前边界和上一个边界状态的检测操作是一个循环,其时间复杂度为O(N),N为区间个数。所以总的时间复杂度为O(NlogN),N为区间个数。
具体细节详见程序和注释。
// 区间划分 #include <iostream> #include <vector> #include <algorithm> #include <cassert> using namespace std; const int LEFT = 1; const int RIGHT = 2; const int UNKNOWN = 0; class Border { private: double bor; int mark; public: Border(double d = 0.0, int m = LEFT) : bor(d), mark(m) {} double Bor() const { return bor; } int Mark() const { return mark; } friend bool operator < (const Border& lhs, const Border& rhs); friend bool operator == (const Border& lhs, const Border& rhs); }; bool operator < (const Border& lhs, const Border& rhs) { if (lhs.bor < rhs.bor) { return true; } else if (lhs.bor == rhs.bor && lhs.mark < rhs.mark) { return true; } else { return false; } } bool operator == (const Border& lhs, const Border& rhs) { return lhs.bor == rhs.bor && lhs.mark == rhs.mark; } void ReadIntervals(vector<Border>& itvs) { itvs.clear(); double a = 0.0, b = 0.0; while (cin >> a >> b) { assert(a <= b); itvs.push_back(Border(a, LEFT)); itvs.push_back(Border(b, RIGHT)); } } void PrintRawIntervals(const vector<Border>& itvs) { for (auto i = 0; i < itvs.size() - 1; i += 2) { cout << '[' << itvs[i].Bor() << ',' << itvs[i + 1].Bor() << ']' << ' '; } cout << endl; } void Repartition(const vector<Border>& itvs, vector<Border>& rep) { assert(itvs.size() > 0 && itvs.size() % 2 == 0); vector<Border> bef(itvs); rep.clear(); sort(bef.begin(), bef.end()); int bor = bef[0].Bor(); int mark = bef[0].Mark(); rep.push_back(Border(bor, mark)); for (auto i = 1; i < bef.size(); ++i) { if (bef[i].Mark() == RIGHT) // 如果当前是右界 { if (mark == LEFT) // 前一个边界为LEFT { // 直接将当前边界保存 // 但是不知道该界是否是LEFT还是RIGHT rep.push_back(bef[i]); bor = bef[i].Bor(); mark = UNKNOWN; } else if (mark == RIGHT) // 如果前一个边界为RIGHT { // 这种情况不考虑 // 因为不会出现 // 如果删除UNKNOWN,可以用RIGHT代替 // 如果用RIGHT是表示上一个的状态 // 如果用UNKNOWN是表示将来的状态 } else if (mark == UNKNOWN) { // 当前为RIGHT,前一个未知,则可以推算前一个为LEFT rep.push_back(Border(bor, LEFT)); rep.push_back(bef[i]); bor = bef[i].Bor(); mark = UNKNOWN; } } else if (bef[i].Mark() == LEFT) // 当前为左界 { if (mark == LEFT) // 之前也为LEFT { // 将当前作为右界保存 // 保存当前界 // 记录当前界 rep.push_back(Border(bef[i].Bor(), RIGHT)); rep.push_back(bef[i]); mark = LEFT; bor = bef[i].Bor(); } else if (mark == RIGHT) // 上一个为右界 { // 保存当前 // 记录当前 rep.push_back(bef[i]); mark = LEFT; bor = bef[i].Bor(); } else if (mark == UNKNOWN) // 上一个未知 { // 保存当前 // 记录当前 rep.push_back(bef[i]); mark = LEFT; bor = bef[i].Bor(); } } } } // 重写区间划分函数,严格按照LEFT、RIGHT两种状态 void Repartition2(const vector<Border>& itvs, vector<Border>& rep) { assert(itvs.size() > 0 && itvs.size() % 2 == 0); vector<Border> bef(itvs); rep.clear(); sort(bef.begin(), bef.end()); int premark = bef[0].Mark(); int prebor = bef[0].Bor(); rep.push_back(bef[0]); for (auto i = 1; i != bef.size(); ++i) { if (bef[i].Mark() == LEFT) // 如果当前为左界 { if (premark == RIGHT) // 如果上一个为右界 { // 将当前保存,修改上一个 rep.push_back(bef[i]); premark = bef[i].Mark(); prebor = bef[i].Bor(); } else if (premark == LEFT) // 如果上一个为左界 { // 将当前作为右界保存 // 并保存当前为左界 // 修改上一个 rep.push_back(Border(bef[i].Bor(), RIGHT)); rep.push_back(bef[i]); premark = bef[i].Mark(); prebor = bef[i].Bor(); } else { ; } } else if (bef[i].Mark() == RIGHT) // 如果当前为右界 { if (premark == LEFT) // 如果上一个为左界 { // 将当前保存 // 修改上一个 rep.push_back(bef[i]); premark = bef[i].Mark(); prebor = bef[i].Bor(); } else if (premark == RIGHT) // 如果上一个为右界 { // 将上一个作为左界保存 // 并将当前保存 // 保存下一个 rep.push_back(Border(prebor, LEFT)); rep.push_back(bef[i]); premark = bef[i].Mark(); prebor = bef[i].Bor(); } else { ; } } else { ; } } } // 输出规则化的区间 void PrintRegularIntervals(const vector<Border>& rep) { for (auto i = 0; i < rep.size(); ++i) { if (rep[i].Mark() == LEFT) { cout << '[' << rep[i].Bor() << ','; } else if (rep[i].Mark() == RIGHT) { cout << rep[i].Bor() << ']' << ' '; } else { cout << '*' << rep[i].Bor() << '*'; } } cout << endl; } int main() { vector<Border> itvs; ReadIntervals(itvs); PrintRawIntervals(itvs); PrintRegularIntervals(itvs); cout << endl; vector<Border> rep; Repartition2(itvs, rep); PrintRawIntervals(rep); PrintRegularIntervals(rep); return 0; }
(完)
文档信息
·版权声明:自由转载-非商用-非衍生-保持署名 | Creative Commons BY-NC-ND 3.0
·博客地址:http://www.cnblogs.com/unixfy
·博客作者:unixfy
·作者邮箱:goonyangxiaofang(AT)163.com
·如果你觉得本博文的内容对你有价值,欢迎对博主 小额赞助支持