双向链表无非在pre函数操作的时候更加简洁,不过增加了空间上的开销...

双向链表在insert和remove操作中比单项链表稍微复杂一下,下面给出图解:

双向链表图示:由下图可以发现,fence的定义仍然采用第二种定义,即fence指向当前位置的前一位置,实际上双向链表向前寻址也很方便了,两种fence定义也就没什么区别了,不过仍然用第二种定义无非是习惯而已,毕竟写单向链表的时候用的是第二种定义,而双向链表大部分都是基于单向链表的...

insert图示即代码:

//插入insert操作,请结合图解看程序更好理解
//关键是褛清指针修改的先后顺序
//然后是对特殊情况的处理
//有两处特殊处理:
//第一处是:插入之前fence就指向末尾tail那么把新的Link加到
//fence之后,新的link后面没有元素哦,那么就无需进行第五处
//修改了(见图解,即pre指向新的Link)
//第二处的情形和第一处一样,都是fence起初就指向tail,那么
//插入操作之后,新的Link才是此时真正的tail,所以要将tail改
//为fence->next(即新插入的Link地址)
template<class Elem>
bool DoubleList<Elem>::insert(Elem item){
//此句很关键,一句话完成了图解中前四步的指针修改
fence->next = new Link<Elem>(item,fence->next,fence);
//第一处特殊处理:
//下面的条件判断和fence!=tail等同
//不过原处比较好,更直接的体现出特殊处理的原因
if(fence->next->next!=NULL)
fence
->next->next->pre = fence->next;
//第二处特殊处理
if(tail == fence)
tail
= fence->next;
rightcnt
++;
return true;
}

remove操作图示及代码:



 

 

//删除remove的操作
//搞明白insert操作后,remove操作就很好理解了,很类似
template<class Elem>
bool DoubleList<Elem>::remove(Elem &it){
if(fence->next==NULL)return false;

it
= fence->next->element;

Link
<Elem>* temp = fence->next;
if(temp->next!=NULL)//等同于temp!=tail
temp->next->pre = fence;
else tail = fence;

fence
->next = temp->next;

delete temp;
rightcnt
--;
return true;
}

整体完整代码:

#include<iostream>
using namespace std;
//定义节点,既然学了freelist,那么就顺便用用好了,呵呵
template<class Elem>
class Link{
private:
static Link<Elem>* freeList;
public:
Elem element;
Link
*next;
Link
*pre;

Link(Elem elemval,Link
* nextval=NULL,
Link
* preval=NULL){
element
= elemval;
next
= nextval;
pre
= preval;
}
Link(Link
* nextval = NULL,Link* preval = NULL){
next
= nextval;
pre
= preval;
}
void* operator new(size_t);
void operator delete(void*);
};
template
<class Elem>
Link
<Elem>* Link<Elem>::freeList = NULL;
template
<class Elem>
void* Link<Elem>::operator new(size_t){
if(freeList==NULL)return ::new Link;
Link
<Elem>* temp = freeList;
freeList
= freeList->next;
return temp;
}
template
<class Elem>
void Link<Elem>::operator delete(void *ptr){
((Link
<Elem>*)ptr)->next = freeList;
freeList
= (Link<Elem>*)ptr;
}

