在链表中使用头结点与尾指针

Java数组模拟队列以及头指针尾指针的使用(尚硅谷数据结构自学笔记) 先说一下自己对头指针和尾指针的理解 有头指针和尾指针,刚开始两个值相同,代表着队列为空或者为满的。 当添加一个数据时,尾指针向后移动,当取出数据时头指针向后移动,试想一下,每加入一个数据尾指针+1,然后和头指针就有一些距离,当取数据的时候,头指针开始+1移动,然后取一次加一次,当加到和存数据的尾部指针相同的时候,就相当于存了多少取出了多少个,就代表此时的队列为空值,或者队列为满的。 大家可以自己根据下面的代码,用数字模拟一下,或者画一个图一个数一个数的模拟一下,理清思维,会发现新大陆的,后面的循环队列 阅读详情
AI摘要

本文详细解释了链表中的头结点与尾指针的概念及其作用,并提供了具体的代码示例,帮助读者理解如何在链表操作中正确使用这些概念。

http://blog.youkuaiyun.com/jmy5945hh/article/details/7574857


1 头结点

首先,不要被以下三个词组弄混了大笑:

链表头:数据内容为第一个元素的结点。

头指针:指向头结点元素的指针。

头结点:数据内容无效,其指针是头指针。

一句话描述为:头指针是指向头结点的指针,头结点是指向链表头的结点。


对于一个链表来说,头指针是一定存在的,是访问链表的入口,如果没有头指针则无法对其进行访问;链表头对于非空表来说是一定存在的,非空表则不存在。

注意到,如果说我们不引入头结点的话,将出现操作不统一的问题:

1、对于元素访问的或者结点的引用不统一。假设pHead是头指针,pNode是指向其他链表结点的指针。此时头指针指向链表头。

[cpp]  view plain  copy
  1. pHead->Element; //对于链表头的访问  
  2. pNode->next->Element; //对于其他结点的访问  

2、对于空表与非空表的判定操作不统一。假设pHead是头指针,pNode是指向其他链表结点的指针。此时头指针指向链表头。

[cpp]  view plain  copy
  1. pHead == NULL; //对于空表的判定  
  2. pNode->next == NULL; //对于非空表是否访问到末尾的判定  

头结点的引入可以很好地解决这两个问题。首先来看看带头结点的三种链表形式。

单链表:


双链表:


循环双链表(循环单链表类同)


访问形式统一为:

[cpp]  view plain  copy
  1. p->next->Element; //统一后的元素访问  
  2. p->next == NULL; //统一后的末尾判定  

个人来讲,倾向于在链表中引入头结点。虽然多出了一块儿存储空间,但是相对于大链表来说,这个空间是微不足道的。好处是使所有的操作保持一致性代码的编写也更为简单。


引申:在队列的数据结构中, 一种实现方法是队列的头指针(或者标号)为对头的前一个位置。这种方式也可以看作为头结点的一种扩展方式。


2 尾指针

另外一种链表的技巧是使用尾指针。

尾指针是相对于头指针而言的,形式与头指针相同,内容只想链表的最后一个节点。

通常,链表的插入语删除操作都是在链表头或者链表尾进行。如果只保存一个头指针的话,要在链表尾操作时必须先遍历整个表,增加了时间复杂度,如果能再保存一个尾指针,则可以立即找到链表尾,时间复杂度降为O(1)。生气

在单向循环链表中,时常值保存一个尾指针,因为尾指针的下一个节点即是头结点。这样便可以方便地在首尾进行操作。


最后,提供一个带头结点和尾指针的单链表插入实现参考代码。

