当前位置: 首页 > news >正文

数据结构——双链表

目录

  • 1 双链表的概念
  • 2 双链表的结构
  • 3 双链表的操作
    • 3.1 双链表的初始化
    • 3.2 双链表的尾插
    • 3.3 双链表的头插
    • 3.4 双链表的尾删
    • 3.5 双链表的头删
    • 3.6 双链表的查找
    • 3.7 在指定位置后插入新结点
    • 3.8 删除指定结点
    • 3.9 释放双链表
  • 4 双链表整体实现

1 双链表的概念

双链表一般指的是双向循环带头结点的链表
循环
链表首尾连接,可以通过尾结点找到头结点,也可以通过头结点找到尾结点
头结点
在链表的头部设置一个结点,它不存储任何有效数据,用来简化操作
双向
链表的每个结点设置一前一后两个指针,分别指向前一个结点和后一个结点

图示
在这里插入图片描述

2 双链表的结构

双链表的每个结点都包含了数据域和一前一后的指针域,因此结构如下:

//双向链表
typedef int LTDataType;
typedef struct ListNode
{struct ListNode* prev; //指向前一个结点的指针LTDataType data; //数据struct ListNode* next; //指向下一个结点的指针
}LTNode;

3 双链表的操作

3.1 双链表的初始化

由于双链表有头结点,因此在创建双链表时,要先为其创建一个头结点,并使它的前后指针指向自己
在这里插入图片描述
代码实现

//创建新结点
LTNode* LTCreateNode(LTDataType x)
{LTNode* node = (LTNode*)malloc(sizeof(LTNode));assert(node);node->data = x;node->prev = node;node->next = node;return node;
}//双向链表初始化
LTNode* LTInit()
{LTNode* head = LTCreateNode(-1);return head;
}

3.2 双链表的尾插

head 指向了头结点,node 为新创建的结点,prev 为指向前一个结点的指针,next 为指向后一个结点的指针
在这里插入图片描述

void LTPushBack(LTNode* head, LTDataType x)
{assert(head);LTNode* node = LTCreateNode(x);node->prev = head->prev;node->next = head;head->prev = node;node->prev->next = node;
}

3.3 双链表的头插

head 指向了头结点,node 为新创建的结点,prev 为指向前一个结点的指针,next 为指向后一个结点的指针
在这里插入图片描述
代码实现

void LTPushFront(LTNode* head, LTDataType x)
{assert(head);LTNode* node = LTCreateNode(x);node->prev = head;node->next = head->next;head->next = node;node->next->prev = node;}

3.4 双链表的尾删

del 为要删除的结点,prev 指向了前一个结点,next 指向了后一个结点
在这里插入图片描述
代码实现

