从零开始学数据结构系列之第一章《双链表》

2024-05-28 06:12

本文主要是介绍从零开始学数据结构系列之第一章《双链表》,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

  • 双链表的定义
  • 双链表上的操作
  • 初始化
  • 插入操作
  • 头插法
  • 尾插法
  • 删除操作
  • 总代码
  • 往期回顾


双链表的定义

为什么引入双链表?

  单链表的结点中只有一个指向其后继的指针,使得单链表要访问某个结点的前驱结点时,只能从头开始遍历,访问后驱结点的复杂度为O(1),访问前驱结点的复杂度为O(n)。为了克服上述缺点,引入了双链表。

  双链表的结点中有两个指针prior和next,分别指向前驱结点和后继结点。

双链表中结点类型的描述:

typedef struct Node
{int data;struct Node *next;struct Node *pre;
}Node;

双链表上的操作

​   双链表与单链表一样,为了操作方便也可以加入头结点,那么初始化双链表其实就是定义一个头结点,然后将指针域置空。
在这里插入图片描述

初始化

/* 
数据总数data 清零
同时列表的前端与后继都指向为空
*/
Node* InitList()
{Node* list = (Node*)malloc(sizeof(Node));  list -> data = 0;   list -> next = NULL;list -> pre = NULL;return list;
}

在这里插入图片描述

插入操作

  在双链表中p所指的结点之后插入结点*s,其指针的变化过程如下图所示:

头插法

/* 
注意,这是头插法,
所以待插入列表数据的前端永远指向原先列表
待插入列表数据的后端如果是第一次插入则指向为空,后续都指向下一个列表
这里涉及到了4条“线”的连接
*/
void headInsert(Node* list, int data)
{Node* node = (Node*)malloc(sizeof(Node));  node -> data = data;node -> next = list -> next;node -> pre = list;/** 注意,这里是以防第一次插入的时候* 不能是NULL直接指向node*/if(list -> next){list -> next ->pre = node;}list -> next = node;list -> data++;
}

尾插法

/* 
这里涉及到了4条“线”的连接
尾插法最主要是找到最后一项的位置
待插入列表数据的后继永远指向NULL,也就是list -> next
*/
void tailInsert(Node* list, int data)
{Node* head = list;Node* node = (Node*)malloc(sizeof(Node));  node -> data = data;while(list -> next){list = list -> next;}node -> next = list -> next;node -> pre = list;list -> next = node;head ->data ++;  
}

删除操作

void delete(Node* list, int data) 
{Node* preNode = list;Node* node = list -> next;while(node){if(node -> data == data) {preNode -> next = node->next;/*防止最后一项删除不掉,如果是最后一项的话,不需要执行这一步操作,如果执行了就是NULL前项指向preNode了*/if(node -> next)node -> next -> pre = preNode;free(node);list -> data--;break;}preNode = node;node = node -> next;}
}

总代码

#include <stdio.h>
#include "stdlib.h"typedef struct Node
{int data;struct Node *next;struct Node *pre;
}Node;Node* InitList()
{Node* list = (Node*)malloc(sizeof(Node));  list -> data = 0;   list -> next = NULL;list -> pre = NULL;return list;
}void headInsert(Node* list, int data)
{Node* node = (Node*)malloc(sizeof(Node));  node -> data = data;node -> next = list -> next;node -> pre = list;	if(list -> next){list -> next ->pre = node;}list -> next = node;list -> data++;
}void tailInsert(Node* list, int data)
{Node* head = list;Node* node = (Node*)malloc(sizeof(Node));  node -> data = data;while(list -> next){list = list -> next;}node -> next = list -> next;node -> pre = list;list -> next = node;head ->data ++;  
}void delete(Node* list, int data) 
{Node* preNode = list;Node* node = list -> next;while(node){if(node -> data == data) {preNode -> next = node->next;if(node -> next)node -> next -> pre = preNode;free(node);list -> data--;break;}preNode = node;node = node -> next;}
}void printfList(Node* list)
{Node* head = list;list = list -> next;while(list != NULL){printf("%d->", list -> data);list = list -> next;}printf("NULL\n");
}void main()
{Node* list = InitList();headInsert(list,1);headInsert(list,2);headInsert(list,3);headInsert(list,3);tailInsert(list,4);tailInsert(list,5);tailInsert(list,6);printfList(list);delete(list,3);delete(list,6);printfList(list);}

在这里插入图片描述

往期回顾

1.【第一章】《线性表与顺序表》
2.【第一章】《单链表》
3.【第一章】《单链表的介绍》
4.【第一章】《单链表的基本操作》
5.【第一章】《单链表循环》

