news 2026/3/24 7:13:51

结构体与链表

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
结构体与链表

结构体与链表
在 C 语言中,结构体是一种用户自定义的数据类型,它可以把不同类型的数据组合在一起,形成一个整体。
struct Node {
int data;
struct Node *next;
};
这段代码定义了一个叫 Node 的结构体,它有两个成员:

  • int data:用来存储实际的数据,比如整数。
  • struct Node *next:是一个指针,指向下一个 Node 类型的结构体。
    结构体的内存布局
    当我们定义了一个 struct Node,编译器会为它分配一块连续的内存空间,大小等于所有成员占用空间之和。
    假设 int 占 4 字节,指针也占 8 字节(64位系统),那么每个 Node 节点总共占 12 字节(或更多,因对齐规则可能增加)。

如何创建链表节点
静态创建
struct Node node1;
struct Node node2;
struct Node node3;
struct Node node4;

node1.data = 1;
node2.data = 2;
node3.data = 3;
node4.data = 4;

node1.next = &node2;
node2.next = &node3;
node3.next = &node4;

  • 这里是直接在栈上声明变量,四个 Node 对象都存放在程序的栈区。
  • 每个节点有名字(如 node1),可以通过名字访问。
  • 使用 &node2 获取 node2 的地址,赋值给 node1.next,就建立了连接。
    动态创建
    struct Node *node1 = (struct Node *)malloc(sizeof(struct Node));
    struct Node *node2 = (struct Node *)malloc(sizeof(struct Node));
    // … 其他节点
  • 使用 malloc() 在堆(heap) 上申请内存。
  • 返回的是一个指向该内存的指针,所以我们必须用指针接收。
  • 每个节点都是独立申请的,可以随时增删。
    起别名
    typedef struct Node {
    int data;
    struct Node *next;
    } Node, LinkNode, *sNode;
    typedef struct Node {…} Node;
    给 struct Node 起了个别名 Node,以后可以直接写 Node 而不用写 struct Node。比如:Node node1; 就等价于 struct Node node1;
    LinkNode 是另一个别名可以当作 Node 的别名使用,用于命名一致性。
    *sNode 是指针类型的别名,sNode 表示“指向 Node 结构体的指针”
    所以 sNode node4; 相当于 struct Node *node4;
    链接链表
    node1->data = 1;
    node2->data = 2;
    node3->data = 3;
    node4->data = 4;

node1->next = node2;
node2->next = node3;
node3->next = node4;
node1 → node2 → node3 → node4 → NULL
内存地址: 0x1000 0x2000 0x3000 0x4000
±---------±---------±---------±---------+
| data=1 | next=0x2000| data=2 | next=0x3000| …
±---------±---------±---------±---------+
遍历读取链表

voidprintList(Node*head){for(Node*cur=head;cur!=NULL;cur=cur->next){printf("%d",cur->data);if(cur->next!=NULL){printf("->");}}printf("\n");}

插入/删除链表
插入链表:

