算法随笔 — 线性表基础 — 链表

单链表是什么

已经熟悉单链表概念的读者可以跳至单链表的实现或习题。

链表和数组很像,它们都是线性的存储结构,它们的不同点是数组是用一段连续的内存地址来存储数据,这也是为什么数组可以通过下标来直接访问的原因。

链表是相对松散的线性结构,也就是说链表中每个节点的物理地址可能不是连续的。

数组读取数据的时间复杂度是O(1),而链表则是O(n),因为要访问链表的某个节点必须从头开始遍历。

链表中的一个节点可以分为两部分:指针域和数据域。

指针域是用来指向下一个节点的位置,而数据域则是用来存储这个节点表示的数据。

单链表
链表常用场景

  1. 操作系统内的动态内存分配 (一种实现方式)
  2. LRU 缓存淘汰算法

单链表的实现

单链表的实现方式主要有两种,通过对象引用的方式和数组方式

1.对象形式

class ListNode {
   
  val: any
  next: ListNode | null
  constructor(val: any, next: ListNode) {
   
    this.val = val === undefined ? 0 : val
    this.next = next === undefined ? null : next
  }
}

function checkChain(head: ListNode) {
   
  let result = ''
  while (head) {
   
    result += head.val + '->'
    head = head.next
  }
  console.log(result)
}

// main
const head = new ListNode(0, null)
const node1 = new ListNode(1, null)
const node2 = new ListNode(2, null)
const node3 = new ListNode(3, null)

head.next = node1
node1.next = node2
node2.next = node3

checkChain(head) // 0->1->2->3->

2.数组形式

通过双数组实现链表

// @ts-ignore
const data: number[] = new Array(10).fill(0)
// @ts-ignore
const next: number[] = new Array(10).fill(0)

const add = (lastPointer: number, curPointer: number, val: number) => {
   
  next[lastPointer] = curPointer
  data[curPointer] = val
}

// main
//* 定义头节点
const head = 3
data[3] = 0

//* 添加后续节点
add(3, 5, 1)
add(5, 2, 2)
add(2, 7, 3)
add(7, 9, 100)

//* 遍历链表
let p = head
let result = ''
while (p !== 0) {
   
  result += `${
     data[p]}->`
  p = next[p]
}
console.log(result)	// 0->1->2->3->100->

习题

以下是在LeetCode上有关单链表的习题,有条件的读者可以边看边做。

只要是不看答案就写不出来的都不算是掌握了。

===================================

leetCode 141 环形链表

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

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

如果链表中存在环,则返回 true 。 否则,返回 false 。
leetCode141
解题思路:
使用快慢指针,慢指针每次走一步,快指针每次走两步,如果有环,两个指针迟早会指向同一个节点。

由于每次快指针都比慢指针多走一步,所以当两指针都进入环时,每走一次二者的距离都少1。

function hasCycle(head: ListNode | null): boolean {
   
    if (!head || !head.next) return false
    let slow = head, fast = head
    do {
   
        slow = slow.next
        fast = fast.next.next
    } while (slow !== fast && fast && fast.next)
    return !!fast && !!fast.next
};

141

===================================

leetCode 142 环形链表2

给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。

为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值