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

尾不指头:一种别致的单向循环链表

单向循环链表操作实现

单向循环链表是一种链表数据结构,和单链表不同的地方是:最后一个节点的指针不指向 null,而是指向链表的头节点,形成一个环状结构。这样从任何一个节点出发,都可以通过指针遍历整个链表。
20200726091943622

代码实现

单向循环链表的创建、插入、删除、查找等常用操作。

#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>typedef int DataType_t; 
typedef struct circularlink_manager
{DataType_t data; struct circularlink_manager *next;}Circllink_t;//用来创建一个头结点 Circllink_t* Circllink_Create(void)
{Circllink_t *Head = (Circllink_t *)calloc(1,sizeof(Circllink_t));if(Head == NULL){perror("Calloc memory for the Head is failed!\n");exit(-1);}//链表只有一个头结点时,头结点next指向自身Head->next = Head;return Head;
}//用来创建一个新的有效结点 
Circllink_t* Circllink_NewNode(DataType_t data)
{Circllink_t *New = (Circllink_t *)calloc(1,sizeof(Circllink_t));if(New == NULL){perror("Calloc memory for the Head is failed!\n");return NULL;}//新结点初始化New->data = data;New->next = NULL;return New;
}//头插(在头结点后插入一个结点)
bool Circl_HeadInsert(Circllink_t* Head,DataType_t data)
{Circllink_t *New = Circllink_NewNode(data);if (New == NULL){// 函数Circllink_NewNode给新结点内存分配失败会返回NULLreturn false; }if(Head->next == Head){//如果只有头结点,New直接成为首结点Head->next = New;New ->next = New;}else{Circllink_t *Find_Tail = Head->next;//定义指针Tail,找到并指向最后一个结点while(Find_Tail->next != Head->next){Find_Tail = Find_Tail->next;}New ->next = Head->next;Head->next = New;//更新尾结点的next,尾结点next始终指向首结点Find_Tail->next = New;
}return true;
}
//尾插
bool Circll_TailInsert(Circllink_t* Head,DataType_t data)
{Circllink_t *New = Circllink_NewNode(data);// 函数Circllink_NewNode给新结点内存分配失败会返回NULLif (New == NULL) {return false; }//如果只有头结点,New直接成为首结点if(Head->next == Head){Head->next = New;New ->next = New;}else{Circllink_t *Find_Tail = Head->next;while(Find_Tail->next != Head->next){//循环找链表最后一个结点Find_Tail = Find_Tail->next;}Find_Tail->next = New;New ->next = Head->next;}return true;
}
//指定链表位置插入结点
bool Circll_DestInsert(Circllink_t* Head,DataType_t dest,DataType_t data)
{Circllink_t *New = Circllink_NewNode(data);if (New == NULL) {return false; }if(Head->next == Head){Head->next = New;New ->next = New;return true;}Circllink_t *Find_Dest = Head->next;//遍历链表,找到数据域data等于目标值dest的结点while(Find_Dest->data != dest){	if (Find_Dest->next == Head->next){//若遍历到链表最后一个结点,data和dest还不相等,说明dest为无效指定结点位置printf("无效指定结点位置\n");return false;}Find_Dest = Find_Dest->next;}if (Find_Dest->next  == Head->next){//若遍历到链表最后一个结点,数据域data等于dest,新结点New成为尾结点Find_Dest->next = New;New->next = Head->next;}else{New->next = Find_Dest->next;Find_Dest->next = New;}return true;
}//遍历链表
bool CirLList_Print(Circllink_t *Head)
{Circllink_t *Phead = Head;if(Head->next == Head){printf("current circulinked is empty!\n");return false;}while(Phead->next){Phead = Phead->next;printf("data = %d\n",Phead->data);if(Phead->next == Head->next){	break;}}return true;
}//删除链表头结点
bool CirLList_HeadDel(Circllink_t *Head)
{Circllink_t *Phead = Head;Circllink_t *Temp  = Head->next;if(Head->next == Head){printf("current circulinked is empty!\n");return false;}//如果链表只有一个有效结点if(Head->next->next == Head->next){Head->next = Head;free(Temp);return true;}//找到最后一个结点while(Phead->next){Phead = Phead->next;if(Phead->next == Head->next){	break;}}Phead ->next = Head->next->next;//更新尾结点next的指向Head  ->next = Phead->next;Temp  ->next = NULL;free(Temp);return true;
}
//删除链表尾结点
bool CirLList_TailDel(Circllink_t *Head)
{Circllink_t *Phead = Head->next;if(Head->next == Head){printf("current circulinked is empty!\n");return false;}if(Phead->next == Head->next){//如果链表只有一个首结点(有效结点)Head->next = Head;free(Phead);Phead = NULL;return true;}while(Phead->next->next != Head->next){//找到最后一个结点Phead = Phead->next;}free(Phead->next);Phead->next = Head->next;//更新尾结点next指向return true;
}
//指定位置删除链表结点
bool cirlist_del_dest(Circllink_t* Head,DataType_t dest)
{	if(Head->next == Head){printf("current circulinked is empty!\n");return false;}Circllink_t *PreFind_Dest = Head;Circllink_t *Find_Dest = Head->next;while(Find_Dest->data != dest){	if (Find_Dest->next == Head->next){//若遍历到链表最后一个结点printf("未找到指定节点\n");return false;}PreFind_Dest = PreFind_Dest->next;Find_Dest = Find_Dest->next;}//若目标结点是唯一结点if (Find_Dest == Find_Dest->next){Head->next = Head;}else{//PreFind_Dest->next = Find_Dest->next;if(Find_Dest == Head->next){Circllink_t *Find_Tail = Head->next;while(Find_Tail->next != Head->next){//循环找链表最后一个结点Find_Tail = Find_Tail->next;}Find_Tail->next = Find_Dest->next;PreFind_Dest->next = Find_Dest->next;}else{PreFind_Dest->next = Find_Dest->next;			}}free(Find_Dest);return true;
}

主函数测试

int main(int argc, char const *argv[])
{Circllink_t *Head = Circllink_Create();printf("链表已创建\n");// 测试插入操作printf("\n=== 插入测试 ===\n");Circl_HeadInsert(Head, 10);  // 头插 10Circl_HeadInsert(Head, 20);  // 头插 20Circll_TailInsert(Head, 30); // 尾插 30Circll_TailInsert(Head, 40); // 尾插 40Circll_DestInsert(Head, 30, 35); // 在 30 后插入 35// 打印链表printf("\n插入后的链表:\n");CirLList_Print(Head);//预估结果:20,10 30 35 40// 测试删除操作printf("\n=== 删除测试 ===\n");printf("删除指定值 20 的节点:\n");if (cirlist_del_dest(Head, 20)) {printf("删除成功\n");} else {printf("删除失败\n");}CirLList_Print(Head);printf("\n删除头节点:\n");if (CirLList_HeadDel(Head)) {printf("删除成功\n");} else {printf("删除失败\n");}CirLList_Print(Head);printf("\n删除尾节点:\n");if (CirLList_TailDel(Head)) {printf("删除成功\n");} else {printf("删除失败\n");}// 再次打印链表printf("\n删除后的链表:\n");CirLList_Print(Head);//预估结果:30 35 // 释放头节点free(Head);printf("\n链表已释放\n");return 0;
}

测试结果

vmware_ihGBasSdkg

细心的读者可能会发现:在本实现中,链表的最后一个有效节点的 next 指向的是第一个有效节点(即 Head->next),而不是头结点 Head 本身。这与部分教材中“尾节点指向头结点”的描述略有不同。

设计思想:头结点是“管理节点”,不参与数据循环

在我的实现中,头结点(Head)被定义为一个纯管理性质的辅助节点,它不存储任何有效数据,也不应被纳入“数据节点”的循环逻辑中。真正的数据循环只发生在所有有效数据节点之间

  • 尾节点的 next 指向第一个有效节点(Head->next),形成一个仅包含有效数据节点的闭环

  • 头结点 Head 仅作为入口指针和结构管理存在,不参与数据环。

无论采用哪种方式,只要在整个代码中保持统一逻辑,应该都是合理的实现。

http://www.sczhlp.com/news/4870/

相关文章:

  • 软工8.3
  • Hive环境搭建
  • 带返回值方法的定义
  • 2.9 rt-thread实操 stm32l496 w5500
  • 最好的MPI集群环境搭建教程网站 - 仰望星空-自然
  • 什么是 API?
  • 神谷活心流x飞天御剑流
  • MySQl查询分析工具 EXPLAIN ANALYZE
  • MySQL查询计划
  • javaRveShell详解
  • Spark SQL使用
  • InnoDB行格式
  • 学习之道 反思 神经模型
  • 女生对男朋友的期待与幻想分析
  • MX-2025 盖世计划 C 班 Day 1 复盘
  • atomic不是免费午餐
  • 方法定义(带参数)+调用
  • 小智服务器部署 - MKT
  • 卷积神经网络CNN
  • 8月3日
  • AX-MES生产制造管理系统-异常管理 - AX
  • 16
  • 2024_8_3模拟赛
  • 7.15
  • Ansible 零基础到精通实战指南
  • IIC通信
  • webstorm2025版本激活教程
  • 二叉搜索树
  • iOS安全和逆向系列教程 第20篇:Objective-C运行时机制深度解析与Hook技术 - 教程