[cpp]  view plain  copy
  1. #include <stdio.h>  
  2. #include <stdlib.h>  
  3.   
  4. #define ElementType int  
  5.   
  6. struct ListNode  
  7. {  
  8.     ElementType Element;  
  9.     struct ListNode *Next;  
  10. };  
  11.   
  12. typedef struct  
  13. {  
  14.     struct ListNode *Head;  
  15.     struct ListNode *Tail;  
  16. } List, *pList;  
  17.   
  18. int InsertTail( ElementType X, pList L ) //尾部插入元素  
  19. {  
  20.     struct ListNode *newP;  
  21.   
  22.     if ( (newP = malloc(sizeof(struct ListNode))) == NULL )  
  23.     {  
  24.         perror("OUT OF SPACE!");  
  25.         return -1;  
  26.     }  
  27.   
  28.     newP->Element = X;  
  29.     newP->Next = NULL;  
  30.   
  31.     L->Tail->Next = newP;  
  32.     L->Tail = newP;  
  33.   
  34.     if ( L->Head->Next == NULL)  
  35.     {  
  36.         L->Head->Next = L->Tail;  
  37.     }  
  38.   
  39.     return 0;  
  40. }  
  41.   
  42. int InsertHead( ElementType X, pList L ) //头部插入元素  
  43. {  
  44.     struct ListNode *newP;  
  45.   
  46.     if ( (newP = malloc(sizeof(struct ListNode))) == NULL )  
  47.     {  
  48.         perror("OUT OF SPACE!");  
  49.         return -1;  
  50.     }  
  51.   
  52.     newP->Element = X;  
  53.     newP->Next = L->Head->Next;  
  54.     L->Head->Next = newP;  
  55.   
  56.     return 0;  
  57. }  
  58.   
  59.       
  60. int main()  
  61. {  
  62.     pList L;  
  63.   
  64.     if ( (L = malloc(sizeof(List))) == NULL )  
  65.     {  
  66.         perror("OUT OF SPACE!");  
  67.         return -1;  
  68.     }  
  69.   
  70.     if ( (L->Head = malloc(sizeof(struct ListNode))) == NULL )  
  71.     {  
  72.         perror("OUT OF SPACE!");  
  73.         return -1;  
  74.     }  
  75.   
  76.     L->Head->Next = NULL; //初始化  
  77.     L->Tail = L->Head;  
  78.       
  79.     InsertTail( 10, L );  
  80.     InsertTail( 11, L );  
  81.     InsertTail( 12, L ); //三次尾部插入  
  82.     InsertHead( 13, L );  
  83.     InsertHead( 14, L ); //两次头部插入  
  84.     InsertTail( 15, L );  
  85.     InsertTail( 16, L ); //两次尾部插入  
  86.   
  87.     while( L->Head->Next != NULL ) //遍历输出  
  88.     {  
  89.         printf("%d ", L->Head->Next->Element);  
  90.         L->Head = L->Head->Next;  
  91.     }  
  92.   
  93.     puts("");  
  94.   
  95.     return 0;  
  96. }  


运行结果:

[cpp]  view plain  copy
  1. jimmy@MyPet:~/code/learnc$ make  
  2. gcc -Wall -g -o test test.c -std=c99  
  3. jimmy@MyPet:~/code/learnc$ ./test   
  4. 14 13 10 11 12 15 16  
【数据结构】尾指针(Tail Pointer)详解 在数据结构的实现中,链表作为一种基本的线性结构广泛应用于计算机科学和软件工程中。链表的灵活性和动态性使其成为许多算法的基础,而尾指针则是提升链表操作效率的重要工具。本文将详细探讨尾指针的定义、作用、实现方式、使用场景以及其在实际应用中的示例。 阅读详情

相关推荐

链表队列(包含头指针和尾指针)代码实现

带头尾指针的链表队列代码实现

qq_43761725的博客 485

【数据结构】链表

引言 单链表 静态链表 循环链表和双向链表 链表的应用

高高冷的博客 9904

详解:创建链表的过程(为什么我们要使用为指针)

如何创建一个链表呢? 首先要明白结点的构成部分: struct listNode{ int data; listNode *next; }; 一个结点有两个组成部分:一个是数据域,另一个是指针域。 当我们要使用它的时候,比如说,给数据域赋值,则使用:p->data = num;链接下一个结点,理解为给指针域赋值:p->next = pNew; 为了完整地还原整个过程(实际上用视频更好解释哈哈哈)。 # include <iostream> using namespace std

qq_36950117的博客 5766

链表的头结点和尾节点的用处

