原书对循环链表的介绍很简略,实现部分也不完整(当然了,如果完整就又是重复建设)。而我也没觉得循环链表有什么别的用,他更应该是为了一个特殊的问题而产生的,这只是个人的看法。我从链表类派生出了循环链表,这需要注意几个细节。
1. 构造函数:派生类实例化时,先调用基类的构造函数;因此,初始化循环链表的工作就是将带表头的空链表的表头节点的link指向表头节点,从而构成一个圈。
2. 析构函数:释放对象时,先调用派生类的析构函数,然后调用基类的析构函数。因此,释放循环链表只需要将循环链表变成普通的单链表,然后这个单链表会被基类的析构函数释放。这里假定不使用这种语句Base *p = new Drived;delete p;因为我在~List()前面没有加virtual。你可以参阅各种C++书籍搞清这类问题。
3. 判空函数:条件不是检测头节点的link是否为空,而是是否指向头节点。
4. 置空函数:原来的显然不能工作了,实际上只要从表头位置不断后删直到表空就可以了。
5. Next():遇到表头节点要跳过去。
6. Remove():当前节点是表头节点时不能删,删了表头节点的后果自己想吧(因为在循环链表中prior指针不一定为空——其实应该是一定不空,但是由于继承部分List函数,所以就是不一定了,以至于原来的Remove()检查可能无效);如果删除的是表尾节点,删除后当前指针将指向表头节点,要跳过去指向下一个。总之,使用Next()和Remove()时,不能让外界觉察到表头节点的存在,否则,当你循环计数时,表头节点就被算进去了。
7. “<<”必须重写,否则,当你执行cout << CircList;这种东西时,天哪,自己想去吧;当然了,只需要拷贝过来修改一下循环判断就可以了。
8. End()将不能工作,考虑到如果按照原来的功能来实现,效率很低,而且用处不大,所以修改End()功能定义为更正last指针。为避免混淆,将其放在private,对外不提供这个功能。
#ifndef CircList_H
#define CircList_H
include “List.h”
template <class Type> class CircList : public List<Type>
{
public:
CircList() { pGetFirst()->link = pGetFirst(); }
~CircList() { End(); pGetLast()->link = NULL; }
BOOL IsEmpty()
{
Node<Type> *p = pGetFirst();
return p->link == p;
}
Type *Next()
{
if (pNext() == pGetFirst()) pNext();
return Get();
}
BOOL Remove()
{
if(!IsEmpty())
{
if (pGet() == pGetFirst()) return FALSE;
List<Type>::Remove();
if (pGet() == pGetFirst()) pNext();
return TURE;
}
return FALSE;
}
void MakeEmpty()
{
First();
while (!IsEmpty()) RemoveAfter();
}
void LastInsert(const Type &value)
{
End();
List<Type>::LastInsert(value);
}
private:
void End()
{
if (pGetLast()->link != pGetFirst())
{
Node<Type> *pfirst = pGetFirst();
for (Node<Type> *p = pGet(); p->link != pfirst; p = pNext());
PutLast(p);
}
}
friend ostream & operator << (ostream & strm, CircList<Type> &cl)
{
cl.First();
Node<Type> *pfirst = cl.pGetFirst();
while (cl.pGet()->link != pfirst) strm << *cl.Next() << " " ;
strm << endl;
cl.First();
return strm;
}
};
#endif
【说明】为了后面的约瑟夫问题,我添加了LastInsert。如果使用Insert是倒插,当然可以倒输入来解决,但这样的做法有将就的嫌疑,而不断的Locate显然效率太低。显然,Find,Loacte,Length这类继承过来的函数,运行起来会发生意想不到的事,我没有在这里给出重新的实现出于以下原因: