所謂單鏈表的迭代器,就是將原本鏈表中用於處理遍歷、訪問和更新的方法封裝到一個新的迭代器類中,而只在鏈表類中保留描述其狀態的成員函數。在討論其實現方法和特點之前,先看一下是如何使用的。
#include "AbsList.cpp"
#include "AbsListItr.cpp"
#include "ListNode.cpp"
#include "List.cpp"
#include "ListItr.cpp"
int main()
{
List<int> list; //定義一個單鏈表
cout<<list.IsEmpty()<<endl; //判斷是否爲空
ListItr<int> itr(list); //定義一個迭代器
for(int i=1;i<=10;i++)
itr.Insert(i); //插入10個元素
cout<<itr()<<endl; //輸出當前結點的元素
cout<<itr.Remove(5)<<endl; //刪除值爲5的結點
cout<<list<<endl; //輸出整個鏈表
return 0;
}
從中不難看出,絕大多數對鏈表的處理是通過迭代器來完成的(事實上最後的輸出整個鏈表也是如此)。那麼爲何在main()中,一個迭代器對象能處理一個鏈表對象呢,看起來它們的“地位”似乎是一樣的。請注意上述代碼中的第五行:List<int> itr(list); 在定義一個迭代器 itr 時,需要將一個鏈表對象 list 作爲參數傳遞給迭代器類的構造函數。迭代器類和鏈表類一樣有一個頭指針,利用鏈表結點的特性,在迭代器類的構造函數中,通過把鏈表的頭指針賦給迭代器的頭指針,使得它們同時指向鏈表的頭結點,迭代器就能訪問整個鏈表了。
以下是具體實現的代碼,參考自《數據結構與算法(C++)》 2005 上海交通大學出版社 竇延平 張同珍 姜麗紅 陳玉泉。(這本書我很不推薦)
鏈表類:
#define ABSLIST
#ifndef ABSLISTITR
template <class ElemType> class AbsListItr;
#endif //ABSLISTITR
template <class ElemType>
class AbsList
{
public:
AbsList(){}
virtual ~AbsList(){}
virtual IsEmpty() const=0; //是否空
virtual IsFull() const=0; //是否滿
virtual void MakeEmpty()=0; //清空
friend class AbsListItr<ElemType>;
private:
AbsList(const AbsList &){} //凍結複製另一鏈表的構造函數
};
鏈表迭代器類:
#define ABSLISTITR
#ifndef ABSLIST
template <class ElemType> class AbsList;
#endif //ABSLIST
template <class ElemType>
class AbsListItr
{
public:
AbsListItr(const AbsList<ElemType> &L){}
AbsListItr(const AbsListItr&);
virtual ~AbsListItr(){}
virtual void Insert(const ElemType &x)=0; //在當前結點後插入
virtual int Remove(const ElemType &x)=0; //刪除值爲x的結點
virtual int Find(const ElemType &x)=0;
virtual int IsFound(const ElemType &x) const=0;
virtual int operator+() const=0; //判斷當前結點是否存在
virtual const ElemType & operator()()const=0; //取當前結點的內容
virtual void Zeroth()=0; //定位於鏈表的首結點之前
virtual void First()=0; //定位於鏈表的首結點
virtual void operator++()=0; //定位於下一結點
virtual void operator ++(int)=0;
protected:
AbsListItr(){} //凍結無參數的構造函數
};
單鏈表結點類:
#include <iostream.h>
#ifndef LISTNODE
#define LISTNODE
#ifndef LIST
template<class ElemType> class List;
#endif //LIST
#ifndef LISTITR
template<class ElemType> class ListItr;
#endif //LISTITR
template<class ElemType>
class ListNode
{
friend class List<ElemType>;
friend class ListItr<ElemType>;
private:
ListNode<ElemType> *Next;
ElemType Element;
public:
ListNode(const ElemType &E,ListNode<ElemType> *N=NULL):Element(E),Next(N){}
ListNode(){Next=NULL;}
~ListNode(){};
};
#endif //LISTNODE
單鏈表類:
#define LIST
#include <iostream.h>
#ifndef ABSLIST
template<class ElemType> class AbsList;
#endif //ABSLIST
#ifndef LISTITR
template<class ElemType> class ListItr;
#endif //LISTITR
#ifndef LISTNODE
template<class ElemType> class ListNode;
#endif //LISTNODE
template<class ElemType>
class List:public AbsList<ElemType>
{
friend class ListItr<ElemType>;
private:
ListNode<ElemType> *head;
public:
List()
{
head=new ListNode<ElemType>;
}
~List()
{
MakeEmpty();
delete head;
}
const List &operator=(const List &R);
int IsEmpty() const
{
return head->Next==NULL;
}
int IsFull()const
{
return 0;
}
void MakeEmpty();
};
template <class ElemType>
void List<ElemType>::MakeEmpty()
{
ListNode<ElemType> *Ptr;
ListNode<ElemType> *NextNode;
for(Ptr=head->Next;Ptr!=NULL;Ptr=NextNode)
{
NextNode=Ptr->Next;
delete Ptr;
}
head->Next=NULL;
}
template <class ElemType>
const List<ElemType> & List<ElemType>::operator=(const List<ElemType> &R)
{
if(this==&R)
return *this;
MakeEmpty();
ListItr<ElemType> Itr(*this);
for(ListItr<ElemType> Ritr(R);+Ritr;Ritr++)
Itr.Insert(Ritr());
return *this;
}
template <class ElemType>
ostream & operator<<(ostream & Out,const List<ElemType> &L)
{
if(L.IsEmpty())
Out<<"Empty List";
else
for(ListItr<ElemType> Itr(L);+Itr;Itr++)
Out<<Itr()<<endl;;
return Out;
}
迭代器類:
#define LISTITR
#ifndef ABSLISTITR
template<class ElemType> class AbsListItr;
#endif //ABSLISTITR
#ifndef LISTNODE
template<class ElemType> class ListNode;
#endif //LISTNODE
#ifndef LIST
template<class ElemType> class List;
#endif //LIST
template<class ElemType>
class ListItr:public AbsListItr<ElemType>
{
private:
ListNode<ElemType> *const head;
ListNode<ElemType> *Current;
public:
ListItr(const List<ElemType> &L):head(L.head)
{
Current=L.IsEmpty() ? head : head->Next;
}
~ListItr(){}
int Find(const ElemType &x); //查找值爲x的結點,成功則使其成爲當前結點
int IsFound(const ElemType &x) const; //查找值爲x的結點,不改變Current
void Insert(const ElemType &x);
int Remove(const ElemType &x);
int operator +() const //當前結點非空則返回True
{
return Current && Current !=head;
}
const ElemType & operator()()const; //取當前結點的數據值
void operator ++(); //使當前結點的後繼結點成爲當前結點 前綴++
void operator ++(int) //將後綴++定義爲前綴++
{
operator++();
}
void Zeroth()
{
Current=head;
}
void First();
const ListItr & operator=(const ListItr&); //賦值運算符
};
template<class ElemType>
void ListItr<ElemType>::Insert(const ElemType &x)
{
ListNode<ElemType> *p;
p=new ListNode<ElemType>(x,Current->Next);
Current=Current->Next=p;
}
template<class ElemType>
int ListItr<ElemType>::Find(const ElemType &x)
{
ListNode<ElemType> *Ptr=head->Next;
while(Ptr!=NULL && !(Ptr->Element==x))
Ptr=Ptr->Next;
if(Ptr==NULL)
return 0;
Current=Ptr;
return 1;
}
template<class ElemType>
int ListItr<ElemType>::IsFound(const ElemType &x) const
{
ListNode<ElemType> *Ptr=head->Next;
while(Ptr!=NULL && !(Ptr->Element==x))
Ptr=Ptr->Next;
return Ptr!=NULL;
}
template<class ElemType>
int ListItr<ElemType>::Remove(const ElemType &x)
{
ListNode<ElemType> *Ptr=head;
while(Ptr->Next!=NULL && !(Ptr->Next->Element==x))
Ptr=Ptr->Next;
if(Ptr->Next==NULL)
return 0;
ListNode<ElemType> *P=Ptr->Next;
Ptr->Next=Ptr->Next->Next;
delete P;
Current=head;
return 1;
}
template<class ElemType>
const ElemType & ListItr<ElemType>::operator()()const
{
return Current->Element;
}
template<class ElemType>
void ListItr<ElemType>::operator++()
{
Current=Current->Next;
}
template<class ElemType>
const ListItr<ElemType> &ListItr<ElemType>::operator=(const ListItr<ElemType> &R)
{
if(this==&R)
return *this;
head=R.head;
Current=R.Current;
return *this;
}
template<class ElemType>
void ListItr<ElemType>::First()
{
Current=head->Next;
}
細心的人肯定已經發現了,要使迭代器能夠訪問鏈表的頭指針,必須將迭代器類設爲鏈表類的友元類,這在一定程度上破壞了類的封裝性。使用迭代器的初衷是未避免經常修改鏈表類以及鏈表類變的過於龐大。然而面向對象程序設計的一個基本原則是封裝性和信息隱蔽。友元類雖然有助於數據共享,卻違背了信息隱蔽,一般只有在使用它時能使程序精煉並能大大提高程序的效率時才使用友元。
很顯然,在構建鏈表時使用迭代器使程序變的複雜,不利於初學者把精力放在數據結構本身上。同時以破壞封裝性爲代價,在小規模程序中並沒有提高程序的效率(反而是降低了)。因此我建議初學者在學習數據結構時不要使用迭代器。
可以通過此鏈接下載本程序:http://cid-24fba8dfcc188fae.skydrive.live.com/self.aspx/Public/ListItr.rar