数据结构入门指南

数据结构入门指南:线性结构核心知识点与C语言实现

数据结构是程序设计的基石,直接决定代码的效率与可扩展性,尤其在Linux内核开发、嵌入式设备资源管理等场景中,合理运用数据结构能显著优化程序性能。本文聚焦入门必学的线性结构(数组、链表、栈、队列),通过精简概念+规范C语言代码,带初学者快速掌握核心用法,为后续复杂结构(树、图)打下基础。

一、数据结构的核心价值与应用场景

数据结构的本质是“组织与存储数据的方式”,其选择直接影响程序的时间复杂度与空间复杂度,核心应用场景如下:

  • 底层开发:Linux内核用链表管理进程、栈保存函数调用上下文,嵌入式设备用队列缓冲外设数据。
  • 算法优化:任何算法都依赖数据结构承载数据,如排序算法基于数组/链表,搜索算法基于树结构。
  • 工程实践:数据库索引用B+树,消息队列用队列结构,缓存机制用哈希表(后续进阶)。

入门阶段重点攻克线性结构——即数据元素按线性顺序排列的结构,是最基础且高频使用的类型。

二、预备知识:环境与核心概念

2.1 开发环境

沿用C语言入门环境(Windows Dev-C++/Linux GCC),无需额外配置,代码兼容双平台,编译运行方式与C语言程序一致。

2.2 核心概念

  • 逻辑结构:数据元素间的关联关系(线性结构为“一对一”,如数组元素、链表节点)。
  • 物理结构:数据在内存中的存储方式,分为“顺序存储”(如数组,连续内存)和“链式存储”(如链表,离散内存)。
  • 时间复杂度:衡量操作(增删查改)的效率,常用O(1)(常数级)、O(n)(线性级)表示,越低效率越高。

三、线性结构核心知识点与C语言实现

以下按“数组→链表→栈→队列”的顺序讲解,每个结构聚焦核心特性、实现代码与适用场景,代码遵循变量名规范,仅保留核心功能。

3.1 数组(顺序存储线性结构)

3.1.1 核心特性

连续内存存储,支持随机访问(通过下标快速定位),但插入/删除元素需移动后续元素,效率较低(时间复杂度O(n)),适合元素数量固定、查询频繁的场景。

3.1.2 C语言实现(动态数组)

静态数组大小固定,实际开发中常用动态数组(基于malloc分配内存),实现元素的增删查改:

#include<stdio.h>#include<stdlib.h>// 动态数组结构体typedefstruct{int* array_data;// 存储数据的指针int array_size;// 数组容量int element_count;// 实际元素个数} DynamicArray;// 初始化动态数组voidinit_dynamic_array(DynamicArray* dynamic_array,int initial_size){ dynamic_array->array_data =(int*)malloc(initial_size *sizeof(int)); dynamic_array->array_size = initial_size; dynamic_array->element_count =0;}// 插入元素(尾部插入,效率O(1))voidinsert_element(DynamicArray* dynamic_array,int element_value){// 容量不足时扩容(翻倍扩容,减少扩容次数)if(dynamic_array->element_count == dynamic_array->array_size){ dynamic_array->array_size *=2; dynamic_array->array_data =(int*)realloc(dynamic_array->array_data, dynamic_array->array_size *sizeof(int));} dynamic_array->array_data[dynamic_array->element_count++]= element_value;}// 查找元素(按值查找,效率O(n))intfind_element(DynamicArray* dynamic_array,int target_value){for(int i =0; i < dynamic_array->element_count; i++){if(dynamic_array->array_data[i]== target_value){return i;// 返回下标,未找到返回-1}}return-1;}// 释放内存voidfree_dynamic_array(DynamicArray* dynamic_array){free(dynamic_array->array_data); dynamic_array->array_data =NULL; dynamic_array->array_size =0; dynamic_array->element_count =0;}intmain(){ DynamicArray dynamic_array;init_dynamic_array(&dynamic_array,2);// 初始容量为2insert_element(&dynamic_array,10);insert_element(&dynamic_array,20);insert_element(&dynamic_array,30);// 触发扩容,容量变为4int target_index =find_element(&dynamic_array,20);printf("元素20的下标:%d\n", target_index);free_dynamic_array(&dynamic_array);return0;}

3.2 链表(链式存储线性结构)

3.2.1 核心特性

离散内存存储,通过指针连接节点,插入/删除元素无需移动数据(仅修改指针),效率O(1),但不支持随机访问(需从头遍历,效率O(n)),适合元素数量动态变化、插入删除频繁的场景(如Linux进程链表)。

