94.【C语言】数据结构之双向链表的初始化,尾插,打印和尾删

目录

1.双向链表

2.结构体的定义

3.示意图

3.代码示例

1.双向链表的尾插

示意图

代码

main.c

List.h

List.c

详细分析代码的执行过程

双向链表的初始化

2.双向链表的打印

代码

3.双向链表的尾删


1.双向链表

以一种典型的双向链表为例:带头双向循环链表(带头: 哨兵位的节点)

2.结构体的定义

cpp 复制代码
typedef struct ListNode
{
	struct ListNode* next;
	struct ListNode* prev;
	LTDataType data;
}LTNode;

3.示意图

head为带哨兵位的头节点,无有效数值,只储存第一个有效节点的地址,负责找到第一个节点

特点:

1.prev指向前一个节点,next指向下一个节点

2.末尾的next指向哨兵位的头

3.哨兵位的头的prev指向末尾(不用像单向链表那样循环找尾节点)

3.代码示例

List.h

cpp 复制代码
#pragma once
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
typedef int LTDataType;
 
typedef struct ListNode
{
	struct ListNode* next;
	struct ListNode* prev;
	LTDataType data;
}LTNode;

void LTInit();
void LTDestory();
void LTPushBack(LTNode* phead,LTDataType x);
void LTPopBack(LTNode* phead);

用结构体定义节点,节点有三部分构成:next指针,prev指针和数据,符合双向节点的定义

注:prev为previous的缩写

1.双向链表的尾插

示意图

非空链表

空链表

和之前的无头的单向链表有所不同,这里的带哨兵位的头节点

未尾插之前,head->prev指向head->next,head->next指向head->prev(这样可以实现双向循环)

千万不要被箭头的指向所误导!!!!

不是head->prev=head->next;head->next=head->prev;

++箭头指向的是head节点++
head->prev=head;head->next=head;

尾插之后

实现过程和非空链表一样

*无论对于空链表还是非空链表,尾插都只需要4步,即修改四个指针*

tail指向尾节点

代码

main.c
cpp 复制代码
#include "List.h"
void TestList()
{
	LTNode* plist = LTInit();
	LTPushBack(plist, 1);
	LTPushBack(plist, 2);
	LTPushBack(plist, 3);
	LTPushBack(plist, 4);
}

int main()
{
	TestList();
	return 0;
}
List.h
cpp 复制代码
#include <assert.h>
typedef int LTDataType;
 
typedef struct ListNode
{
	struct ListNode* next;
	struct ListNode* prev;
	LTDataType data;
}LTNode;

LTNode* LTInit();
LTNode* BuyListNode(LTDataType x);
void LTPushBack(LTNode* phead, LTDataType x);
List.c
cpp 复制代码
#include "List.h"
LTNode* LTInit()
{
	LTNode* phead = BuyListNode(-1);
	phead->next = phead;
	phead->prev = phead;
	return phead;
}

LTNode* BuyListNode(LTDataType x)
{
	LTNode* node = (LTNode*)malloc(sizeof(LTNode));
	if (node == NULL)
	{
		perror("malloc");
		return NULL;
	}
	node->next = NULL;
	node->prev = NULL;
	node->data = x;
	return node;
}

void LTPushBack(LTNode* phead, LTDataType x)
{
	assert(phead);

	LTNode* newnode = BuyListNode(x);
	LTNode* tail = phead->prev;

	tail->next = newnode;
	newnode->prev = tail;
	newnode->next = phead;
	phead->prev = newnode;
}

详细分析代码的执行过程

进入main函数-->调用TestList函数-->调用LTInit函数-->调用BuyListNode函数

在BuyListNode函数中,先为新的节点开辟空间,之后node指向新节点,如果node为NULL,则开辟失败返回NULL,如果开辟成功继续向下执行①prev和next置NULL ②写入节点的data值

返回node指针,BuyListNode函数结束

双向链表的初始化

在LTInit函数中,phead得到node的值

已知phead存储的值为00 c0 a0 98,求phead->next = phead;和phead->prev = phead;执行完后按小端序计算0x00c0a098~0x00c0a09f处的数据

解:

按照结构体成员变量定义的先后顺序

phead->prev存储在0x00C0A098~0x00C0A09B处,phead->next存储在0x00C0A09C~0x00C0A09F处

因此答案为98 a0 c0 00 98 a0 c0 00

返回phead后,LTInit函数结束

在TestList函数中,plist得到phead的值

调用LTPushBack函数

在LTPushBack函数中,phead得到plist的值(这里没有传二级指针,修改结构体成员变量的值只需要一级指针),断言phead,确保phead不为NULL

调用BuyListNode,返回新节点的地址给newnode

只有带哨兵位的头结点时,LTNode* tail = phead->prev;等价为LTNode* tail = phead;

LTPushBack函数结束

剩下的分析思想一样,略去

2.双向链表的打印

让cur指针指向head节点的下一个节点,循环打印,当cur直到head时,停止打印

代码

cpp 复制代码
void LTPrint(LTNode* phead)
{
	assert(phead);
	LTNode* cur = phead->next;
	printf("head<=>");
	while (cur != phead)
	{
		printf("%d<=>", cur->data);
		cur = cur->next;
	}
	printf("\n");
}

3.双向链表的尾删

尾删要单独判断是否只有带哨兵位的头节点

写一个LTEmpty函数

cpp 复制代码
bool LTEmpty(LTNode* phead)
{
	assert(phead);
	return phead->next == phead;
}

直接将phead->next == phead结果的真假返回,比if判断要简洁

cpp 复制代码
void LTPopBack(LTNode* phead)
{
	assert(phead);
	assert(!LTEmpty(phead));//注意感叹号
	LTNode* tail = phead->prev;
	LTNode* tailPrev = tail->prev;//定义指向tail的前一个节点的指针
	tailPrev->next = phead;
	phead->prev = tailPrev;
	free(tail);
	tail = NULL;
}
相关推荐
LDR0068 小时前
Type-C 快充全面升级!LDR6601 赋能个人护理便携电机,重塑剃须刀 / 理发器新体验
c语言·开发语言
小小工匠9 小时前
Redis - 事务机制:能实现 ACID 属性吗
数据结构·redis·性能优化·并发·持久化
Luminous.9 小时前
C语言--day30
c语言·开发语言
玖玥拾10 小时前
C/C++ 数据结构(七)栈、容器适配器
c语言·数据结构·c++··容器适配器
謓泽10 小时前
C语言不是语法,是通往机器的地图。
c语言·开发语言
不会C语言的男孩10 小时前
Linux 系统编程 · 第 8 章:进程基础
linux·c语言
Qres82111 小时前
算法复键——树状数组
数据结构·算法
2601_9516438812 小时前
C语言长文整理,关键字和数据类型
c语言·数据类型·关键字·嵌入式开发·格式化输出
m0_5474866614 小时前
《C#语言程序设计与实践》 全套PPT课件
c语言·c#·c语言程序设计
牛油果子哥q14 小时前
并查集(DSU)超精讲,路径压缩、按秩合并、万能模板、连通性判定、最小生成树与刷题实战全解
数据结构·c++·最小生成树·并查集