这道习题让我纠结了一整天。在写Intset的添加元素的push成员函数时,我一下走进了思维误区。直到晚上无意间看到了C++Primer 16章的Queue类之后才犹如醍醐灌顶。问题在于我把empty()函数写砸了。我原先是这样写的:
bool Intset::empty() const
{
return beg==end;
}
然而,这样的一个empty函数将导致在添加第一个元素时陷入困境。在添加第一个元素时
if(empty())
beg=end=newElement;
empty显示容器仍然为空。而事实上,容器已经有一个元素了。
这样以后我绞尽脑汁写了一个更别扭的:
if(empty())
{
beg=newElement;
beg->next=end;
}
这样,容器“不再为空”了。但是在添加第二个元素时,你会发现一个惊人的事实:你无法写出添加第二个元素的代码。
if(!empty())
.....//这里竟然会无法实现。
这是很正常的。因为,end指针此时为0,而不是指向尾元素。这导致end指向了“尾元素的下一位置”,而beg却指向了尾元素。这显然是链表出现了结构错误。
正确的empty()应该是:
bool Intset::empty() const
{
return beg==0;
}
还有,del函数也相当关键。我也思考了不少时间。
//9.(*3)定义、实现并测试一个整数集合的类Intset,提供并、交和对称差等操作。
//10.(*1.5)将类Intset修改为一个结点Node的集合。其中Node是你定义的一种struct。#include <iostream>
#include <stdexcept>
using namespace std;
struct Node{
Node(int ival):i(ival),next(0){}
Node* next;
int i;
};
class Intset{
public:
Intset():beg(0),end(0){}
~Intset();
bool push(int);
void del(Node*);
Node* find(int) const;
Intset setUnion(const Intset&) const;
Intset intersect(const Intset&) const;
Intset symmetricDifference(const Intset&) const;
bool empty() const{return beg==0;}
void print() const;
private:
Node *beg,*end;
};
Intset::~Intset()
{
Node* p=beg;
while(p){
Node* victim=p;
p=p->next;
delete victim;
}
}
bool Intset::push(int ival)
{
Node* pfind=find(ival);
if(pfind) return false;
Node* pn=new Node(ival);
if(empty())
beg=end=pn;
else{
end->next=pn;//核心语句:把pn链入Intset
end=pn; //让旧尾元素的next指针指向新尾元素,同时使end指向新尾元素。
}
}
void Intset::del(Node* ptr)
{
Node* p=beg;
while(p!=ptr&&p&&p->next!=ptr)
p=p->next;
if(p){
if(p==ptr){//要删除的是第一个元素
beg=beg->next;
}else if(ptr==end){
end=p;
end->next=0;
}else{
p->next=ptr->next;
}
delete ptr;
}else throw std::out_of_range("no such element");
}
Node* Intset::find(int ival) const
{
Node* p=beg;
while(p&&p->i!=ival) p=p->next;
return p;
}
Intset Intset::setUnion(const Intset& rhs) const
{
Intset ret;
for(Node* p=beg;p;p=p->next)
ret.push(p->i);
for(Node* p=rhs.beg;p;p=p->next)
ret.push(p->i);
return ret;
}
Intset Intset::intersect(const Intset& rhs) const
{
Intset ret;
for(Node* p=beg;p;p=p->next)
if(rhs.find(p->i))
ret.push(p->i);
return ret;
}
Intset Intset::symmetricDifference(const Intset& rhs) const
{
Intset ret;
for(Node* p=beg;p;p=p->next)
if(!rhs.find(p->i))
ret.push(p->i);
for(Node* p=rhs.beg;p;p=p->next)
if(!find(p->i))
ret.push(p->i);//不会导致重复:push()会检查重复性
return ret;
}
void Intset::print() const
{
for(Node* p=beg;p;p=p->next)
std::cout<<p->i<<'\t';
std::cout<<std::endl;
}
int main()
{
Intset a,b;
a.push(1);
a.push(2);
a.push(3);
a.print();
if(Node* p2=a.find(2))
a.del(p2);
a.print();
b.push(3);
b.print();
a.setUnion(b).print();
a.intersect(b).print();
a.symmetricDifference(b).print();
return 0;
}