链表探秘:用指针编织的动态寻宝图(leetcode 21、83)

125 阅读4分钟

欢迎来到数据结构的奇幻王国!今天我们将化身探险家,手持"内存指针"这张神奇藏宝图,在链表构建的迷宫中开启智慧寻宝之旅。

链表VS数组:两种寻宝哲学的碰撞

维度数组(地铁直通车)链表(密室逃脱)
存储模式所有车厢连成钢铁巨龙密室如星罗棋布
访问速度第5节车厢直接跳入必须解开前4道密码锁
元素增删全体乘客需要大挪移仅需修改两张地图标记
空间魔法需预定整块黄金地段零散空间也能变废为宝

总结

  • 数组是规划完美的地铁线路,直达任意站点
  • 链表是环环相扣的密室逃脱,每扇门后藏着新线索

节点构造:魔法宝箱的解剖学

每个链表节点都是会施法的魔法宝箱:


	function MagicNode(treasure, nextClue) {

	  this.treasure = treasure; // 宝藏本体(数据域)

	  this.nextClue = nextClue; // 下一关线索(指针域)

	}

三宝连珠实战演示:


	// 创建终极宝藏(无后续线索)

	const finalTreasure = new MagicNode("龙族秘宝", null); 

	 

	// 中继宝藏指向终极

	const middleTreasure = new MagicNode("古卷残页", finalTreasure); 

	 

	// 起始宝藏开启冒险

	const startTreasure = new MagicNode("青铜钥匙", middleTreasure); 
        
连接链表
	 

	

链表特技:动态空间魔法

瞬移插入术

在现有节点间插入新宝藏:


	const phantomGem = new MagicNode("幽灵宝石");

	 

	// 只需修改两个魔法链接

	startTreasure.nextClue = phantomGem;  // 青铜钥匙 → 幽灵宝石

	phantomGem.nextClue = middleTreasure; // 幽灵宝石 → 古卷残页

操作耗时恒定O(1),比数组大挪移高效百倍!

隔空取物术

删除中间节点:


	// 让幽灵宝石直接指向龙族秘宝

	phantomGem.nextClue = finalTreasure;

瞬间消除目标,无需惊动其他宝藏

时间代价

寻找第N个宝藏:


	function findNthTreasure(start, n) {

	  let explorer = start;

	  let steps = 1;

	 

	  while (steps < n && explorer) {

	    explorer = explorer.nextClue; // 逐洞探索

	    steps++;

	  }

	  return explorer?.treasure || "深渊尽头";

	}

最坏情况需遍历全链,时间成本O(n)

实战演练:破解古老谜题

谜题一:双图合一(有序链表合并)

任务:融合两张神秘地图
地图A:1→3→5
地图B:2→4→6

解密代码


var mergeTwoLists = function(list1, list2) {
    // 1. 创建哑节点(虚拟头节点)
    let head = new ListNode(); // 用于简化边界条件处理
    let cur = head;           // 当前工作指针
 
    // 2. 遍历两个链表
    while (list1 && list2) {  // 当两个链表都未遍历完时
        if (list1.val <= list2.val) {
            cur.next = list1; // 将较小值的节点接入结果链表
            list1 = list1.next; // list1指针后移
        } else {
            cur.next = list2;
            list2 = list2.next;
        }
        cur = cur.next; // 工作指针后移
    }
 
    // 3. 处理剩余节点(至少一个链表已遍历完)
    if (list1) cur.next = list1; // 直接接上剩余链表
    else cur.next = list2;
 
    // 4. 返回哑节点的下一个节点(真实头节点)
    return head.next;
}

融合过程

	初始:1(A) vs 2(B) → 选1

	第二步:3(A) vs 2(B) → 选2

	...

	最终:123456

注意:一开始需要建立空头结点,一开始需要确定哪个头节点更小,选择头节点开始,后面头节点保留不懂,cur得到头节点的地址,代替头节点去做事,这样我们返回的头节点,才是原来一开始的头节点,不然直接使用头节点的话,后面返回的头节点,就是我们已经遍历两条链表的尾部,而不是整条链表,用cur去做事就不会干扰头节点

谜题二:净化诅咒(删除重复节点)

任务:清除连续重复的魔法标记
🗡️ 诅咒链:1→1→2→3→3

净化仪式

var deleteDuplicates = function(head) {
    let cur=head
    while(cur&&cur.next){
        if(cur.val<cur.next.val){
            cur=cur.next
        }
        else{
            cur.next=cur.next.next
        }
}
        return head

};

这里需要注意:如果是力扣的话,while循环条件必须要是cur写在cur.next,先判断当前节点是否存在再判断下一节点是否存在

净化轨迹

	原始:1→1→2→3→3

	第一次净化:1→2→3→3(消除第二个1)

	第二次净化:1→2→3(消除第二个3)

🌐现实世界的链表魔法

  1. 网页时光机

    • 每个页面是时空节点
    • 后退键=prev指针,前进键=next指针
  2. 碎片空间魔法师

    • 操作系统用链表管理零散内存块
  3. AI行为树

    • NPC决策路径通过指针动态跳转
  4. 区块链密码学

    • 每个区块通过哈希指针形成信任链

冷知识
你的DNA就是天然双链表!

  • 数据域:ATCG碱基密码
  • 指针域:氢键连接的互补链

链表的真正魔力,在于用指针编织出动态的数据宇宙。当你在代码中熟练操控next指针时,就已经掌握了数据结构世界的"空间折叠术"——让计算机内存变成任你挥洒的创意画布!