《算法导论》10.2-6 动态集合操作Union以两个不相交集合S1和S2作为输入,并返回集合S = S1∪S2。该操作通常会破坏集合S1和S2。试说明如何选用一种合适的表类数据结构,来支持O(1)时间的Union操作。
O(1)时间能干嘛?不能移动元素,只能改改指针,所以采用链表最合适,这道题采用单链表就够了。
我在之前定义的SingleLinkedList类型里面声明一个friend function。注意声明为friend 的class or function不可以是template,必须是实例化类型或方法,所以用
friend SingleLinkedList Union<Object>(SingleLinkedList&& lhs,SingleLinkedList&& rhs);
而不是friend SingleLinkedList Union(SingleLinkedList&& lhs, SingleLinkedList&& rhs);
。
//将模板函数Union声明为class SingleLinkedList的友元函数
template<typename Object> class SingleLinkedList; //needed for parameters in Union
//forward declarations needed for friend declarations in SingleLinkedList
template<typename Object>
SingleLinkedList<Object> Union(SingleLinkedList<Object>&& lhs,
SingleLinkedList<Object>&& rhs);
template<typename Object>
class SingleLinkedList
{
//in order to refer to a specific instantiation of the template function "Union", "<Object>" is needed
friend SingleLinkedList Union<Object>(SingleLinkedList&& lhs,
SingleLinkedList&& rhs);
//...[main part of class definition ](https://www.cnblogs.com/meixiaogua/p/10175608.html)
}
//定义Union
/*我一开始把返回值定义成&&了,那样是不对的
因为函数Union返回相当于是在执行 SingleLinkedList<Object>&& temp = std::move(u);
u告诉我们自己的资源可以被偷走,然后把资源位置写到temp变量中,然后u的资源就被函数销毁了。
就相当于temp里面记录的资源位置还没来得及被人注意到,那个资源就失效了
正确的方法是定义返回值类型为SingleLinkedList<Object>*/
template<typename Object>
SingleLinkedList<Object> Union(SingleLinkedList<Object>&& lhs,
SingleLinkedList<Object>&& rhs)
{
SingleLinkedList<Object> u(std::move(lhs));
if(!rhs.empty())
{
u.sentinelPrev->next = rhs.sentinel->next;
rhs.sentinelPrev->next = u.sentinel;
u.sentinelPrev = rhs.sentinelPrev;
rhs.sentinel->next = rhs.sentinelPrev = rhs.sentinel;
}
return std::move(u);
}
void testUnion()
{
using namespace std;
SingleLinkedList<int> a,b;
for(int i = 0; i != 4; ++i)
a.push_back(i);
for(int i = 10; i != 14; ++i)
b.push_back(i);
auto r = Union(std::move(a),std::move(b));
decltype(a) u(std::move(r));
while(!u.empty())
{
cout << u.front() << " ";
u.pop_front();
}
cout << endl;
}
//测试输出
0 1 2 3 10 11 12 13