理论基础 —— 线性表 —— 双向链表
【实现类】
template <class T>
struct Node{//结点
T data;//数据域
Node *llink;//左指针
Node *rlink;//右指针
};
template <class T>
class doubleList{
private:
Node<T> *first;//头指针
public:
doubleList();//无参构造函数
doubleList();//有参构造函数
~doubleList();//析构函数
void insertElement(T x);//在双链表中插入值为x的元素
T deleteElement(T x);//删除双链表中值为x的元素
void Sort(int len);//冒泡排序
void print();//按序号依次输出双链表各元素
};
【构造函数】
1.无参构造函数
对于无参构造函数,只需建一个头结点,令其左右指针分别为空即可
template <class T>
linkList<T>::doubleLink(){//无参构造函数
first=new Node<T>;//头指针指向头结点
first->llink=NULL;//左指针为空
first->rlink=NULL;//右指针为空
}
2.有参构造函数
1)头插法
template <class T>
linkList<T>::doubleLink(T a[],int n){
first=new Node;//头指针指向头结点
first->llink=NULL;//左指针为空
first->rlink=NULL;//右指针为空
Node *s;//新结点
for(int i=1;i<=n;i++){
s=new Node;
s->data=a[i];//数据域
s->rlink=first->rlink;
first->rlink=s;
s->llink=first;
if(s->rlink!=NULL)//下个结点不为空
s->rlink->llink=s;//下一个节点指向自己
}
}
2)尾插法
template <class T>
linkList<T>::doubleLink(T a[],int n){
first=new Node<T>;//头指针指向头结点
Node *r=first;//尾指针
first->llink=NULL;//左指针为空
first->rlink=NULL;//右指针为空
Node<T> *s;//新结点
for(int i=0;i<n;i++){
s=new Node<T>;
s->data=a[i];//数据域
r->rlink=s;
s->llink=r;
r=s;
}
r->rlink=NULL;
}
【析构函数】
对于析构函数,与单链表的析构函数相同,仅需使用右指针 rlink 不断指向下一结点,释放存储空间即可
template <class T>
doubleLink<T>::~doubleLink(){
Node<T> *p,*q;//工作指针
p=first;//从头开始
while(p!=NULL){
q=p->rlink;//指向下一结点
delete p;//释放当前结点空间
p=q;//令当前节点指向下一结点
}
}
【插入】
在双向链表中插入一个结点,对指针的操作顺序有很多,但由于双向链表实质上可看作两条反向的单链表,所以插入操作的核心是:先处理每个方向的远端指针,再处理近端指针
原则上,插入一个结点需要连接 4 个指针,但考虑插入时的特殊情况,即在空表或表尾插入一个结点时,新结点的右指针指向为空,此时只需连接 3 个指针

void doubleList<T>:: insertElement(T x){//在双表中插入值为x的元素
Node<T> *s=new Node<T>;//新结点
s->data=x;//新结点数据域赋值为x
s->rlink=p->rlink;//新结点s的右指针指向工作结点p之后的结点
s->llink=p;//新结点s的左指针指向工作结点p
p->rlink=s;//工作结点p的右指针指向新结点s
if(s->rlink!=NULL)//不为表尾或空时
s->rlink->llink=s;//新结点s的右指针的左指针指向新结点s
}
【删除】
对于删除操作,其与插入操作相似,在删除时需要判断是否为表尾结点

bool doubleList<T>::deleteElement(T x){//删除双链表中值为x的元素
Node<T> *p;//工作指针
p=first->rlink;
while(p!=NULL){
if(p->data==x){
if(p->rlink==NULL)//p为表尾元素
p->llink->rlink=NULL;
else{//p不为表尾元素
p->llink->rlink=p->rlink;
p->rlink->llink=p->llink;
}
delete p;//释放空间
return true;//删除成功
}
p=p->rlink;
}
return false;//删除失败
}
【冒泡排序】
int doubleList<T>::void Sort(int len){//冒泡排序
Node<T> *p;//工作指针
for(int i=0;i<len-1;i++){//len-1轮
p=first->rlink;
for(int j=0;j<len-i-1;j++){//len-i次
T tempA=p->data;//当前数据
T tempB=p->rlink->data;//下一结点数据
if(tempA>tempB){//比较
T temp=p->data;
p->data=p->rlink->data;
p->rlink->data=temp;
}
p=p->rlink;//指向下一结点
}
}
}
【输出】
双链表的遍历输出,与单链表相同,仅需使用右指针 rlink 不断指向下一结点,输出数据域即可
template <class T>
void doubleLink<T>::print(){
Node<T> *p;//工作指针
p=first->rlink;//从第一个结点开始
while(p!=NULL){
cout<<(p->data)<<endl;//输出数据域
p=p->rlink;//指向下一结点
}
}

浙公网安备 33010602011771号