前言:
在理解双向链表前,应该掌先掌握单链表的基本操作。
介绍:
双向链表区别于单链表而言,最主要的就是双向链表可以通过后面的结点找到前面的结点,也就是说可以实现正反遍历方式。
所以这样的链表在实现上,会比单链表会更复杂一点,但是其根本思想是一致的。你可以理解为有两个链表一个往👉指,另一个往👈指。
而我们使用链表最重要的原因就是它的插入和删除使相对于顺序表而言,时间上来看,是要快的。所以我们这里介绍插入和删除的关键代码:
插入:执行的顺序为红橙黄绿。
实现代码:
- ptemp->prior=p;//ptemp的结点前驱是p;
- ptemp->next=p->next;//ptemp结点的后继是p->next;
- p->next->prior=ptemp;//p->next结点的前驱是ptemp;
- p->next=ptemp;//p的后继结点是ptemp;
删除:执行顺序红橙
实现代码:
- ptemp-prior->next=ptemp->next;
- ptemp->next->prior=ptemp->prior
完整代码:
#include<stdio.h>
#include<stdlib.h>
typedef struct node
{
int data;//数据域
struct node *prior;//直接前驱;
struct node *next;//直接后驱;
}DNode,*DLinklist;
DLinklist InitLinklist();//初始化双向链表,成功返回1失败返回0;
int InsertDLinklist(DLinklist phead,int pos,int values);//插入结点,在pos位置插入values;成功则返回1,失败则返回0;
int DeleteDLinklist(DLinklist phead,int pos,int *values);//删除结点,在pos位置删除values成功返回1失败返回0;
void print(DLinklist phead);
/*初始化链表*/
DLinklist InitLinklist()
{
DLinklist phead=(DLinklist)malloc(sizeof(DNode));
if(NULL==phead)
{
printf("动态分配内存失败!\n");
exit(0);
}
phead->prior=NULL;
phead->next=NULL;
phead->data=1;
//
DLinklist p=phead;
p->next=NULL;
int i,values;
printf("请输入你的链表结点数\n");
scanf("%d",&values);
for(i=0;i<values;i++)
{
DLinklist ptemp=(DLinklist)malloc(sizeof(DNode));
if(NULL==ptemp)
{
printf("动态分配内存失败!\n");
exit(0);
}
ptemp->prior=NULL;
ptemp->next=NULL;
ptemp->data=(i+1)*(i+1);
//
p->next=ptemp;
ptemp->next=NULL;
ptemp->prior=p;
p=ptemp;
}
return phead;
}
//插入结点
int InsertDLinklist(DLinklist phead,int pos,int values)
{
DLinklist p=phead->next;
phead->prior=NULL;
int count=0;
if(p==NULL)
{
DLinklist ptail=(DLinklist)malloc(sizeof(DLinklist));
ptail->data=values;
//
ptail->prior=phead;
phead->next=ptail;
ptail->next=NULL;
return 1;
}
//遍历链表得到结点个数
while(NULL!=p)
{
p=p->next;
count++;
}
printf("链表长度:%d \n",count);
if(pos>count+1||pos<0)
{
printf("插入位置出错!\n");
return 0;
}
p=phead->next;
int i=1;
while(NULL!=p&&i<pos-1)
{
p=p->next;
i++;
}
//此时的p是插入的结点的直接前驱结点
DLinklist ptemp=(DLinklist)malloc(sizeof(DNode));
if(NULL==ptemp)
{
printf("动态分配内存失败!\n");
return 0;
}
ptemp->data=values;
DLinklist q=p->next;
//
ptemp->prior=p;//ptemp的结点的前驱就是p;
ptemp->next=p->next;//将下一个结点的地址赋给ptemp的next;
p->next->prior=ptemp;//p的直接后继结点的前驱是指向ptemp;
p->next=ptemp;//将p的直接后继结点变成ptemp;
return 1;
}
//删除结点
int DeleteDLinklist(DLinklist phead,int pos,int *values)
{
DLinklist p=phead->next;
int count=0;
while(NULL!=p)
{
p=p->next;
count++;
}
if(pos>count+1||pos<0)
{
printf("删除位置出错!\n");
return 0;
}
DLinklist ptemp=phead->next;
int i=0;
while(NULL!=ptemp&&i<pos-1)
{
ptemp=ptemp->next;
i++;
}
*values=ptemp->data;//保存要删除的结点
//此时的ptemp就是要删除的那个结点;
if(ptemp->next==NULL)
{
printf("您删除的是最后一个结点!\n");
ptemp->prior->next=NULL;
free(ptemp);
ptemp=NULL;
return 1;
}
if(phead==ptemp->prior)
{
printf("您删除的是第一个结点!\n");
phead->next=ptemp->next;
ptemp->next->prior=phead;
// ptemp->next->prior=phead;
phead->prior=NULL;
return 1;
}
ptemp->prior->next=ptemp->next;//此时的ptemp的前驱结点应该装上ptemp结点的后继结点地址;
ptemp->next->prior=ptemp->prior;//ptemp的前驱结点应该装上ptemp后继结点的前驱地址;
free(ptemp);//释放内存;
ptemp=NULL; //指向空
return 1;
}
void print(DLinklist phead)
{
DLinklist ptemp=phead->next;//从左往右打印
printf("双向链表从头开始打印:\n");
while(NULL!=ptemp)
{
printf("%d ",ptemp->data);
ptemp=ptemp->next;
}
printf("\n");
printf("双向链表从尾开始打印:\n");
DLinklist ptail=phead;
// phead->prior=NULL;
while(ptail->next!=NULL)
{
ptail=ptail->next;
}
while(phead!=ptail)
{
printf("%d ",ptail->data);
ptail=ptail->prior;
}
printf("\n");
return;
}
int main()
{
DLinklist phead=NULL;
int pos,values;
int num,pval;
phead=InitLinklist();
int result;
printf("请输入插入位置:\n");
scanf("%d",&pos);
printf("请输入插入元素:\n");
scanf("%d",&values);
result=InsertDLinklist(phead,pos,values);
if(result==1)
{
printf("插入成功!\n");
print(phead);
}
else
{
printf("插入失败!\n");
}
printf("请输入删除位置:\n");
scanf("%d",&num);
int res=DeleteDLinklist(phead,num,&pval);
if(res==1)
{
printf("删除成功!删除元素:%d\n",pval);
print(phead);
}
else
{
printf("删除失败!\n");
}
}
如果对你有用,点个赞~,谢谢!