数据结构之“链表”

242 阅读3分钟

链表简介

链表是什么?

  • 多个元素组成的列表。
  • 元素存储不连续,用next指针连在一起

数组 vs 链表

  • 数组:增删非首尾元素时往往需要移动元素
  • 链表:增删非首尾元素,不需要移动元素,只需要更改next的指向即可。

JS中的链表

  • JavaScript中没有链表
  • 可以用Object模拟链表

代码演示

const a = {val : 'a'};
const b = {val : 'b'};
const c = {val : 'c'};
const d = {val : 'd'};
a.next = b;
b.next = c;
c.next = d;

//遍历链表
let p = a;
while(p){
    console.log(p.val);
    p = p.val;
}
//插入
const e = {val:'e'};
c.next = e;
e.next = d;
//删除
c.next = d;

LeetCode:237.删除链表中的节点

image.png 解题思路

  • 无法直接获取被删除节点的上个节点。
  • 将被删除节点转移到下个节点。 解题步骤
  • 将被删节点的值改为下个节点的值。
  • 删除下个节点。 代码题解:
/**
 * Definition for singly-linked list.
 * function ListNode(val) {
 *     this.val = val;
 *     this.next = null;
 * }
 */
/**
 * @param {ListNode} node
 * @return {void} Do not return anything, modify node in-place instead.
 */
var deleteNode = function(node) {
    node.val = node.next.val;
    node.next = node.next.next;
};

LeetCode206:反转链表

image.png 解题思路

  • 反转两个节点:将n+1的next指向n
  • 反转多个节点:双指针遍历链表,重复上述操作 解题步骤
  • 双指针一前一后遍历链表
  • 反转双指针 题解coding:
/**
 * Definition for singly-linked list.
 * function ListNode(val, next) {
 *     this.val = (val===undefined ? 0 : val)
 *     this.next = (next===undefined ? null : next)
 * }
 */
/**
 * @param {ListNode} head
 * @return {ListNode}
 */
var reverseList = function(head) {
    let p1 = head;
    let p2 = null;
    while(p1){
        let temp = p1.next;
        p1.next = p2;
        p2 = p1;
        p1 = temp;
    }
    return p2; 
};

LeetCode2:两数相加

image.png

解题思路

  • 小学数学题,模拟相加操作
  • 需要遍历链表 解题步骤
  • 新建一个空链表
  • 遍历被相加的两个链表,模拟相加操作,将个位数追加到新链表上,将十位数留到下一位去相加 题解coding:
/**
 * Definition for singly-linked list.
 * function ListNode(val, next) {
 *     this.val = (val===undefined ? 0 : val)
 *     this.next = (next===undefined ? null : next)
 * }
 */
/**
 * @param {ListNode} l1
 * @param {ListNode} l2
 * @return {ListNode}
 */
var addTwoNumbers = function(l1, l2) {
    let l3 = new ListNode(0);
    let p1 = l1, p2 = l2, p3 = l3;
    let carry = 0;
    while(p1 || p2){
        const v1 = p1 ? p1.val : 0;
        const v2 = p2 ? p2.val : 0;
        const val = v1 + v2 + carry;
        carry = Math.floor(val/10);
        p3.next = new ListNode(val%10);
        
        if(p1) p1 = p1.next;
        if(p2) p2 = p2.next;
        p3 = p3.next;
    }
    if(carry){
        p3.next = new ListNode(carry);
    }
    return l3.next;
};

LeetCode83:删除排序链表中的重复元素

image.png 解题思路

  • 因为链表是有序的,所以重复元素一定相邻
  • 遍历链表,如果发现当前元素和下个元素值相同,就删除下个元素值 解题步骤
  • 遍历链表,如果发现当前元素和下个元素值相同,就删除下个元素值
  • 遍历结束后,返回原链表的头部 题解Coding:
/**
 * Definition for singly-linked list.
 * function ListNode(val, next) {
 *     this.val = (val===undefined ? 0 : val)
 *     this.next = (next===undefined ? null : next)
 * }
 */
/**
 * @param {ListNode} head
 * @return {ListNode}
 */
var deleteDuplicates = function(head) {
    let p = head;
    while(p && p.next){
        if(p.val === p.next.val){
            p.next = p.next.next;
        }else{
            p = p.next;
        }
    }
    return head;
};

Leetcode141:环形链表

image.png 解题思路

  • 两个人在圆形操场上的起点同时起跑,速度快的人一定会超过速度慢的人一圈
  • 用一快一慢两个指针遍历链表,如果指针能够相逢,那么链表就有圈 解题步骤
  • 用一快一慢两个指针遍历链表,如果指针能够相逢,就返回true
  • 遍历结束后,还没有相逢就返回false 题解coding:
/**
 * Definition for singly-linked list.
 * function ListNode(val) {
 *     this.val = val;
 *     this.next = null;
 * }
 */

/**
 * @param {ListNode} head
 * @return {boolean}
 */
var hasCycle = function(head) {
    let p1 = head ,p2 = head;
    while(p1 && p2 && p2.next){
        p1 = p1.next;
        p2 = p2.next.next;
        if(p1 === p2){
            return true;
        }
    }
    return false;
};