链表这个东西我在大学第一次学数据结构的时候其实没太当回事。当时觉得数组好用多了按下标一秒定位链表还要一个节点一个节点next过去麻烦得很。直到后来有一次真的在项目里遇到需要在表中间高频插入删除的场景数组一扩容一搬移就是几毫秒没了我才回过头把链表重新摸了一遍。链表简单说就是一群节点用指针串起来的数据结构每个节点存自己的数据再存一个指向下一个节点的指针。它跟数组最大的区别就是内存不连续靠指针把彼此联系起来。这篇文章想写给三类人正在准备数据结构期末复习的大学生、刷408考研数据结构代码题的考生、以及面试前想快速把链表基本功补起来的朋友。我会先把链表是什么、为什么需要它讲透然后从C语言手写单链表切入覆盖插入、删除、遍历、逆序、清空这些基本操作再聊双链表、循环链表、十字链表最后结合LRU缓存、链式哈希这类真实场景把链表用起来。内容尽量贴近实战该给的代码给代码该说的坑一个不落。1. 链表到底在解决什么问题在动手写代码之前先把这个最基础的问题想明白链表和数组差在哪为什么我们有时候宁可牺牲随机访问也要用链表。1.1 数组的痛点和链表的本质数组是把数据放在连续的内存空间里这件事带来了两个结果。好处是随机访问极其快只要知道首地址和下标一次加法一次解引用就能拿到数据时间复杂度O(1)。坏处是连续意味着两个麻烦插入删除要挪数据空间满了要扩容。举一个实际例子。假设你维护一个在线用户列表用户中途掉线要摘除如果这个列表用数组存你需要把后面所有用户往前移一位。假如这个列表有10万条记录一次删除就是几万次内存拷贝高并发场景下这就是性能灾难。链表把数据拆成独立的节点每个节点申请一块独立的内存节点之间用指针连接。删除一个节点只需要把前面节点的next指针绕过它指向它的后继然后释放这块内存即可。数组要挪几万个元素链表只需要改一个指针这就是本质差异。链表的价值在于它把数据之间的先后关系从物理上的紧挨着变成了逻辑上的指针连接。物理位置不再重要重要的是每个节点告诉我们下一个节点在哪。这种抽象能力在需要频繁增删、或者数据量无法提前预知的场景里非常有用。1.2 链表的核心优势与代价链表并不是全能的它只是把连续内存、随机访问换成了分散内存、顺序访问。用表格看更清楚对比维度数组链表内存布局连续分散随机访问O(1) 按下标直取O(n) 从头遍历头部插入/删除O(n) 整体搬移O(1) 改指针中间插入/删除O(n) 挪元素O(1) 前提是已定位前驱空间额外占用无每个节点一个到两个指针CPU缓存友好性高低真正做工程的时候还有两个被很多人忽略的差异。第一个是缓存局部性。数组是连续内存遍历的时候CPU缓存命中率高链表节点分散在堆里每次访问都可能缓存未命中所以在数据量小、操作简单的场景数组往往比链表还快。第二个是内存碎片。链表节点频繁malloc和free堆上容易产生碎片长时间运行可能出现碎片增多、分配变慢的问题。这也是为什么系统设计里链表很少单打独斗经常和哈希表、数组组合使用。2. 链表的家族图谱单链表、双链表、循环链表与十字链表很多人一听到链表就只想到单链表其实链表是一个家族。不同的形态解决不同的问题单链表、双链表、循环链表、十字链表各有各的来由。2.1 单链表最基础也是最常考的形态单链表每个节点只有一个next指针只能从head开始往后遍历。它最打动人的地方是简单——一个结构体、一个指针、一个节点就能表达一条链。但也正是这种单向性让很多问题变得有意思。反向遍历做不到于是出现了反转链表这个经典题查找最后一个元素必须从头走完于是有了双指针找倒数第k个节点的技巧。这里展开讲一个高频考点链表相交问题。LeetCode上160题链表相交二就是典型的单链表题目。两个单链表可能在某个节点之后合并成同一个链表求相交的起始节点。最直觉的解法是把第一个链表的所有节点放到哈希集合里再遍历第二个链表找第一个重复节点。另一种更巧妙的做法是两个指针分别从两个链表头出发走完自己的链表后转到对方链表头继续走如果两个链表相交两个指针一定会在相交节点相遇。这个做法不需要额外空间是面试官很喜欢考察的思路。判断链表有没有环也是单链表的经典应用用快慢指针。快指针每次走两步慢指针每次走一步如果链表有环快指针终会在环里追上慢指针。给朋友讲的时候我常用一个类比两个人在操场跑圈一个跑得快一个跑得慢只要两个人都一直在跑跑得快的早晚会从后面追上跑得慢的。这个思想后面还会衍生出找环入口的一系列题目。2.2 双链表空间换时间的典型双链表在每个节点上多加了一个prev指针指向直接前驱。代价很直接每个节点多占用一个指针的内存。换来的是两个能力可以从两端向中间遍历删除节点时如果已经拿到了目标节点本身可以在O(1)时间内完成删除而不需要先找到它的前驱。LRU缓存就是双链表的典型应用场景。Java里的LinkedList底层就是双向链表C标准库的std::list同样是。当你要频繁在中间插入和删除又要同时支持向前向后遍历时双链表比单链表顺手得多。当然代价是每个节点的内存变大如果设计成循环双链表还能让整条链在逻辑上闭合解决约瑟夫环这类问题会更自然。2.3 循环链表与十字链表特殊场景的大杀器循环链表让尾节点的next指针重新指回头节点整体形成一个环。最常见的应用是约瑟夫问题n个人围成一圈报数到m的人出圈问最后剩下的那个人是谁。用循环链表天然贴合这个问题每到第m个人就删掉该节点然后继续报数不需要考虑越界和回绕。操作系统里的时间片轮转调度也常用循环链表每个进程节点轮流分配CPU时间片转完一圈再回来循环链表刚好满足这种公平轮转的需求。十字链表Orthogonal List主要用于稀疏矩阵的存储。普通的二维数组存稀疏矩阵浪费大量空间十字链表把矩阵按行和列分别组织成两条链。每个非零元素节点既存在于它所在行的行链表中也存在于它所在列的列链表中形成十字交叉的结构。当你需要以O(行数非零元素个数)的代价遍历任意一行或一列时十字链表比传统的三元组压缩存储更方便。这个结构听起来冷门却是数据结构专业课里很常考的一个知识点。3. 从零手写链表C语言实操全流程C语言是理解链表最好的语言因为它让我们直接操作指针所有内存细节都暴露无遗。我建议所有人在学习阶段都用C语言把单链表完整写一遍再去看C、Java、Python的封装实现。这一章我带大家完整走一遍从头节点的创建到插入、删除、遍历、逆序、清空每个函数都给出可以直接运行的代码以及踩过的坑这份程序就能当作单链表基本操作实验报告的核心内容。3.1 结构体定义与内存管理核心在C语言里定义一个链表节点最经典的是下面这样typedef struct Node { int data; struct Node *next; } Node;注意这里有个新手最容易栽的坑结构体内部声明next指针时必须写struct Node *next不能直接写Node *next。原因是typedef是在结构体定义完之后才生效的在结构体内部使用Node这个别名是未定义的。这个细节在我面试过的很多候选人身上出现过看起来不起眼但写错编译都过不去。创建节点并初始化的函数Node *createNode(int data) { Node *node (Node *)malloc(sizeof(Node)); if (node NULL) { fprintf(stderr, 内存分配失败\n); exit(EXIT_FAILURE); } node-data data; node-next NULL; return node; }很多教材里不写malloc返回值检查直接拿着node-data赋值。这在大多数机器上不会立刻崩但一旦内存紧张malloc返回NULL后面node-data data就是空指针访问轻则段错误重则让整个进程崩溃。我写C代码的习惯是凡是malloc必查返回值。这个习惯在大量分配节点的链表场景里格外重要尤其是长时间运行的服务内存分配失败是真实会发生的事。3.2 五种基本操作插入、删除、遍历、逆序、清空先讲插入。网上搜索链表插入在指定位置插入建立单链表的热度一直很高说明这是链表操作里最关键的场景。按照插入位置可以分为头插法、尾插法、指定位置插入。头插法最省事新节点先指向旧头再把链表头指针指向新节点。Node *insertAtHead(Node *head, int data) { Node *node createNode(data); node-next head; return node; }这里为什么用返回值而不是传入Node *head后在函数里直接改因为在C语言里函数参数是值传递。你在函数里写head node改的是参数副本调用者那边的head还是原来的值。要想在函数里真改头指针要么返回新头让调用者接收要么传入二级指针Node **head。两种写法都常见我的建议是创建链表、改变头指针的场景用二级指针遍历不改变头指针的场景用一级指针语义干净不容易出错。尾插法要先找到最后一个节点Node *insertAtTail(Node *head, int data) { Node *node createNode(data); if (head NULL) return node; Node *curr head; while (curr-next ! NULL) { curr curr-next; } curr-next node; return head; }指定位置插入比如在下标pos处插入是一个综合题要先找到第pos-1个节点作为前驱再把新节点挂上去。Node *insertAt(Node *head, int pos, int data) { if (pos 0) return head; if (pos 0) return insertAtHead(head, data); Node *curr head; for (int i 0; i pos - 1 curr ! NULL; i) { curr curr-next; } if (curr NULL) return head; // 位置越界 Node *node createNode(data); node-next curr-next; curr-next node; return head; }提示这里有个顺序问题一定要先把新节点的next指向前驱原来的后继再把前驱的next指向新节点。两步反过来的话前驱的next改了之后原来的后继就找不到了链表就断了。删除节点是插入的镜像操作核心是找到目标节点的前驱让它绕过目标节点Node *deleteAt(Node *head, int pos) { if (head NULL) return NULL; if (pos 0) { Node *tmp head; head head-next; free(tmp); return head; } Node *curr head; for (int i 0; i pos - 1 curr-next ! NULL; i) { curr curr-next; } if (curr-next NULL) return head; Node *tmp curr-next; curr-next tmp-next; free(tmp); return head; }删除的坑更多。free(tmp)之后如果还有别的指针指向这块内存就成了悬挂指针。尤其是面试手写代码时很多人写着写着就忘记把悬空的指针处理干净。实际工程里删除节点后最好把free掉的指针变量置NULL宁可多写一条语句也不要留下隐患。遍历最简单void traverse(Node *head) { for (Node *curr head; curr ! NULL; curr curr-next) { printf(%d , curr-data); } printf(\n); }我让学生遍历时单独用一个curr指针绝对不要去动head本身。head是整条链的入口一旦在循环里把它改了遍历完链表就丢了连释放都很麻烦。反转链表是面试必考迭代写法每个人都要背熟Node *reverse(Node *head) { Node *prev NULL; Node *curr head; while (curr ! NULL) { Node *next curr-next; curr-next prev; prev curr; curr next; } return prev; }这个逻辑我的理解方式很形象想象一条队伍所有人原本脸朝前现在要集体转身。每个位置的人先抓住自己后面的人保存next然后掉头指向自己前面的人curr-next prev然后整体往前走一步。循环结束的时候prev就是原来队尾也就是反转后的新头。递归版反转同样经典Node *reverseRecursive(Node *head) { if (head NULL || head-next NULL) { return head; } Node *newHead reverseRecursive(head-next); head-next-next head; head-next NULL; return newHead; }递归版的思路是先把后面一串反转好得到一个newHead再把当前节点接上去。理解递归的关键是假设函数已经帮我把后续反转好了剩下只需处理当前节点。不过要注意链表很长时递归深度可能非常大生产环境慎用。考试和面试里写出递归版反而加分因为展示了思路的多样性。清空链表void clear(Node **head) { Node *curr *head; while (curr ! NULL) { Node *tmp curr; curr curr-next; free(tmp); } *head NULL; }清空几乎是最容易被写错的操作。我见过最常见的错误是一边free当前节点一边接着访问它的nextfree之后next字段已经不可靠了访问就是未定义行为。正确做法是先用tmp保存当前节点再把curr移动到下一个节点最后free tmp。清空之后把头指针置NULL同样关键否则调用者手里的head就是一个悬空的野指针。3.3 进阶操作排序与查找链表排序在编程题实训里很常考。数组的快排依赖随机访问链表上不好实现所以链表排序一般用插入排序或者归并排序。插入排序的思路是把链表拆成有序部分和无序部分每次从无序部分取一个节点插入到有序部分的正确位置。归并排序则用快慢指针找到链表中间点递归排序前后两半再合并两个有序链表。热词里有人搜链表排序c语言结构体链表基本语法说明这确实是很多人的拦路虎建议多画图多调试。说到查找顺序查找在链表上就是从头遍历时间复杂度O(n)。如果需要高效查找工程上会用跳表Skip List在有序链表上增加多层索引实现O(logn)的查找Redis的有序集合底层就用了跳表。考试和面试阶段掌握顺序查找就够跳表可以作为扩展内容去了解。4. 语言之争C、Java与Python的链表实现对比数据结构本身是语言无关的但不同语言实现链表的细节天差地别。C语言让你看见指针C给你封装和智能指针Java有现成的LinkedListPython用对象引用模拟指针。4.1 C链表struct、class与智能指针的取舍C里定义链表节点最常见的写法是struct带构造函数struct Node { int data; Node *next; Node(int x) : data(x), next(nullptr) {} };相比C语言C多了一个构造函数的便利创建节点直接写new Node(5)不需要单独写createNode。内存用new/delete管理而不是malloc/free。需要注意C中new出来的对象如果忘了delete一样会内存泄漏。面试手写的时候很多人用C写链表却写成C语言的malloc/free混搭风格语法上没有错但风格上很混乱建议写之前先想清楚自己用的是哪套语法。关于智能指针用unique_ptr或shared_ptr替代裸指针可以自动管理内存但链表恰恰是智能指针的尴尬场景。unique_ptr链表的节点所有权需要频繁转移写起来要move来move去shared_ptr有引用计数开销链表每个节点都要维护额外的计数。所以实际工作中绝大多数C项目直接使用std::list或者std::forward_list自己手写链表的情况反而出现在面试或练习中。我的建议是学习阶段用裸指针练手理解原理工程阶段直接用STL不要重复造轮子。4.2 Java的LinkedList与Python的单链表逆序Java原生提供了java.util.LinkedList它是双向链表支持在任意位置插入删除日常开发可以直接使用。但面试时面试官问的不是你怎么用LinkedList而是要你手写节点类和操作。Java链表写法需要掌握定义一个内部静态类当节点链表类里维护头引用即可。Python单链表逆序是很多Python面试题的常客。Python没有指针但对象引用本身就相当于指针class ListNode: def __init__(self, x): self.val x self.next None def reverse_list(head: ListNode) - ListNode: prev None curr head while curr is not None: next_node curr.next curr.next prev prev curr curr next_node return prevPython写链表的好处是代码量少、逻辑直观特别适合理解算法思路。坏处是你不会真正体会到内存布局和指针操作的细节遇到复杂指针问题容易心里没底。热词里有人搜python单链表逆序说明这个代码风格确实是Python面试的常客。我个人建议用Python理解思路用C语言验证细节两个语言交叉训练效果最好。5. 链表的实战战场从缓存淘汰到稀疏矩阵链表如果只出现在考卷和面试题里它的价值就被低估了。真实工程里链表无处不在只是很多封装太严实平时感知不到。5.1 LRU缓存双链表加哈希表的经典组合LRULeast Recently Used最近最少使用策略是缓存淘汰的黄金算法。它的目标是当缓存满了优先淘汰最久没有访问的数据。实现这个目标哈希表负责O(1)查找数据位置双向链表负责O(1)记录访问顺序。具体做法是每次访问一个数据把它对应的节点从链表中摘下来移到链表头部。这样链表头部永远是最近访问过的数据链表尾部就是最久没访问的数据。缓存淘汰时直接删尾部节点同时删除哈希表里对应的映射。为什么用双链表而不是单链表因为在删除一个节点时需要拿到它的前驱。如果用单链表拿到节点本身还不够得从头遍历找前驱这一下就变成O(n)了。双链表每个节点带prev指针删除节点时prev直接给出前驱整体复杂度才是真正的O(1)。这个设计是面试高频题也是理解双链表价值最好的案例。5.2 链式哈希表、图的邻接表与稀疏矩阵哈希表解决哈希冲突有两种主流方式开放寻址法和拉链法。拉链法就是在数组的每个位置挂一条链表冲突的元素在链上顺序存放。Java的HashMap在链表长度超过阈值时还会把链表转成红黑树目的就是防止链表过长导致查找退化。所以链表虽然不是哈希表的最终形态却是哈希表设计的重要基石。图论里邻接表存储每个顶点相连的边。对每个顶点都维护一条链表链表里的每个节点代表一条从该顶点出发的边。稀疏图的邻接表比邻接矩阵节省大量空间遍历某个顶点的所有邻居也非常方便。操作系统里空闲内存块的管理也常用链表空闲链表把散落的空闲块串起来分配时遍历链表找一块合适的。文件系统里链式分配用链指针把磁盘块串起来处理文件时按链访问。这些场景的共同点是数据规模动态变化、插入删除频繁、不需要随机访问正好是链表的舒适区。5.3 关于数据结构关键词的多义性热词里有一条是头歌pandas数据结构创建。提这一句是想提醒大家数据结构这个术语在不同的语境下含义完全不同。pandas里的DataFrame是一种表格型结构面向数据分析和批量计算和链表这种链式存储结构不是一回事。很多初学者在搜索引擎里搜数据结构想找链表的资料结果被pandas相关的文章带偏。我的建议是搜索时加上语言前缀比如搜C语言 链表数据结构 王道408前者定位到实现语言后者定位到考研复习的经典资料这样出来的结果更精准。6. 面试与考试视角408备考、实验报告与常见排坑指南链表不仅是工程工具还是各种考试和面试的重头戏。408考研的数据结构部分链表几乎是必考内容数据结构实验报告里单链表基本操作是入门必做实验期末复习时链表知识点经常以选择题和填空题出现。王道408系列资料对链表的要求很明确能手工模拟插入删除过程能写出基本操作的代码。6.1 408考研与期末复习链表要背到什么程度如果目标是408考研链表部分的代码要求其实很固定定义节点结构体、头插、尾插、删除、遍历、反转这些基本操作要能闭着眼写出来。考试时不会要求写完整可运行的程序更常见的是让你补全某个函数或者画出插入删除后链表的形态。所以复习时除了动手写代码还要多画图模拟给出一条链表手工画出删除第2个节点之后指针的变化这个过程比背代码更贴近考场上的题型。数据结构与算法这门课的整体复习也是这个思路链表是第一个坎后面树、图、查找、排序都依赖链表打下的指针基础。数据结构期末复习可以按题型整理选择题常考链表和数组的时间复杂度对比、单链表头插尾插的区别、循环链表判空的条件填空题常考某操作之后指针指向哪个节点大题常考反转链表、合并两个有序链表、判断是否有环。这些题目都可以在纸上画图解决画图能显著降低理解成本。6.2 链表最常见的五个致命问题我整理了一下自己写链表和帮人改代码时遇到的最典型的五个问题悬挂指针与内存泄漏。free之后原指针没有置NULL或者节点被删除后还有其它变量指向它。注意free只是释放内存指针变量里的地址还在如果不置空下次访问是未定义行为如果再次freedouble free直接崩溃。解决办法是保持所有权清晰谁malloc谁free谁new谁delete删除后立刻置NULL。边界条件忘掉空链表和单节点。很多人在普通链表上写得好好的一到空链表就崩溃。写任何链表操作之前先在心里过三张用例空链表、只有一个节点的链表、常规链表。这个习惯在面试里尤其有用写完代码主动补试空链表和单节点两个用例能当场发现很多低级错误。修改head导致链表丢失。遍历时直接用head指针把head一路next下去返回的时候发现链表入口没了。记住遍历用临时指针保留head不动。清空链表时同样要保留原头指针直到释放完毕。反转时先断链。反转链表最经典的错误是先把curr-next改成prev然后再去取curr-next结果拿到的是已经被改过的指针原后继丢了。一定要先把next保存到临时变量再改指针。是否用虚拟头结点的纠结。实际工程和面试技巧里虚拟头结点dummy是一个非常实用的设计。链表头结点容易丢、插入删除逻辑总是要单独考虑头结点加一个dummy节点作为哨兵可以让所有操作统一插入删除的循环条件都从dummy开始最后返回dummy-next即可。这个技巧在合并两个有序链表时尤其好用可以避免写一堆头结点特殊判断。6.3 给实验报告和面试代码的两点建议写数据结构实验报告时我建议除了功能代码一定把测试用例写清楚。单链表基本操作实验至少覆盖往空链表头插、往空链表尾插、指定位置越界插入、删除唯一一个节点、反转单节点链表、清空空链表。这些用例能跑通报告里实验结果与分析部分就不愁没内容。每个用例写清楚输入、预期输出、实际输出老师很难不给高分。面试现场手写链表代码时不要闷头就写。我的做法是先跟面试官确认边界条件比如这个函数如果链表为空应该返回什么插入位置从0开始吗然后简单说一下思路再动手。这样既显得严谨又给自己争取了组织代码的时间。写完之后主动拿着空链表、单节点两个case在脑子里过一遍很多错误当场就能发现。最后分享一点我自己的体会。链表这个数据结构看起来简单但它的每个操作都在训练你对指针、边界条件和内存生命周期的敏感度。我面试过很多候选人反转链表和合并两个有序链表这两道题基本上两三分钟就能看出一个人的代码功底。如果能把单链表的基本操作从零到一写通再随手补上双链表和循环链表后面学二叉树、图、并查集会顺很多因为它们都用到了同一种思维通过引用指针把不连续的数据组织成可追踪的结构。如果时间允许我强烈建议大家用C语言把链表的增删改查反转清空全部手写一遍然后用调试器gdb或者IDE的断点单步跟踪一次反转过程看着每一个next指针的变化。这个过程比看十篇教程都管用。学完链表之后顺手把LeetCode上合并两个有序链表链表相交环形链表三道经典题做掉感受同样的思维在不同题型里的变化。链表值得你花一两天把它彻底吃透因为你后面所有数据结构的学习都会受益于今天打下的这个基础。
企业数字化 ERP 产品动态
相关推荐
Neo4j企业版5.15.0 Windows生产部署全指南 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/26 5:42:11
DOI批量下载PDF的可靠工作流:API优先+渐进式降级实现 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/26 5:42:05
LITESTAR 4D照明设计实战:从室内办公到室外道路的全流程应用 引子:从一次深夜改图说起做照明设计这行,时间久了手里总会攒下几个“老伙计”。有人钟情DIALux,操作顺手;有人偏爱AGi32,算法严谨。但我个人近几年用得最频繁的,反而是LITESTAR 4D。最开始是被它内置的大量… · 2026/9/26 5:41:59
Harness Anything:桌面应用界面自动化新范式 1. 这不是“AI写脚本”,而是让AI直接接管你的办公软件界面你有没有过这种时刻:刚整理完Zotero里200篇文献,突然发现所有PDF标题都缺了年份前缀;WPS表格里上千行数据要批量插入超链接,但VBA宏调试了三小时还是报错&… · 2026/9/26 6:13:57
Win11Debloat:系统级去臃肿的原理与安全实践 1. 这不是“卸载几个App”——Win11Debloat 的真实战场在哪?你点开某篇“Win11一键去臃肿”的教程,复制粘贴几行 PowerShell 命令,回车执行,弹出一堆红色报错,最后只删掉了“天气”和“邮件”,心里嘀咕&… · 2026/9/26 6:13:57
永久免费CRM系统选型指南:开源与SaaS深度横评 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/26 6:13:57
柔性制造数字化转型:智能工厂五大系统选型与避坑指南 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/26 6:13:51
CSDN平台深度解析:从搜索技巧到博客写作与避坑指南 1. 从一个开发者视角重新认识CSDN1.1 这个平台到底是什么CSDN,全称Chinese Software Developer Network,中文名中国软件开发者网络,圈内人一般直接叫它CSDN。它是一个面向中文开发者的技术社区和内容平台,核心业务包括技术博客、论… · 2026/9/26 6:13:51
数据库课后习题答案别硬背:当测试用例集刷,效率翻倍 简介:万常选版《数据库原理与设计》课后习题答案资源,覆盖第2至6章及第9章,适合正在学习关系模型、数据库建模、关系数据理论与模式求精的本科生、自学者作为复习与自测材料。压缩包共7个文件,含3个doc参考答案、2个sql示例脚本、… · 2026/9/26 0:00:21
OpenClaw 替代品?Hermes Agent 踩坑实录:macOS 飞书接入 TaoToken 配置 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/26 0:00:40
向下兼容与向上兼容:接口设计中的兼容性策略与工程实践 一次版本升级事故,是很多团队绕不过去的坎。线上环境里,服务端明明已经上线了新版接口,老的移动端还在照着旧文档传参数。请求一到网关,校验直接拒绝,用户操作失败,客服群炸了锅,开发群里开始互… · 2026/9/26 0:00:46