3.2.2 C语言实现(单链表)

单链表是最基础的链表类型,每个节点包含数据域和指向下一节点的指针:

#include<stdio.h>#include<stdlib.h>// 链表节点结构体typedefstructLinkNode{int node_data;// 数据域structLinkNode* next;// 指针域,指向后续节点} LinkNode;// 创建新节点 LinkNode*create_link_node(int data_value){ LinkNode* new_node =(LinkNode*)malloc(sizeof(LinkNode)); new_node->node_data = data_value; new_node->next =NULL;return new_node;}// 头部插入节点(效率O(1))voidinsert_node_head(LinkNode** head_node,int data_value){ LinkNode* new_node =create_link_node(data_value); new_node->next =*head_node;*head_node = new_node;}// 遍历链表voidtraverse_link_list(LinkNode* head_node){ LinkNode* current_node = head_node;while(current_node !=NULL){printf("%d ", current_node->node_data); current_node = current_node->next;}printf("\n");}// 释放链表内存voidfree_link_list(LinkNode* head_node){ LinkNode* temp_node;while(head_node !=NULL){ temp_node = head_node; head_node = head_node->next;free(temp_node);}}intmain(){ LinkNode* head_node =NULL;// 链表头节点初始化insert_node_head(&head_node,30);insert_node_head(&head_node,20);insert_node_head(&head_node,10);printf("链表遍历结果:");traverse_link_list(head_node);// 输出:10 20 30free_link_list(head_node);return0;}

3.3 栈(先进后出LIFO结构)

3.3.1 核心特性

受限线性结构,仅允许在一端(栈顶)插入/删除元素,另一端(栈底)固定,符合“先进后出”规则,常用顺序存储(数组)实现,效率O(1),应用场景如函数调用栈、括号匹配、表达式求值。

3.3.2 C语言实现(顺序栈)
#include<stdio.h>#include<stdlib.h>#defineMAX_STACK_SIZE100// 栈最大容量// 顺序栈结构体typedefstruct{int stack_data[MAX_STACK_SIZE];// 存储栈元素int stack_top;// 栈顶指针(-1表示空栈)} SequenceStack;// 初始化栈voidinit_sequence_stack(SequenceStack* sequence_stack){ sequence_stack->stack_top =-1;}// 判断栈空intis_stack_empty(SequenceStack* sequence_stack){return sequence_stack->stack_top ==-1;}// 入栈voidpush_stack_element(SequenceStack* sequence_stack,int element_value){if(sequence_stack->stack_top == MAX_STACK_SIZE -1){printf("栈满,无法入栈\n");return;} sequence_stack->stack_data[++sequence_stack->stack_top]= element_value;}// 出栈intpop_stack_element(SequenceStack* sequence_stack){if(is_stack_empty(sequence_stack)){printf("栈空,无法出栈\n");exit(1);// 异常退出}return sequence_stack->stack_data[sequence_stack->stack_top--];}intmain(){ SequenceStack sequence_stack;init_sequence_stack(&sequence_stack);push_stack_element(&sequence_stack,10);push_stack_element(&sequence_stack,20);push_stack_element(&sequence_stack,30);printf("出栈元素:%d\n",pop_stack_element(&sequence_stack));// 30printf("出栈元素:%d\n",pop_stack_element(&sequence_stack));// 20return0;}

3.4 队列(先进先出FIFO结构)

3.4.1 核心特性

受限线性结构,允许在一端(队尾)插入元素,另一端(队头)删除元素,符合“先进先出”规则,常用链式存储实现(避免顺序存储的假溢出),应用场景如任务调度、外设数据缓冲、消息队列。