intinsertAt(Node**head,intindex,intvalue){intlen=getListLen(*head);if(index<0||index>len){return-1;// 插入失败}Node*newNode=(Node*)malloc(sizeof(Node));if(!newNode){return-1;}newNode->data=value;if(index==0){newNode->next=*head;*head=newNode;}else{Node*prev=*head;for(inti=0;i<index-1;i++){prev=prev->next;}newNode->next=prev->next;prev->next=newNode;}return0;}

这里传参需要二维指针是因为需要修改指针指向,若一维指针只是拷贝传递。
删除链表:

// 删除第一个值为 data 的节点voiddelList(Node**head,intdata){if(*head==NULL)return;// 如果要删除的是头节点if((*head)->data==data){Node*temp=*head;*head=(*head)->next;free(temp);return;}Node*cur=*head;while(cur->next!=NULL){if(cur->next->data==data){Node*temp=cur->next;cur->next=cur->next->next;free(temp);return;// 只删第一个匹配项}cur=cur->next;}}

双向链表

#include<stdio.h>#include<stdlib.h>typedefstructNode{intdata;structNode*next;structNode*prev;}Node;// 获取链表长度intgetListLen(Node*head){inti=0;for(Node*cur=head;cur!=NULL;cur=cur->next){i++;}returni;}intinsertAt(Node**head,intindex,intvalue){intlen=getListLen(*head);if(index<0||index>len){return-1;}Node*newNode=(Node*)malloc(sizeof(Node));if(!newNode){return-1;}newNode->data=value;newNode->next=NULL;newNode->prev=NULL;if(index==0){newNode->next=*head;if(*head!=NULL){(*head)->prev=newNode;}*head=newNode;}else{Node*cur=*head;for(inti=0;i<index;i++){cur=cur->next;}newNode->next=cur;newNode->prev=cur->prev;cur->prev->next=newNode;cur->prev=newNode;}return0;}// 输出链表voidprintList(Node*head){for(Node*cur=head;cur!=NULL;cur=cur->next){printf("%d",cur->data);if(cur->next!=NULL){printf("->");}}printf("\n");}// 删除第一个值为 data 的节点voiddelList(Node*head,intdata){if(head==NULL)return;Node*cur=head;while(cur!=NULL){if(cur->data==data){if(cur->prev!=NULL){cur->prev->next=cur->next;}else{head=cur->next;// 删除头节点}if(cur->next!=NULL){cur->next->prev=cur->prev;}free(cur);return;}cur=cur->next;}}intmain(){constintN=4;intvalues[N]={10,20,30,40};Node*head=NULL;Node*tail=NULL;// 使用头插法for(inti=0;i<N;i++){Node*newNode=(Node*)malloc(sizeof(Node));if(!newNode){return-1;}newNode->data=values[i];newNode->next=NULL;newNode->prev=tail;if(head==NULL){head=tail=newNode;}else{;tail=newNode;}}intlen=getListLen(head);printf("链表长度: %d\n",len);// 插入printf("index=2 ,99");if(insertAt(&head,2,99)==0){printf("插入后: ");printList(head);}// 删除printf("请输入要删除的数据: ");intdata;scanf("%d",&data);delList(head,data);printf("删除后: ");printList(head);return0;}
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/3/24 0:02:56

深蓝词库转换:从新手到专家的20种输入法格式互通指南

深蓝词库转换&#xff1a;从新手到专家的20种输入法格式互通指南 【免费下载链接】imewlconverter ”深蓝词库转换“ 一款开源免费的输入法词库转换程序 项目地址: https://gitcode.com/gh_mirrors/im/imewlconverter 还在为不同输入法之间的词库不兼容而烦恼吗&#xf…

作者头像 李华
网站建设 2026/3/15 23:50:07

GLM-TTS - 自然、富有情感和表现力的语音克隆/文本转语音系统 支持批量生成 支持50系显卡 一键整合包下载

GLM-TTS 是智谱AI开源的一个新型的文本转语音&#xff08;TTS&#xff09;系统&#xff0c;它能在“零样本”条件下模仿声音&#xff0c;在极少的语音样本模仿声音&#xff0c;生成自然、有情绪的语音&#xff0c;并且让合成语音更有情感和表现力。它的特点是可控、自然、支持实…

作者头像 李华
网站建设 2026/3/23 21:54:33

Termius中文汉化版:极速上手的移动端SSH神器

Termius中文汉化版&#xff1a;极速上手的移动端SSH神器 【免费下载链接】Termius-zh_CN 汉化版的Termius安卓客户端 项目地址: https://gitcode.com/alongw/Termius-zh_CN 还在为英文SSH客户端而头疼吗&#xff1f;每次连接服务器都要面对满屏的英文界面和难以理解的错…

作者头像 李华
网站建设 2026/3/22 2:22:08

Vue PDF嵌入组件:构建现代化文档预览体验的完整指南

Vue PDF嵌入组件&#xff1a;构建现代化文档预览体验的完整指南 【免费下载链接】vue-pdf-embed PDF embed component for Vue 2 and Vue 3 项目地址: https://gitcode.com/gh_mirrors/vu/vue-pdf-embed 在当今数字化办公时代&#xff0c;PDF文档已成为企业信息传递和知…

作者头像 李华
网站建设 2026/3/18 6:54:50

MouseTester终极指南:从性能瓶颈诊断到精准优化实战

MouseTester终极指南&#xff1a;从性能瓶颈诊断到精准优化实战 【免费下载链接】MouseTester 项目地址: https://gitcode.com/gh_mirrors/mo/MouseTester 还在为鼠标响应延迟、光标漂移等问题困扰&#xff1f;专业鼠标性能测试工具MouseTester通过开源技术方案&#x…

作者头像 李华