目录
双向循环链表定义
1、双向链表的定义:在单链表的每个结点里增加一个指向其前驱的指针prior,这样链表中就形成了有两个方向不同的链,称为双向链表。
2、双向循环链表:循环的同时,让头结点的前驱指针指向链表的最后一个结点,让最后一个结点的后继指针指向头结点。
优点:
双向访问:双向链表允许从任意节点向前或向后遍历,这使得在需要频繁访问链表前后节点的场景中,双向链表比单向链表更加高效。
循环特性:双向循环链表的头尾相连,形成一个环,这使得在处理需要循环访问所有节点的任务时,双向循环链表比单向循环链表更加方便。
空间效率:虽然双向链表比单向链表多存储了一个指向直接前驱和后继的指针,但在某些应用场景中,这种设计带来的便利性可能超过其空间复杂度的增加。
缺点:
空间复杂度较高:由于每个节点需要存储指向直接前驱和后继的指针,双向链表的空间复杂度比单向链表高。
实现复杂:虽然双向链表的实现看起来简单,但在某些特定操作上,如插入和删除节点时,需要处理更多的指针操作,这可能会比单向链表更复杂。
设p为链表中某结点的指针, 有对称性:(p->prior)->next = p = (p->next)->prior
双向循环链表结构
#ifndef _DLIST_H_
#define _DLIST_H_
typedef struct node{
int data;
struct node *prior;//前驱指针
struct node *next;//后驱指针
}dlistnode;
dlistnode * dlist_create();
void dlist_show(dlistnode *H);
void dlist_insert(dlistnode *H,int value,int pos);
void dlist_clear(dlistnode *H);
dlistnode *dlist_get(dlistnode *H,int pos);
int dlist_len(dlistnode *H);
int dlist_delete(dlistnode *H,int pos);
#endif
链表创建
dlistnode * dlist_create(){
dlistnode *H,*p,*r ;
//判断头节点申请成功
if((H = (dlistnode *)malloc(sizeof(dlistnode)))== NULL){
printf("malloc error\n");
return NULL;
}
//头结点初始化
H->next = H;
H->data = 0;
H->prior = H;
r = H;
//同时根据用户输入在插入后续节点,如果输入-1结束输入
while(1){
int ch;
printf("please input:input 'end'exit\n");
scanf("%d",&ch);
if(ch ==-1 ){
printf("exit\n");
break;
}
if((p = (dlistnode *)malloc(sizeof(dlistnode))) == NULL){
printf("p malloc eror\n");
return NULL;
}
//尾结点插入需要注意指针链接顺序,头结点的data作为链表长度使用
p->data = ch;
p->prior = r;
p->next = H;
H->prior = p;
r->next = p;
r = p;
H->data++;
}
return H;
}
链表遍历
void dlist_show(dlistnode *H){
if(H == NULL){
printf("H is NULL\n");
return;
}
dlistnode *p;
p = H->next;
while(p!=H){
printf("%d ",p->data);
p = p->next;
}
puts("");
}
链表插入
void dlist_insert(dlistnode *H,int value,int pos){
if(H == NULL){
printf("H is NULL\n");
return;
}//pos小于0大于当前长度都是无效插入位置
if(pos<0||pos>H->data){
printf("pos is error\n");
return;
}
dlistnode *p,*r=H;
int i=0;
if((p=(dlistnode *)malloc(sizeof(dlistnode))) == NULL){
printf("malloc is NULL\n");
return;
}
//指针移动到插入的前一个位置
while(i<pos){
r=r->next;
i++;
}//插入后头结点data自加1
p->data =value;
p->prior = r;
p->next = r->next;
r->next->prior = p;
r->next = p;
H->data++;
}
链表删除某节点
int dlist_delete(dlistnode *H,int pos){
if(H == NULL){
printf("H is NULL\n");
return -1;
}
if(pos<0||pos>H->data-1||H->data == 0){
printf("pos get error\n");
return -1;
}
dlistnode *p,*r;
p = dlist_get(H,pos);
r = H;
//找到pos节点前一个节点地址
while(r->next!=p){
r=r->next;
}//删除节点后data自减1
int a = p->data;
r->next =r->next->next;
r->next->prior = r;
H->data--;
free(p);
return a;
}
链表清空
oid dlist_clear(dlistnode *H){
if(H == NULL || H->data ==0){
printf("H delete wrong\n");
return;
}
dlistnode *r,*p;
p = H->next;
r = H;
while(p!=H){
r = p;
p = p->next;
free(r);
}
H->data = 0;
}
链表查询某节点
dlistnode *dlist_get(dlistnode *H,int pos){
if(H == NULL){
printf("H is NULL\n");
return NULL;
}//pos小于0等于data或者空结点,pos都是无效输入位置
if(pos<0||pos>H->data-1||H->data == 0){
printf("pos get error\n");
return NULL;
}
int i=0;
dlistnode *p = H;
while(i<pos){
p = p->next;
i++;
}//查询节点返回p的下一个地址
return p->next;
}
链表长度
int dlist_len(dlistnode *H){
if(H == NULL){
printf("H is NULL\n");
return -1;
}
return H->data;
}