这篇关于从零开始学数据结构系列之第一章《双链表》的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1009749

相关文章

Spring Security 从入门到进阶系列教程

Spring Security 入门系列 《保护 Web 应用的安全》 《Spring-Security-入门(一):登录与退出》 《Spring-Security-入门(二):基于数据库验证》 《Spring-Security-入门(三):密码加密》 《Spring-Security-入门(四):自定义-Filter》 《Spring-Security-入门(五):在 Sprin

【数据结构】——原来排序算法搞懂这些就行,轻松拿捏

前言:快速排序的实现最重要的是找基准值,下面让我们来了解如何实现找基准值 基准值的注释:在快排的过程中,每一次我们要取一个元素作为枢纽值,以这个数字来将序列划分为两部分。 在此我们采用三数取中法,也就是取左端、中间、右端三个数,然后进行排序,将中间数作为枢纽值。 快速排序实现主框架: //快速排序 void QuickSort(int* arr, int left, int rig

科研绘图系列:R语言扩展物种堆积图(Extended Stacked Barplot)

介绍 R语言的扩展物种堆积图是一种数据可视化工具,它不仅展示了物种的堆积结果,还整合了不同样本分组之间的差异性分析结果。这种图形表示方法能够直观地比较不同物种在各个分组中的显著性差异,为研究者提供了一种有效的数据解读方式。 加载R包 knitr::opts_chunk$set(warning = F, message = F)library(tidyverse)library(phyl

【生成模型系列(初级)】嵌入(Embedding)方程——自然语言处理的数学灵魂【通俗理解】

【通俗理解】嵌入(Embedding)方程——自然语言处理的数学灵魂 关键词提炼 #嵌入方程 #自然语言处理 #词向量 #机器学习 #神经网络 #向量空间模型 #Siri #Google翻译 #AlexNet 第一节:嵌入方程的类比与核心概念【尽可能通俗】 嵌入方程可以被看作是自然语言处理中的“翻译机”,它将文本中的单词或短语转换成计算机能够理解的数学形式,即向量。 正如翻译机将一种语言

6.1.数据结构-c/c++堆详解下篇(堆排序,TopK问题)

上篇:6.1.数据结构-c/c++模拟实现堆上篇(向下,上调整算法,建堆,增删数据)-CSDN博客 本章重点 1.使用堆来完成堆排序 2.使用堆解决TopK问题 目录 一.堆排序 1.1 思路 1.2 代码 1.3 简单测试 二.TopK问题 2.1 思路(求最小): 2.2 C语言代码(手写堆) 2.3 C++代码(使用优先级队列 priority_queue)

flume系列之:查看flume系统日志、查看统计flume日志类型、查看flume日志

遍历指定目录下多个文件查找指定内容 服务器系统日志会记录flume相关日志 cat /var/log/messages |grep -i oom 查找系统日志中关于flume的指定日志 import osdef search_string_in_files(directory, search_string):count = 0

《数据结构(C语言版)第二版》第八章-排序(8.3-交换排序、8.4-选择排序)

8.3 交换排序 8.3.1 冒泡排序 【算法特点】 (1) 稳定排序。 (2) 可用于链式存储结构。 (3) 移动记录次数较多,算法平均时间性能比直接插入排序差。当初始记录无序,n较大时, 此算法不宜采用。 #include <stdio.h>#include <stdlib.h>#define MAXSIZE 26typedef int KeyType;typedef char In

GPT系列之:GPT-1,GPT-2,GPT-3详细解读

一、GPT1 论文:Improving Language Understanding by Generative Pre-Training 链接:https://cdn.openai.com/research-covers/languageunsupervised/language_understanding_paper.pdf 启发点:生成loss和微调loss同时作用,让下游任务来适应预训

生信代码入门:从零开始掌握生物信息学编程技能

少走弯路,高效分析;了解生信云,访问 【生信圆桌x生信专用云服务器】 : www.tebteb.cc 介绍 生物信息学是一个高度跨学科的领域,结合了生物学、计算机科学和统计学。随着高通量测序技术的发展,海量的生物数据需要通过编程来进行处理和分析。因此,掌握生信编程技能,成为每一个生物信息学研究者的必备能力。 生信代码入门,旨在帮助初学者从零开始学习生物信息学中的编程基础。通过学习常用

Java基础回顾系列-第七天-高级编程之IO

Java基础回顾系列-第七天-高级编程之IO 文件操作字节流与字符流OutputStream字节输出流FileOutputStream InputStream字节输入流FileInputStream Writer字符输出流FileWriter Reader字符输入流字节流与字符流的区别转换流InputStreamReaderOutputStreamWriter 文件复制 字符编码内存操作流(