题目描述:假设两个线性表t1, t2均从小到大排序,给出求这两个线性表的交集和并集的算法。
题目分析:
本题很简单,因为是线性表,且已排过序,所以很容易给出一个O(m+n)的算法来,并且是一个很适合递归的实现。
比如考虑求交集,我们可以用下面的代码来实现:
template <typename LinearTableIter, typename LinearTable>
void intersection(LinearTableIter t1_begin, LinearTableIter t1_end,
LinearTableIter t2_begin, LinearTableIter t2_end,
LinearTable& t)
{
if (t1_begin != t1_end && t2_begin != t2_end) {
if (*t1_begin == *t2_begin) {
t.push_back(*t1_begin);
intersection(++t1_begin, t1_end, ++t2_begin, t2_end, t);
} else if (*t1_begin < *t2_begin) {
intersection(++t1_begin, t1_end, t2_begin, t2_end, t);
} else {
intersection(t1_begin, t1_end, ++t2_begin, t2_end, t);
}
}
}
这里做了两个表中的数据满足严格的偏序关系的假设。虽然对于已排序的线性表来说,不一定满足这个条件。但是因为求交和求并都是集合运算,对于两个集合来说,应该满足集合元素的互易性,在这种考虑下该假设是合理的。如果单纯是求两个线性表的公共元素而允许线性表中含有相同元素的话,可以将sort()之后的两个表用unique()处理一下,进而使用该算法。应注意的是,这里不考虑在代码中加入考虑非严格偏序元素处理的修正的原因在于:unique()本身也是个O(n)的算法,因此,调用它并没有显著的增加复杂度。另外更重要的是,即使考虑了修正,也只是把unique()做的事情并入到前述算法中,并未降低运算的复杂度,反而违反了KISS哲学。故我们将其分为两个方法来实现。
求并集的思路和求交集类似,也是用一个简单的递归思想完成的。要注意的地方是求交集的时候,两个表中的任何一个结束,计算就结束了;而求并集的时候,要所有的表都结束了,运算才能结束。可以用下面的代码来实现:
template <typename LinearTableIter, typename LinearTable>
void make_union(LinearTableIter t1_begin, LinearTableIter t1_end,
LinearTableIter t2_begin, LinearTableIter t2_end,
LinearTable& t)
{
if (t1_begin != t1_end && t2_begin != t2_end) {
if (*t1_begin == *t2_begin) {
t.push_back(*t1_begin++);
t2_begin++;
} else if (*t1_begin < *t2_begin)
t.push_back(*t1_begin++);
else
t.push_back(*t2_begin++);
make_union(t1_begin, t1_end, t2_begin, t2_end, t);
}
while (t1_begin != t1_end)
t.push_back(*t1_begin++);
while (t2_begin != t2_end)
t.push_back(*t2_begin++);
}