1、循环链表
在很多实际问题中,操作是在首或者尾部进行,此时单链表的头节点就显得不够方便,如果改用终端端点的尾指针,并且该尾部指针指向头节点,则查找头节点,开始节点以及尾部节点都很方便,他们的存储地址:rear->next,rear->next->next.rear。这就是循环链表:
//clinklist
template<typename T>
class clinklist{
private:
node<T>*rear;
node<T>*first;
int size;
public:
clinklist(){first=new node<T>;rear->next=first;first->next=first;size=0;}
clinklist(T a[],int n);
~clinklist();
int getsize();
T get(int i);
int loc(T x);
void insert(int i,T x);
T del(int i);
void prt();};
template<typename T>
clinklist<T>::clinklist(T a[],int n){
first=new node<T>;
node<T>*p=first;
for(int i=0;i<n;i++)
{node<T>*s=new node<T>;
s->data=a[i];
p->next=s;
p=s;}
size=n;
rear=p;
p->next=first;
}
template<typename T>
int clinklist<T>::getsize(){
return size;}
template<typename T>
T clinklist<T>::get(int i){
node<T>*p=first;
int j=0;
while(p!=rear&&j<i){
p=p->next;
j++;}
if(p==rear)throw"i error";
else return p->data;}
template<typename T>
int clinklist<T>::loc(T x){
node<T>*p=rear->next;//rear->next==first
int j=0;
while(p!=rear&&p->data!=x){
p=p->next;
j++;}
if(p==rear)return -1;
else return j;}
template<typename T>
void clinklist<T>::insert(int i,T x){
node<T>*p=rear->next;
int j=0;
while(p!=rear&&j<i-1){
p=p->next;
j++;}
if(p==rear)cout<<"i error";
else {
node<T>*s=new node<T>;
s->data=x;
s->next=p->next;
p->next=s;
size++;}
}
template<typename T>
T clinklist<T>::del(int i){
node<T>*p=rear->next;
int j=0;
while(p!=rear&&j<i-1){
p=p->next;
j++;}
if(p==rear||p->next==rear)throw"del error";
else{node<T>*q=p->next;
T x=q->data;
p->next=q->next;
delete q;
size--;
return x;}
}
template<typename T>
clinklist<T>::~clinklist(){
node<T>*p=rear->next;
while(p!=rear){
node<T>*q=p;
p=p->next;
delete q;}
}
template<typename T>
void clinklist<T>::prt(){
node<T>*p=first;
if(p==rear)cout<<"empty"<<endl;
while(p!=rear){
p=p->next;
cout<<p->data<<" ";
}
cout<<endl;}
2、双向链表
虽然循环链表以及很方便了,但是主要针对的是首尾端,对于其中任意一个节点比如前驱节点的扫描还是需要遍历整个循环链表,因此可以在单循环链表基础上再设置一个指向前驱的指针域。那么对于链表中开始,终端,中间任意位置处节点的操作都是相同:
//dclinklist
template<typename T>
struct dnode{
T data;
dnode<T>*pri;
dnode<T>*next;};
template<typename T>
class dclinklist{
private:
dnode<T>*rear;
dnode<T>*first;
int size;
public:
dclinklist(){first=new dnode<T>;first=rear->next;first->next=first;size=0;}
dclinklist(T a[],int n);
~dclinklist();
int getsize();
T get(int i);
int loc(T x);
void insert(int i,T x);
T del(int i);
void prt();};
template<typename T>
dclinklist<T>::dclinklist(T a[],int n){
first=new dnode<T>;
dnode<T>*p=first;
for(int i=0;i<n;i++)
{dnode<T>*s=new dnode<T>;
s->data=a[i];
p->next=s;
p=s;}
size=n;
rear=p;
p->next=first;}
template<typename T>
dclinklist<T>::~dclinklist(){
dnode<T>*p=rear->next;
while(p!=rear){
dnode<T>*q=p;
p=p->next;
delete q;}
}
template<typename T>
int dclinklist<T>::getsize(){
return size;}
template<typename T>
T dclinklist<T>::get(int i){
dnode<T>*p=rear->next;
int j=0;
while(p!=rear&&j<i){
p=p->next;
j++;}
if(p==rear)throw"i error";
else{return p->data;}}
template<typename T>
int dclinklist<T>::loc(T x){
dnode<T>*p=first;
int j=0;
while(p!=rear&&p->data!=x){
p=p->next;
j++;}
if(p==rear)return -1;
else return j;}
template<typename T>
void dclinklist<T>::insert(int i, T x){
dnode<T>*p=first;
int j=0;
while(p!=rear&&j<i-1){
p=p->next;
j++;}
if(p==rear)cout<<"i error"<<endl;
else{
dnode<T>*s=new dnode<T>;
s->data=x;
s->pri=p;
s->next=p->next;
p->next->pri=s;
p->next=s;
size++;}
}
template<typename T>
T dclinklist<T>::del(int i){
dnode<T>*p=first;
int j=0;
while(p!=rear&&j<i-1){
p=p->next;
j++;}
if(p==rear||p->next==rear)throw"del error";
else{dnode<T>*q=p->next;
T x=q->data;
( q->pri)->next=q->next;
(q->next)->pri=q->pri;
delete q;
size--;
return x;}
}
template<typename T>
void dclinklist<T>::prt(){
dnode<T>*p=first;
if(p==rear)cout<<"empty"<<endl;
while(p!=rear){
p=p->next;
cout<<p->data<<" ";
}
cout<<endl;}
双循环链表同单循环链表比,求表长,查找等操作基本一样,唯一就是插入和删除不一样,它是一种对称结构。