3.4.2 C语言实现(链式队列)
#include<stdio.h>#include<stdlib.h>// 队列节点结构体typedefstructQueueNode{int node_data;structQueueNode* next;} QueueNode;// 队列结构体(记录队头和队尾)typedefstruct{ QueueNode* queue_front;// 队头 QueueNode* queue_rear;// 队尾} LinkQueue;// 初始化队列voidinit_link_queue(LinkQueue* link_queue){ link_queue->queue_front = link_queue->queue_rear =(QueueNode*)malloc(sizeof(QueueNode)); link_queue->queue_front->next =NULL;}// 判断队列空intis_queue_empty(LinkQueue* link_queue){return link_queue->queue_front == link_queue->queue_rear;}// 入队voidenqueue_element(LinkQueue* link_queue,int element_value){ QueueNode* new_node =(QueueNode*)malloc(sizeof(QueueNode)); new_node->node_data = element_value; new_node->next =NULL; link_queue->queue_rear->next = new_node; link_queue->queue_rear = new_node;}// 出队intdequeue_element(LinkQueue* link_queue){if(is_queue_empty(link_queue)){printf("队列空,无法出队\n");exit(1);} QueueNode* temp_node = link_queue->queue_front->next;int element_value = temp_node->node_data; link_queue->queue_front->next = temp_node->next;// 队尾与队头重合时,更新队尾if(link_queue->queue_rear == temp_node){ link_queue->queue_rear = link_queue->queue_front;}free(temp_node);return element_value;}intmain(){ LinkQueue link_queue;init_link_queue(&link_queue);enqueue_element(&link_queue,10);enqueue_element(&link_queue,20);enqueue_element(&link_queue,30);printf("出队元素:%d\n",dequeue_element(&link_queue));// 10printf("出队元素:%d\n",dequeue_element(&link_queue));// 20return0;}

四、经典实战案例:括号匹配(栈的应用)

以面试高频题“括号匹配”为例,演示栈的实际应用,判断输入字符串中的括号(()、[]、{})是否成对闭合:

#include<stdio.h>#include<string.h>#defineMAX_STACK_SIZE100typedefstruct{char stack_data[MAX_STACK_SIZE];int stack_top;} BracketStack;voidinit_bracket_stack(BracketStack* bracket_stack){ bracket_stack->stack_top =-1;}voidpush_bracket(BracketStack* bracket_stack,char bracket_char){ bracket_stack->stack_data[++bracket_stack->stack_top]= bracket_char;}charpop_bracket(BracketStack* bracket_stack){return bracket_stack->stack_data[bracket_stack->stack_top--];}// 判断括号匹配intis_bracket_matched(char* input_string){ BracketStack bracket_stack;init_bracket_stack(&bracket_stack);int string_length =strlen(input_string);for(int i =0; i < string_length; i++){char current_char = input_string[i];// 左括号入栈if(current_char =='('|| current_char =='['|| current_char =='{'){push_bracket(&bracket_stack, current_char);}else{// 右括号无对应左括号,匹配失败if(bracket_stack.stack_top ==-1)return0;char top_bracket =pop_bracket(&bracket_stack);// 检查括号是否成对if((current_char ==')'&& top_bracket !='(')||(current_char ==']'&& top_bracket !='[')||(current_char =='}'&& top_bracket !='{')){return0;}}}// 栈空说明所有括号都匹配return bracket_stack.stack_top ==-1;}intmain(){char input_string[100];printf("请输入包含括号的字符串:");scanf("%s", input_string);if(is_bracket_matched(input_string)){printf("括号匹配成功\n");}else{printf("括号匹配失败\n");}return0;}

五、入门常见问题与避坑指南

  • 链表空指针问题:遍历或操作链表时,需先判断节点指针是否为NULL,避免野指针访问(如链表尾节点next必须置空)。
  • 栈/队列边界判断:入栈前检查栈满,出栈前检查栈空;队列同理,避免越界访问或空操作。
  • 内存泄漏:链式结构(链表、链式队列)的节点需手动free,避免长期运行导致内存耗尽,建议封装专门的释放函数。
  • 顺序存储假溢出:顺序队列若仅移动指针,会出现“队尾满但队头有空余”的假溢出,可通过循环队列优化。

六、进阶学习路线(贴合底层开发)

掌握线性结构后,可按以下路线深化,适配Linux系统编程与嵌入式开发需求:

  1. 复杂线性结构:双向链表、循环链表(Linux内核常用)、循环队列、优先级队列(堆实现)。
  2. 非线性结构:树(二叉树、红黑树)、图,重点掌握二叉树的遍历(前中后序)与红黑树在Linux内核中的应用。
  3. 算法结合:学习基于数据结构的排序(链表排序、堆排序)、搜索(二叉树查找)算法,优化时间复杂度。
  4. 实战落地:在嵌入式开发中用队列缓冲串口数据,用链表管理传感器节点,复刻Linux内核简单链表逻辑。

总结

数据结构入门的关键是“理解特性+多实战”,线性结构虽简单,但需明确不同结构的适用场景——数组适合查询,链表适合增删,栈/队列适合特定顺序需求。本文实现的代码均为核心逻辑,可直接用于课程作业或小型项目,建议手动敲写并调试,理解指针操作与内存管理的细节。

