文章目录
1.双向链表的定义√
本篇接上两节插队比喻
每个数据节点都有两个指针,一个值直接后继一个指直接前继(数据-我,直接前继-带个新朋友插队,直接后继-陌生人),而和单向链表(仅后继)相比当然占用空间会更大
双向链表定义结点:√
typedef struct node
{
int date;
struct node *qian;
struct node *next;
}Node,*Link;
初始化结点√
Link Init()
{
Node* head;
head=(Node*)malloc(sizeof(Node));
head->qian=NULL;
head->next=NULL;
return head;
}
比单链表多创建一个直接前驱结点(指针域)
双向循环链表的定义√
双向链表的前后都需要连接
2.双向链表的创建(尾插法创建)√
按单链表的基础创建,但每创建一个新结点都要与他的前驱结点建立两次联系
法①(头插创建)将新节点的 qian 指针指向直接前驱节点;
p->qian=head;
p->next=head->next
将直接前驱节点的 next 指针指向新节点;
head->next->qian=p;
head->next=p;
法②(尾插创建)
需要两个结点p,s
p=head;
p->next=s;
s->qian=p;
p=p->next;
(代码含有单链表尾插 p->next=s; p=s; 区别诙谐注解)
void Create(Link head)
{
Node *p=head,*s;//p-老朋友,s插队人
printf("请输入要输入的数据:\n");
int date;
while(1)
{
scanf("%d",&date);
if(date==0)
break;
s=(Node*)malloc(sizeof(Node));
s->qian=NULL;//前驱结点指针域初始化
s->next=NULL;//后继结点指针域初始化
s->date=date;
//条件
p->next=s;
// 老朋友下一个插入人
//单链表中此处**接着**p=s(本来插队只有我一人)
//但是由于有新朋友,故需要新朋友指向(认识)老朋友
s->qian=p;
//对于新老朋友建立双向联系
p=p->next;//循环条件 (完事我插)
}
}
3.双向链表的插入
在头插,尾插,中间插
插头
单链表是新节点
p->next=head->next;找到头结点指针域(指向首节点)
head->next=p;作为首结点
而双向链表通过前驱指针实现双向
p->next=head;新节点找到头节点(前驱为空,故插入前驱也为空)本身,
head->qian=p;(实现双向,头结点前驱指向新节点)
2.中间插
单链表创建新节点Node* p;
p=head;
遍历找到p,输入插入数据s
s->next=p->next;
p->next=s;
是不是和头插很像,不过多了遍历
双链表新节点先与其直接后继节点建立双层逻辑关系;
新节点的直接前驱节点与之建立双层逻辑关系;
插尾
单链表的创建p
4.双向链表的打印
基本同单链表输出,可以添加判断有空指针域的头结点作为结束标志,或者直接p作为条件也行
void Output(Link head)
{
Node *p;
p=head->next;
printf("以下是信息:\n");
while(p!=head)
{
printf("%d\t",p->date);
p=p->next;
}
printf("\n");
}
5.双向链表的删除
6.双向链表更改节点数据
7.双向链表的查找
8.双向链表的结点计数√
int Length(Link head) {
Node *p = head->next;
int cnt = 0;
while(p) {
cnt++;
p = p->next;
}
return cnt;
}
9.例题
①回文链表
10.测试函数及结果
int main()
{
Link ha;
ha=Init(ha);
Create(ha);
Output(ha);
return 0;
}
本篇是按照大佬作品做的笔记详解双向链表的基本操作(C语言)