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

C语言-单向循环链表带头节点的基本操作(增、删、改、查)

C语言-单向循环链表带头节点的基本操作(增、删、改、查)

前言

带头节点的单向循环链表=链表成环+永远不用判断空头。如果你已经会单链表,那么会很快上手单向循环链表。

详细代码

1、所需要包含的头文件以及定义链表的节点结构

#include <stdio.h>
#include <stdlib.h>typedef struct Node {int data;struct Node* next;
} Node;

2、创建链表(带头节点)

Node* createList() {Node* head = (Node*)malloc(sizeof(Node));if (head == NULL) {printf("内存分配失败!\n");exit(1);}head->next = head;  // 初始化为空链表return head;
}

功能说明:创建一个带有头节点的链表,头节点不存放任何数据,初始化为空链表,头节点指向自己

3、判断是否为空

int isEmpty(Node* head) {if (head == NULL) return 1;return head->next == head;
}

功能说明:第一行判断链表是否有头节点,无头节点,自然链表为空;第二行判断链表是否只有头节点;

4、指定位置插入节点(从0开始)

void insert(Node* head, int value, int position) {if (head == NULL) return;Node* newNode = (Node*)malloc(sizeof(Node));if (newNode == NULL) {printf("内存分配失败,插入节点失败!\n");return;}newNode->data = value;Node* current = head;int i = 0;// 找到插入位置的前一个节点while (i < position && current->next != head) {current = current->next;i++;}// 插入操作newNode->next = current->next;current->next = newNode;
}

功能说明:先找到插入位置的前一个节点再进行插入

5、查找节点

Node* find(Node* head, int value) {if (head == NULL) {return NULL;}Node* current = head->next;while (current != head) {if (current->data == value) {return current;}current = current->next;}return NULL;
}

6、在指定值(第一个查找到的)后面插入节点

void insertAfterValue(Node* head, int targetValue, int newValue) {if (head == NULL || head->next == head) {printf("链表为空,无法插入!\n");return;}// 查找目标节点Node* target = find(head, targetValue);if (target == NULL) {printf("未找到值 %d,插入失败!\n", targetValue);return;}// 创建新节点Node* newNode = (Node*)malloc(sizeof(Node));if (newNode == NULL) {printf("内存分配失败!\n");return;}newNode->data = newValue;// 插入到目标节点后面newNode->next = target->next;target->next = newNode;printf("在值 %d 后面插入 %d 成功!\n", targetValue, newValue);
}

功能说明
1、遍历链表找到链表中第一个和目标值相等的节点
2、创建新的节点并插入到目标值后面

7、删除指定位置的节点

int deleteAtPosition(Node* head, int position) {if (head == NULL || head->next == head) {printf("链表为空,删除失败!\n");return 0;}if (position < 0) {printf("位置不能为负数!\n");return 0;}Node* prev = head;Node* current = head->next;int i = 0;// 找到要删除的节点及其前驱while (current != head && i < position) {prev = current;current = current->next;i++;}if (current == head) {printf("位置 %d 超出链表范围,删除失败!\n", position);return 0;}// 执行删除prev->next = current->next;int deletedValue = current->data;free(current);printf("删除位置 %d 的节点(值:%d)成功!\n", position, deletedValue);return 1;
}

功能说明:找到找到要删除的节点及其前驱,然后执行删除

8、删除指定值(第一个查找到的)的节点

