用迭代器构建的单链表

本文介绍单链表迭代器的设计与实现,包括如何通过迭代器处理链表遍历、插入与删除等操作。详细解释了迭代器与链表之间的交互机制及其实现代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

所谓单链表的迭代器,就是将原本链表中用于处理遍历、访问和更新的方法封装到一个新的迭代器类中,而只在链表类中保留描述其状态的成员函数。在讨论其实现方法和特点之前,先看一下是如何使用的。

//Main.cpp
#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 上海交通大学出版社 窦延平 张同珍 姜丽红 陈玉泉。(这本书我很不推荐)

 链表类:

//AbsList.cpp
#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 &){}    //冻结复制另一链表的构造函数

}
;

链表迭代器类:

//AbsListItr.cpp
#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()
{}    //冻结无参数的构造函数

}
;

单链表结点类:

//ListNode.cpp
#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

单链表类:

//List.cpp
#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;
}

迭代器类:

//ListItr.cpp
#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

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值