后续学习中,需结合Linux内核源码、嵌入式项目案例,体会数据结构在底层开发中的优化作用,逐步建立“数据结构决定程序性能”的思维,为复杂项目开发筑牢基础。

Read more

【通过 Vue 实例劫持突破 Web 编辑器的粘贴限制】

【通过 Vue 实例劫持突破 Web 编辑器的粘贴限制】

逆向实战:通过 Vue 实例劫持突破 Web 编辑器的粘贴限制 * 1. 现象与初探:被禁用的 Ctrl+V * 技术视角的初步审视 * 逆向的逻辑前提 * 2. 逆向分析:寻找逻辑的“命门” * 突破口:利用 I18N 国际化配置追踪 * 核心文件追踪:锁定 `answer-code-editor.js` * 代码逻辑解剖:拦截机制的实现 * 3. 攻克方案:Vue 实例的运行时劫持 * 第一步:获取 Vue 实例的“后门” * 第二步:函数劫持(Monkey Patch) * 第三步:状态机的一致性重构 * 第四步:唤醒底层编辑器 * 4. 最终脚本:一行代码解锁限制 * 4.1 Injection

By Ne0inhk

trae整合figma的mcp实现前端代码自动生成

1.现在trae版本在3.0及以上版本。 2.trae账号是企业版。 3.打开设置,找到mcp 这里需要token,需要从figma账号里生成,网页登录figma账号,找到设置,打开后找到security,然后点击generate new token,token名称随便取,权限都钩上。然后生成一个token,把token放到mcp中即可。 4.使用mcp,切换到mcp模式,你也可以自己创建智能体使用 5.提问使用,可参考下面的提示词使用 注意:这里面的figma链接是mcp的链接,不是figma链接,一般需要你有原型的权限才能看到 我需要根据提供的Figma链接生成一个与设计稿高度一致的网页。请严格遵循以下详细要求:

By Ne0inhk

AI在前端工作中的应用

AI在前端工作中的应用 在AI的高速发展中,也离不开前端,前端开发也在AI工具中发挥着举足轻重的作用。同时,一些AI工具也是的前端开发工作提效不少,合理利用工具,能在工作中提升效率。本文介绍一些前端与AI结合的场景,不限于接入,也包含一些工具的使用。 1、自定义GPT场景 在自定义 GPT 场景中,前端的核心职责是搭建 “用户 - 自定义 GPT” 的交互入口,同时支撑 GPT 的个性化配置、功能扩展与数据可视化,需围绕 “交互体验、配置能力、集成适配” 三大核心展开工作。 ant-design提供给前端开发者快速开发AI相关的UI组件库:https://ant-design-x.antgroup.com * SSE SSE是一种基于HTTP协议的数据传输方式,它允许服务端向客户端推送数据。前端可以通过SSE实现GPT的实时对话,用户输入问题,GPT返回结果。为什么选择这种方式,是因为GPT返回结果是很漫长的,所以用流式传入,能让用户体验更友好,不用websocket是因为长连接占用资源过多,服务器长连接数有限,所以用SSE。 可以直接使用微软的SSE库:

By Ne0inhk
旧安卓手机别扔!用KSWEB搭个人博客,搭配外网访问超香

旧安卓手机别扔!用KSWEB搭个人博客,搭配外网访问超香

KSWEB 作为安卓端轻量级 Web 服务器,核心功能是提供 PHP、MySQL 运行环境,能轻松部署 Typecho、WordPress 等博客系统,Termux 则可辅助管理内网穿透服务;这类工具特别适合预算有限的学生、个人博主,或是想折腾闲置设备的数码爱好者,优点也很突出 —— 对硬件要求极低,1GB 内存就能运行,旧款红米、华为畅享等机型都能适配,而且内置的运行环境无需手动配置,新手也能快速上手。 使用这套工具时也有不少需要注意的地方,比如手机要长期插电并连接稳定 Wi-Fi,否则服务容易中断;还要给 KSWEB 和 Termux 关闭电池优化、放开存储权限,我用小米手机测试时就因为没关后台限制,导致 Apache 服务频繁被系统杀掉,折腾了好一会儿才排查出问题;另外非 Root 机型也能使用,但部分文件权限操作会稍显繁琐。 不过仅靠 KSWEB 部署完博客后,只能在局域网内访问,这会带来很多不便:比如在家用电脑能连手机看博客,

By Ne0inhk