某些情况下设置尾指针的好处 尾指针是指向终端结点的指针,用它来表示单循环链表可以使得查找链表的开始结点和终端结点都很方便,设一带头结点的单循环链表,其尾指针为rear,则开始结点和终端结点的位置分别是rear->next->next 和 rear, 查找时间都是O(1)。 若用头指针来表示该链表,则查找终端结点的时间为O(n)。 在链表中设置头结点的好处 头结点即在链表的首元结点(即存储

斜阳雨陌 2万+

合并两个带尾指针的循环单链表

#include typedef struct Node //结点类型定义 { char data; struct Node *next; }Node, *LinkList; //LinkList为结构指针类型 LinkList CreateCLinkList(LinkList *); LinkList Merge(LinkList, LinkList); in

zpluw芦苇之家 3355

数据结构(4)线性表之单循环链表

单循环链表,实际上就是在单链表的基础上,使最后一个结点的next指针再指向头结点,形成循环的效果。

小姚的博客 1296

头插法和尾插法创建链表(有无头结点)

头插法建表规则: 从一个空表开始,读取字符数组a中的字符,生成新节点,将读取的数据存放到新节点的数据域中,然后将新节点插入到当前链表的表头上,直到读完字符数组a的所有元素为止。 头插法建表简单,但生成的链表中节点的次序和原数组的次序相反,若希望两者的次序一致,可采用尾插法建立 尾插法建表规则: 该算法是将新节点插到当前链表的表尾上,为此必须增加一个尾指针rear,使其始终指向当前链表的尾节点 代码...

夜飘凌的博客 2464

戴尔G3/AWCC用户必看:揪出WMI Provider Host疯狂占用的元凶,附5.4.35旧版回退保姆级教程

本文针对戴尔G3/AWCC用户遇到的WMI Provider Host异常占用问题,提供了详细的诊断方法和解决方案。通过分析AWCC 5.5.14.0版本的资源占用问题,指导用户回退到稳定版AWCC 5.4.35,并附上保姆级教程和预防措施,帮助用户彻底解决系统卡顿问题。

weixin_30892037的博客 561

循环链表

循环链表和普通链表差别不大,只是将尾结点指向头结点。如果设一个尾指针指向尾结点可以使在链尾添加结点和两链表合并的操作变得简单快捷,并且尾指针所指向的结点指向的结点即为头结点,因此又可省略头指针。

MyCyber 486

中国高精度年度平均气温栅格数据集(1901-2024)

本文基于中国月度平均气温栅格数据集,计算生成1901-2024年1km分辨率的年度平均气温数据集,并按中国省市行政区划进行裁剪。该数据集融合CRU全球数据和WorldClim高分辨率数据,经496个站点验证,具有高时空精度和长时间序列特点,覆盖全国(含港澳台)逾百年气温记录,为气候变化研究、生态水文分析及农业生产评估等提供重要数据支撑。数据格式为Tif,单位为0.1℃,可获取全国、各省及各市三个尺度的气温栅格数据。

PPdata_Academy的博客 1241

从硅片到时钟:揭秘SiTime MEMS谐振子的精密制造之旅

本文深入解析了SiTime MEMS谐振子的精密制造工艺,从硅晶圆的提纯到DRIE深硅刻蚀,再到真空封装技术,揭示了其如何克服传统石英晶振的局限。通过对比测试数据,展示了MEMS谐振子在精度、可靠性和生产效率上的显著优势,特别是在5G基站和汽车电子等领域的应用潜力。

weixin_42522953的博客 401

两个循环链表的合并

循环链表通常用尾指针表示整个链表(用头指针的话找an必须从头开始找,时间复杂度为O(n)) 合并链表1和链表2: 让an结点的指针域指向b1 删去链表2的头结点 让bn结点的指针域指向链表1的头结点(在第1步前需用临时变量p保存链表1的头结点) 使之变成 也就是 LinkList Connection(LinkList r1,LinkList r2){ Node *p; p=r1->next; r1->next=r2->next-&g...

小的博客 3829

UniApp实战:5分钟搞定极光推送(JG-JPush)从配置到消息测试全流程

本文详细介绍了如何在UniApp中快速集成极光推送(JG-JPush),从基础配置到核心代码实现,再到双端调试技巧和高级功能扩展。通过5分钟全流程指南,开发者可以轻松实现消息推送功能,提升应用的用户触达率。

sat99的博客 682

C语言实现尾插法建立链表

思路:尾插法,就是从链表最后一个结点开始进行插入初始的数据来建立链表,故而肯定需要一个指针时刻指向尾部,从而确保能够从每次都只耗费O(1)的时间来初始化每一个用户录入的元素。因为如果你不这么做的话,那么你试图每次从尾部插入元素,你都得从头指针指向的头结点开始遍历,这样的话,你需要初始化的数据越多,那么你的效率就越慢。 结构体: //链表的结构体 typedef struct node{ ...

qq_36250578的博客 5686

最新Python爬虫实战(入门爬虫篇)——案例8:图书网畅销榜数据采集(详细爬虫思路截图+抓包动图演示+完整爬虫代码+详细注释)

本次案例通过 Python 爬虫技术,成功实现了对图书网畅销榜多页数据的批量爬取与 Excel 保存。代码采用模块化设计,包含分页参数构造、API 接口请求、JSON 数据解析、Excel 数据持久化等完整流程;通过配置模拟浏览器的请求头,有效规避基础反爬策略,保证请求的稳定性。整个爬虫逻辑遵循 “分页遍历 → 接口请求 → JSON 解析 → 提取图书信息 → 保存到 Excel” 的标准流程,与电商类接口爬取范式高度一致。

努力让自己发光,对的人才能迎着光而来 29万+

【Flink】FLink session yarn kerberos认证报错 PortUnreachableException: ICMP Port Unreachable

本篇博客是在上一篇博客:【Flink】FLink session yarn kerberos认证报错 KrbException: Cannot locate default realm还没找到原因的时候做的一次尝试。因为项目需要,我们需要对接华为认证的yarn集群,运行flink任务,我们的任务分为两种,yarn pre-job模式和flink session模式。我们在配置文件中配置如下# kerberos认证需要的东西提交任务的脚本如下。

九师兄 1267

链表、头指针、头结点

文章转自:     图1为线性表(ZHAO, QIAN, SUN, LI, ZHOU, WU, ZHENG, WANG)的逻辑状态。头指针 指示链表中第一个结点(即第一个数据元素的存储映像)的存储位置。同时,由于最后一个数据元素没有直接后继,则线性链表中最后一个结点的指针为“空”(NULL)。 图1 线性链表的逻辑状态 由上述描述可见,单链表可由头指针来唯一确定,在C语言

学海泛舟 479

第4章-07-将WebDriver获取的Cookie传递给Requests

在使用Selenium WebDriver获取了浏览器的Cookies之后,你可以将这些Cookies传递给requests库,以便在后续的HTTP请求中使用这些Cookies。这样做可以让你模拟浏览器会话,使得请求看起来像是从之前使用Selenium WebDriver控制的浏览器发出的。

黑夜开发者的博客 690

线性表简答题

1.多个表并存,表长度发生动态变化,表的总数也可能发生变化,采用哪种存储表示? 采用链表 如果采用顺序表,在多个表并存的情况下,一旦发现有某个表存满并溢出的情况,需要移动其他表腾出位置为其扩充空间,导致大片数据迁移,浪费时间,操作复杂,容易出错, 如果表的总数发生变化,需要开辟新表的空间,释放旧表空间 如果采用链表,在内存空间足够的情况下,各个表的空间分配或者释放不受其他表的影响 2.表的总数基本稳定,很少进行插入和删除,要求以最快的速度存取表中元素,采用哪种存储表示? 采用顺序表。表...

shlshlshk的博客 541

【2026年阿里巴巴集团暑期实习- 4月25日-算法岗-第二题- 矩阵计数】(题目+思路+Java&C++&Python解析+在线测试)

摘要: 给定两个非负整数序列a和b,构造n×m矩阵C,其中C[i][j]=a[i]×b[j]。统计矩阵中元素≥k的数量。解法是先对数组b排序,然后对于每个a[i],若k=0则直接累加m;若a[i]=0且k>0则跳过;否则计算需要的最小b[j]值,在排序后的b中使用二分查找确定满足条件的元素数量。时间复杂度为O((n+m)log m),空间复杂度O(1)。代码实现了排序和二分查找的高效组合。

m0_73659489的博客 63

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

单向循环链表的数据结构

小徐的单向循环链表问题,刚开始没仔细看,后来才整明白。 class Node(object): def __init__(self,item): self.item=item self.next=None class singleCycLinkList(object): def __init__(self): """"创建空链表""" self.__head=None def is_empty(self):

badwomen__的博客 337

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

[E链表] lc21. 合并两个有序链表(链表+二路归并+递归)

文章目录1. 题目来源2. 题目解析 1. 题目来源 链接:21. 合并两个有序链表 2. 题目解析 经典的二路归并算法,在这应用到链表中,要注意虚拟头结点和尾指针的使用。 关于递归写法在这并不是那么好理解,建议去看看题解区的大佬图解。其实就是递归实现的一个二路归并过程,只不过每次只是完成的两个节点的比较合并,每次递归过程都会将链表长度减 1,等于每次都是个新的链表,我觉得理解这个是重要的。然后最后递归返回,一层一层的返回最终答案。模拟样例,帮助理解,真事! 时间复杂度:O(n)O(n)O(n) 空间复杂度

Y-puyu 的博客 265

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

假设以带头结点的循环链表表示队列_17 链式队列及其C语言实现

从上一篇可以知道,单是顺序存储,若不是循环队列,算法的时间性能是不高的,单是循环链表有面临数组可能会溢出的问题,就引出了链式队列队列的链式存储结构,其实就是线性表的单链表, 只不过它只能尾进头出而已,叫做链队列为了方便,将队头指针指向链队列的头结点,而队尾指针指向终端结点空队列的时候,front和rear都指向头结点链队列的结构为:typedef int QElemType; /* QElemTy...

weixin_39989949的博客 868

【数据结构】循环链表和双向链表介绍

介绍了单链表,提到了单链表的一些限制,基于单链表,本文介绍循环链表和双向链表,可以解决一些对于单链表来说比较复杂的问题,对单链表不熟的可以去看。

lhr056813的博客 899
上一篇: 详解KMP算法
下一篇: 链表插入与删除操作中的头、尾指针
imJaron
博客等级 码龄11年 121粉丝 286原创
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值