void LTPopBack(LTNode* head)
{assert(head && head->prev != head);LTNode* del = head->prev; //记录尾节点del->prev->next = head;head->prev = del->prev;free(del);del = NULL;}

3.5 双链表的头删

del 为要删除的结点,prev 指向了前一个结点,next 指向了后一个结点
在这里插入图片描述
代码实现

//头删
void LTPopFront(LTNode* head)
{assert(head && head->next != head);LTNode* del = head->next;del->next->prev = del->prev;del->prev->next = del->next;free(del);del = NULL;
}

3.6 双链表的查找

x 为要查找的值,通过 cur 指针来遍历链表,查找到结点时,返回结点,未查找到则返回空指针
在这里插入图片描述
代码实现

LTNode* LTFind(LTNode* head, LTDataType x)
{assert(head);LTNode* cur = head->next;while (cur != head){if (cur->data == x){return cur;}cur = cur->next;}return NULL;
}

3.7 在指定位置后插入新结点

pos 为指定的位置,node 为新结点,prev 指针指向前一个结点,next 指针指向后一个结点
在这里插入图片描述
代码实现

void LTInsert(LTNode* pos, LTDataType x)
{assert(pos);LTNode* node = LTCreateNode(x);//pos node pos->nextnode->next = pos->next;node->prev = pos;pos->next->prev = node;pos->next = node;
}

3.8 删除指定结点

pos 为指定的结点,prev 指针指向前一个结点,next 指针指向后一个结点
在这里插入图片描述
代码实现

void LTErase(LTNode* pos)
{assert(pos);pos->next->prev = pos->prev;pos->prev->next = pos->next;free(pos);pos = NULL;}

3.9 释放双链表

cur 指向要释放的结点,tail 则用来记录下一个要释放的结点
在这里插入图片描述
代码实现

void LTDestroy(LTNode* head)
{assert(head);LTNode* cur = head->next;while (cur != head){LTNode* tail = cur->next;free(cur);cur = tail;}free(cur);cur = NULL;
}

4 双链表整体实现

List.c

#include "List.h"
//函数的实现//创建新结点
LTNode* LTCreateNode(LTDataType x)
{LTNode* node = (LTNode*)malloc(sizeof(LTNode));assert(node);node->data = x;node->prev = node;node->next = node;return node;
}//双向链表初始化
LTNode* LTInit()
{LTNode* head = LTCreateNode(-1);return head;
}//打印
void LTPrint(LTNode* head)
{assert(head);LTNode* cur = head->next;while (cur != head){printf("%d->", cur->data);cur = cur->next;}printf("\n");
}//尾插
void LTPushBack(LTNode* head, LTDataType x)
{assert(head);LTNode* node = LTCreateNode(x);//第一种写法//node->prev = head->prev;//node->next = head;//head->prev->next = node;//head->prev = node;//第二种写法node->prev = head->prev;node->next = head;head->prev = node;node->prev->next = node;
}//头插
void LTPushFront(LTNode* head, LTDataType x)
{assert(head);LTNode* node = LTCreateNode(x);//第一种写法//node->prev = head;//node->next = head->next;//head->next->prev = node;//head->next = node;//第二种写法node->prev = head;node->next = head->next;head->next = node;node->next->prev = node;}//尾删
void LTPopBack(LTNode* head)
{assert(head && head->prev != head);LTNode* del = head->prev; //记录尾节点del->prev->next = head;head->prev = del->prev;free(del);del = NULL;}//头删
void LTPopFront(LTNode* head)
{assert(head && head->next != head);LTNode* del = head->next;del->next->prev = del->prev;del->prev->next = del->next;free(del);del = NULL;
}//查找
LTNode* LTFind(LTNode* head, LTDataType x)
{assert(head);LTNode* cur = head->next;while (cur != head){if (cur->data == x){return cur;}cur = cur->next;}return NULL;
}//pos后插入数据
void LTInsert(LTNode* pos, LTDataType x)
{assert(pos);LTNode* node = LTCreateNode(x);//pos node pos->nextnode->next = pos->next;node->prev = pos;pos->next->prev = node;pos->next = node;
}//删除pos结点
void LTErase(LTNode* pos)
{assert(pos);pos->next->prev = pos->prev;pos->prev->next = pos->next;free(pos);pos = NULL;}//释放链表
void LTDestroy(LTNode* head)
{assert(head);LTNode* cur = head->next;while (cur != head){LTNode* tail = cur->next;free(cur);cur = tail;}free(cur);cur = NULL;
}//判断链表是否为空
bool LTEmpty(LTNode* head)
{assert(head);if (head->next == head)return true;return false;
}

List.h

//结构体,函数的声明
#pragma once
#include <stdlib.h>
#include <assert.h>
#include <stdio.h>
#include <stdbool.h>//双向链表
typedef int LTDataType;
typedef struct ListNode
{LTDataType data; //数据struct ListNode* prev; //指向前一个结点的指针struct ListNode* next; //指向下一个结点的指针
}LTNode;//初始化
LTNode* LTInit();//打印
void LTPrint(LTNode* head);//尾插
void LTPushBack(LTNode* head, LTDataType x);//头插
void LTPushFront(LTNode* head, LTDataType x);//尾删
void LTPopBack(LTNode* head);//头删
void LTPopFront(LTNode* head);//查找
LTNode* LTFind(LTNode* head, LTDataType x);//pos后插入数据
void LTInsert(LTNode* pos, LTDataType x);//删除pos结点
void LTErase(LTNode* pos);//释放链表
void LTDestroy(LTNode* head);//判断是否为空链表
bool LTEmpty(LTNode* head);
http://www.dtcms.com/a/340111.html

相关文章:

  • 人工智能细分方向全景图:从入门到专精的技术路径
  • AI出题人给出的Java后端面经(十⑨)(日更)
  • 零成本上线个人网站 | Cloudflare Pages 全流程实战指南
  • A股大盘数据-20250819 分析
  • redis基础----通用命令
  • 脑电分析——ICA原理、ICALabel成分与伪迹之间一对多的关系
  • 从合规到主动免疫:大模型内容风控的创新与实践
  • 【PyTorch】单对象分割项目
  • Seata笔记
  • Day22 顺序表与链表的实现及应用(含字典功能与操作对比)
  • 不同语言的并发模型对比:Go、Java与Python
  • Python脚本每天爬取微博热搜-终版
  • 重塑酒店投屏体验:私密投屏技术的革新应用
  • GStreamer无线图传:从树莓派到计算机的实现方案
  • 20250819 强连通分量,边双总结
  • 嵌入式-SPI的IO引脚初始化、模块初始化、数据的收发-Day16
  • Codeforces 盒装苹果
  • vLLM加载lora
  • CF266E More Queries to Array... Solution
  • GPFS不同存储方式的优劣
  • 2943. 最大化网格图中正方形空洞的面积
  • Manus AI 与多语言手写识别技术深度剖析
  • 不同的 Text2sql 方式优缺点探究
  • 智慧校园中IPTV融合对讲:构建高效沟通新生态
  • Unity常用工具及默认快捷键
  • PowerBI登录出错解决过程
  • YOLO多模态改进系列 | YOLOFuse:多模态融合的 Slim-Neck 改进
  • java面试——多线程
  • C++高频知识点(二十九)
  • HarmonyOS 中的 泛型类和泛型接口