int deleteNode(Node* head, int value) {if (head == NULL || head->next == head) {return 0;  // 空链表}Node* prev = head;Node* current = head->next;while (current != head) {if (current->data == value) {prev->next = current->next;free(current);return 1;}prev = current;current = current->next;}return 0;  // 未找到
}

功能说明:遍历链表查找目标值的节点并记录其前驱节点,查找到后进行删除

9、修改节点

int modify(Node* head, int oldVal, int newVal) {Node* node = find(head, oldVal);if (node) {node->data = newVal;return 1;}return 0;
}

10、遍历打印

void traverse(Node* head) {if (head == NULL) {printf("链表为空指针!\n");return;}printf("链表: ");if (head->next == head) {printf("空\n");return;}Node* current = head->next;int index = 0;while (current != head) {printf("[%d]=%d", index, current->data);if (current->next != head) printf(" -> ");current = current->next;index++;}printf("\n");
}

11、获取链表长度

int getLength(Node* head) {if (head == NULL) {return 0;}int len = 0;Node* current = head->next;while (current != head) {len++;current = current->next;}return len;
}

12、销毁链表

void destroyList(Node* head) {if (head == NULL) {return;}Node* current = head->next;while (current != head) {Node* temp = current;current = current->next;free(temp);}free(head);
}

13、测试函数

void test() {printf("=== 带头节点单向循环链表测试 ===\n");// 1. 创建链表Node* list = createList();printf("1. 创建链表\n");traverse(list);// 2. 插入元素printf("\n2. 插入元素\n");insertAtPosition(list, 10, 0);  // 位置0插入10insertAtPosition(list, 20, 1);  // 位置1插入20insertAtPosition(list, 30, 2);  // 位置2插入30printf("插入10, 20, 30后: ");traverse(list);// 3. 在指定值后面插入节点printf("\n3. 在指定值后面插入节点\n");insertAfterValue(list, 10, 15);  // 在10后面插入15printf("在10后面插入15后: ");traverse(list);insertAfterValue(list, 20, 25);  // 在20后面插入25printf("在20后面插入25后: ");traverse(list);// 尝试在不存在的值后面插入insertAfterValue(list, 100, 200);// 4. 删除指定位置的节点printf("\n4. 删除指定位置的节点\n");printf("删除前: ");traverse(list);deleteAtPosition(list, 2);  // 删除位置2的节点printf("删除位置2后: ");traverse(list);deleteAtPosition(list, 0);  // 删除位置0的节点printf("删除位置0后: ");traverse(list);// 尝试删除超出范围的位置deleteAtPosition(list, 5);// 5. 边界测试printf("\n5. 边界测试\n");printf("当前链表长度: %d\n", getLength(list));// 删除所有元素printf("\n删除所有元素...\n");int len = getLength(list);for (int i = 0; i < len; i++) {deleteAtPosition(list, 0);  // 总是删除位置0}printf("清空后: ");traverse(list);// 6. 清理destroyList(list);list = NULL;printf("\n链表已销毁\n");
}int main() {test();  // 运行测试return 0;
}

总结

总体来说带头节点的单向循环链表比不带头节点的单向循环链表在边界处理上要简单许多

http://www.jsqmd.com/news/288013/

相关文章:

  • 矩阵起源荣获 DataFun 星空奖双项大奖 | 科技领航,打造企业级数据智能新基建
  • GPT-OSS显存爆了?微调最低48GB显存避坑部署教程
  • 用Qwen3-1.7B做情感陪伴AI,真的可行吗?实测告诉你
  • 靠谱的打包袋定制厂家选择哪家好,这里有答案!
  • YOLOv10-S与YOLOv9-C对比测评,延迟真的低46%吗?
  • 喜报|矩阵起源获InfoQ极客传媒2025年度技术生态构建品牌奖
  • 聊聊靠谱的液压站加工厂,启东通润如何保障产品质量和售后?
  • 2026年优质的除四害专业团队推荐
  • verl开发者必看:高效RL训练框架部署入门必看
  • 星程x工厂展的举办地址是哪,互动活动多吗,行业口碑如何?
  • 华峰钢结构项目经验靠谱吗,这些案例来证明
  • 高并发场景下Sambert表现:100QPS压力测试部署报告
  • DeepSeek-R1-Distill-Qwen-1.5B vs Qwen-1.5B:代码生成能力实战对比评测
  • 2026年知名的农村建房公司,宁波金鼎乡建解决建房诸多痛点
  • 5分钟部署Z-Image-Turbo,AI绘画一键开箱即用
  • Qwen3-Embedding-4B显存溢出?3步解决部署难题
  • 工厂自动化:用YOLOv10镜像做流水线产品计数
  • Qwen2.5-0.5B推理延迟高?CPU算力优化实战指南
  • Qwen All-in-One自动化测试:单元测试与集成验证
  • AI企业应用入门必看:Qwen3-4B开源模型部署全解析
  • 小白也能懂的Glyph教程:视觉压缩让长文本处理更简单
  • YOLOv12官版镜像上线!立即体验注意力驱动的检测黑科技
  • AutoGLM-Phone能否集成NLP模型?意图增强处理实战
  • fft npainting lama中间结果保存:多轮修复衔接操作指南
  • 必备工具清单:部署麦橘超然所需的5个Python库详解
  • 手把手教你用Z-Image-Turbo生成汉服美少女九宫格
  • Qwen2.5-0.5B模型迭代:基于用户数据的持续优化路径
  • AI头像生成新玩法:unet卡通化+社交媒体内容创作实战
  • TurboDiffusion房地产应用:样板间漫游视频自动生成
  • DeepSeek-R1-Distill-Qwen-1.5B降本方案:GPU按需计费节省50%费用