template
<class Elem>
class DoubleList{
Link
<Elem>* head;
Link
<Elem>* tail;
Link
<Elem>* fence;
int leftcnt;
int rightcnt;
//私有函数
void init(){
fence
= tail = head = new Link<Elem>;
leftcnt
= rightcnt = 0;
}
void removeAll(){
while(head!=NULL){
fence
= head;
head
= head->next;
delete fence;
}
}

public:
//构造函数
DoubleList(){
init();
}
//析构函数
~DoubleList(){
removeAll();
}
void clear(){
//体现了函数模块化的好处:代码重用
removeAll();
init();
}
void setStart(){
fence
= head;
rightcnt
+=leftcnt;
leftcnt
= 0;
}
void setEnd(){
fence
= tail;
leftcnt
+=rightcnt;
rightcnt
= 0;
}
void next(){
if(fence!=tail){
fence
= fence->next;
rightcnt
--;
leftcnt
++;
}
}
//pre()函数体现了双向链表的好处了方便之处了 !!
void pre(){
if(fence!=head){
fence
= fence->pre;
rightcnt
++;
leftcnt
--;
}
}
int leftLength(){return leftcnt;}
int rightLength(){return rightcnt;}

bool getValue(Elem &it){
if(rightcnt==0)return false;
//仍然采用fence的第二种定义
//即fence指向当前元素的上一个元素位置
it = fence->next->element;
return true;
}

bool insert(Elem item);
bool append(Elem item);
bool remove(Elem & item);
bool find(Elem item);
void print();
};
//插入insert操作,请结合图解看程序更好理解
//关键是滤清指针修改的先后顺序
//然后是对特殊情况的处理
//有两处特殊处理:
//第一处是:插入之前fence就指向末尾tail那么把新的Link加到
//fence之后,新的link后面没有元素哦,那么就无需进行第五处
//修改了(见图解,即pre指向新的Link)
//第二处的情形和第一处一样,都是fence起初就指向tail,那么
//插入操作之后,新的Link才是此时真正的tail,所以要将tail改
//为fence->next(即新插入的Link地址)
template<class Elem>
bool DoubleList<Elem>::insert(Elem item){
//此句很关键,一句话完成了图解中前四步的指针修改
fence->next = new Link<Elem>(item,fence->next,fence);
//第一处特殊处理:
//下面的条件判断和fence!=tail等同
//不过原处比较好,更直接的体现出特殊处理的原因
if(fence->next->next!=NULL)
fence
->next->next->pre = fence->next;
//第二处特殊处理
if(tail == fence)
tail
= fence->next;
rightcnt
++;
return true;
}

//删除remove的操作
//搞明白insert操作后,remove操作就很好理解了,很类似
template<class Elem>
bool DoubleList<Elem>::remove(Elem &it){
if(fence->next==NULL)return false;

it
= fence->next->element;

Link
<Elem>* temp = fence->next;
if(temp->next!=NULL)//等同于temp!=tail
temp->next->pre = fence;
else tail = fence;

fence
->next = temp->next;

delete temp;
rightcnt
--;
return true;
}
template
<class Elem>
bool DoubleList<Elem>::append(Elem item){
tail
->next = new Link<Elem>(item,NULL,tail);
tail
= tail->next;
//其实前两句可以写成一句:
//tail = tail->next = new Link<Elem>(item,NULL,tail);
//但是千万不能写成介个:链条没有连接起来 !!!
//tail = new Link<Elem>(item,NULL,tail);
rightcnt++;
return true;
}
template
<class Elem>
bool DoubleList<Elem>::find(Elem item){
Elem it;
//可以看到getValue()返回bool类型的好处 !
//否则如果写成for(setStart();fence->next!=NULL;next())
//循环体内部还得加上getValue(it)这句,有些罗嗦了..
for(setStart();getValue(it);next())
if(it == item) return true;
return false;
}
template
<class Elem>
void DoubleList<Elem>::print(){
Link
<Elem>* temp = head;
cout
<<"The list is : < ";
while(temp!=fence){
cout
<<temp->next->element<<" ";
temp
= temp->next;
}
cout
<<"| ";
while(temp->next!=NULL){
cout
<<temp->next->element<<" ";
temp
= temp->next;
}
cout
<<"> "<<endl;
}
int main(){
DoubleList
<int>list;
list.print();

for(int i=0;i<5;i++)
list.append(i
*2);
list.print();

list.next();
list.print();
list.next();
list.print();
list.pre();
list.print();

list.insert(
5);
list.print();

int it;
list.remove(it);
list.print();
cout
<<"删除的元素为:"<<it<<endl;

if(list.find(8))cout<<" 8 is in the list !"<<endl;
else cout<<" 8 is not in the list !"<<endl;
if(list.find(7))cout<<" 7 is in the list !"<<endl;
else cout<<" 7 is not in the list !"<<endl;

return 0;
}

posted on 2011-05-29 03:58  geeker  阅读(2680)  评论(0编辑  收藏  举报