JavaScript版数据结构与算法-链表

27 篇文章 0 订阅
6 篇文章 0 订阅

JavaScript版数据结构与算法-链表

链表

  • 多个元素组成的列表
  • 元素存储不连续,用next指针连在一起
链表 VS 数组
  • **数组:**增删非首尾元素时往往需要移动元素
  • **链表:**增删非首尾元素,不需要移动元素,只需要更改next的指向即可
js的链表
  • js中是没有链表
  • 可以用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){
    p = p.next
}

// 插入
const e = { val : 'e'}
c.next = e
e.next    = d

// 删除
c.next = d
237. 删除链表中的节点

请编写一个函数,使其可以删除某个链表中给定的(非末尾)节点。传入函数的唯一参数为 要被删除的节点 。

现有一个链表 – head = [4,5,1,9],它可以表示为:

4 ==> 5 >1>9

解题思路
  • 无法直接获取被删除节点的上个节点
  • 将被删除节点转移到下个节点
解题步骤
  • 将被删节点的值改为下个节点的值
  • 删除下个节点
/**
 * 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
    node.next = node.next.next
};
206. 反转链表

反转一个单链表。

示例:

输入: 1->2->3->4->5->NULL
输出: 5->4->3->2->1->NULL
解题思路
  • 反转俩个节点,将n+1next指向 n
  • 反转多个节点:双指针遍历链表,重复上述操作
解题步骤
  • 双指针一前一后遍历链表
  • 反转双指针
/**
 * Definition for singly-linked list.
 * function ListNode(val) {
 *     this.val = val;
 *     this.next = null;
 * }
 */
/**
 * @param {ListNode} head
 * @return {ListNode}
 */
var reverseList = function(head) {
    let p1 = head;
    let p2 = null;
    while(p1){
        let tmp = p1.next;
        p1.next = p2
        p2 = p1
        p1 = tmp 
    }
    return p2
};
2. 两数相加

给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。

请你将两个数相加,并以相同形式返回一个表示和的链表。

你可以假设除了数字 0 之外,这两个数都不会以 0 开头。

示例:

输入:l1 = [2,4,3], l2 = [5,6,4]
输出:[7,0,8]
解释:342 + 465 = 807.
解题思路
  • 模拟相加操作
  • 遍历链表
解题步骤
  • 新建一个空链表
  • 遍历被相加的俩个链表,模拟相加操作,将 个位数 追加到新链表上,将十位数留到下一位去相加
/**
 * 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;
    let p2 = l2;
    let p3 = l3;
    let carry = 0
    while(p1 || p2){
        let v1 = p1 ? p1.val : 0;
        let v2 = p2 ? p2.val : 0;
        let v3 = v1 + v2 + carry;
        carry = Math.floor(v3/10);
        p3.next = new ListNode(v3 % 10) ;
        if(p1) p1 =p1.next;
        if(p2) p2 =p2.next;
        p3 = p3.next;
    }
    if(carry) p3.next = new ListNode(carry);
    return l3.next
};
83. 删除排序链表中的重复元素

给定一个排序链表,删除所有重复的元素,使得每个元素只出现一次。

示例 1:

输入: 1->1->2
输出: 1->2
解题思路
  • 因为链表是有序的,所以重复元素一定相邻
  • 遍历链表,如果发现当前元素和下个元素值相同,就删除下个元素值
解题步骤
  • 遍历链表,如果发现当前元素和下个元素值相同,就删除下个元素值
  • 遍历结束后,返回原链表的头部
/**
 * 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 p1 = head;
    while (p1 && p1.next){
        if (p1.val === p1.next.val){
            p1.next = p1.next.next
        }else{
            p1 = p1.next
        }
    }
    return head
};
141. 环形链表

给定一个链表,判断链表中是否有环。

如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。

如果链表中存在环,则返回 true 。 否则,返回 false 。

输入:head = [3,2,0,-4], pos = 1
输出:true
解释:链表中有一个环,其尾部连接到第二个节点。

输入:head = [1], pos = -1
输出:false
解释:链表中没有环。
解题思路
  • 跑步,跑的快一定比跑得慢的快一圈
  • 用一块一慢俩个指针遍历链表,如果指针能够相逢,那么链表就有圈
解题步骤
  • 用一块一慢俩个指针遍历链表,如果指针能够相逢,就返回 true, slowhead 开始,fasthead.next开始,如果移动过程中 fast 可以追到 slow,则则证明有环,如果 feat 移动到链表末尾说明没有环
  • 遍历结束后,还没有相逢就返回 false
/**
 * 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;
    let p2 = head;
    while( p1 && p2 && p2.next){
        p1 = p1.next
        p2 = p2.next.next
        if(p1 === p2) return true
    }
    return false
};
原型链简介
  • 原型链的本质是链表

  • 原型链上的节点是各种原型对象,比如:Function.prototypeObject.prototype...

  • 原型链通过__proto__属性连接各种原型对象

  • obj => Object.prototype => null

  • func => Function.prototype = > Object.Prototype => null

  • arr => Array.prototype => Object.prototype => null

实现原型链
const instanceOf = (A,B) =>{
    let p = A
    while(p){
        if (B = p.prototype) return true
        p = p.__proto__
    }
    return false
}

总结

  • 链表里的元素存储是不连续的,之间通过 next 链接
  • js中没有链表,但是可以用Object模拟链表
  • 链表常用操作:修改 next 、 遍历链表
  • js中的原型链也是一个链表
  • 使用链表指针可以获取 JSON 的节点值
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值