尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

【数据结构实战】单向循环单链表判别条件理解

【数据结构实战】单向循环单链表判别条件理解 单向循环链表循环链表(Circular Linked List)是另一种形式的链式存储结构。其特点是表中最后一个节点的指针域指向头节点整个链表形成一个环。当链表遍历时判别当前指针p是否指向表尾结点的终止条件不同。在单链表中判别条件为 p!NULL或 p-next!NULL而循环单链表的判别条件为p!L 或 p-next!L。1. 核心区别为什么不能用NULL普通单链表尾节点的next指针是NULL遍历到p NULL或p-next NULL就知道到表尾了。循环单链表尾节点的next指针直接指向头节点L整个链表是一个闭环没有NULL指针所以不能用NULL作为终止标志。2. 两个判别条件的含义假设头指针是L当前遍历指针是p条件 1p ! L适用场景从L-next第一个数据节点开始遍历逻辑当p再次回到头节点L时说明已经绕了一圈遍历结束遍历顺序0 → 70 → 80当p回到L头节点时停止。p L-next; // 从第一个数据节点开始 while (p ! L) { // 处理 p 节点 p p-next; }条件 2p-next ! L适用场景从L或某个节点开始要遍历到尾节点逻辑当p-next L时说明p就是尾节点p L; while (p-next ! L) { p p-next; } // 循环结束时p 指向尾节点80这样可以直接定位到尾节点方便在尾部插入等操作。3. 直观类比把循环链表想象成环形跑道头节点L是「起点 / 终点」普通单链表是「直跑道」跑到尽头就是NULL循环单链表是「环形跑道」永远跑不到NULL只能用「回到起点」作为结束信号4. 易错点提醒❌ 不要写成p ! NULL循环链表没有NULL会导致死循环✅ 必须用p L或p-next L作为终止判断一句话总结循环单链表没有 NULL 终点所以用「回到头节点 L」作为遍历结束的标志遍历所有数据节点 →p ! L找到尾节点 →p-next ! L完整 C 语言代码循环单链表遍历含两种判别条件下面的代码包含创建循环单链表、遍历所有节点、定位尾节点三个核心功能带你直观理解两种判别条件的用法。#include stdio.h #include stdlib.h // 定义循环单链表节点结构 typedef struct Node { int data; // 数据域 struct Node *next; // 指针域 } Node, *CircularLinkList; // 1. 初始化循环单链表带头节点 CircularLinkList InitList() { // 创建头节点 CircularLinkList L (Node *)malloc(sizeof(Node)); if (L NULL) { printf(内存分配失败\n); exit(1); } L-next L; // 循环链表头节点的next指向自己空表 return L; } // 2. 尾插法添加节点构建有数据的循环链表 void AddNode(CircularLinkList L, int data) { // 创建新节点 Node *newNode (Node *)malloc(sizeof(Node)); newNode-data data; // 找到尾节点用判别条件p-next ! L Node *p L; while (p-next ! L) { // 核心尾节点的next指向头节点L p p-next; } // 插入新节点维持循环结构 newNode-next L; // 新节点的next指向头节点 p-next newNode; // 原尾节点指向新节点 } // 3. 遍历所有数据节点用判别条件p ! L void TraverseList(CircularLinkList L) { if (L-next L) { // 空表判断 printf(链表为空\n); return; } printf(循环链表遍历结果); Node *p L-next; // 从第一个数据节点开始 while (p ! L) { // 核心遍历到回到头节点L为止 printf(%d , p-data); p p-next; } printf(\n); } // 4. 定位并打印尾节点验证 p-next L void FindTailNode(CircularLinkList L) { if (L-next L) { printf(链表为空无尾节点\n); return; } Node *p L; while (p-next ! L) { // 找到尾节点尾节点的next是L p p-next; } printf(循环链表的尾节点数据%d\n, p-data); } int main() { // 步骤1初始化循环链表 CircularLinkList L InitList(); // 步骤2添加节点数据10、20、30 AddNode(L, 10); AddNode(L, 20); AddNode(L, 30); // 步骤3遍历所有节点验证 p ! L TraverseList(L); // 步骤4定位尾节点验证 p-next L FindTailNode(L); return 0; }代码关键解释初始化逻辑空的循环单链表头节点L的next直接指向自己L-next L这是循环链表的基础特征。添加节点尾插法用p-next ! L找到尾节点因为尾节点是最后一个节点它的next必须指向头节点L所以当p-next L时p就是尾节点。新节点插入后要保证newNode-next L维持 “循环” 特性。遍历节点从L-next第一个数据节点开始用p ! L作为终止条件只要p没回到头节点就继续遍历避免死循环。运行结果❌ 易错点演示千万别这么写如果把遍历的终止条件写成p ! NULL会触发死循环// 错误示例仅演示不要运行 Node *p L-next; while (p ! NULL) { // 循环链表没有NULL会无限循环 printf(%d , p-data); p p-next; }总结循环单链表无NULL指针核心判别依据是「是否回到头节点L」。p ! L用于遍历所有数据节点从第一个数据节点开始。p-next ! L用于定位尾节点从任意节点开始找尾。
返回列表