反转单向链表

109 阅读2分钟

反转单向链表

题目

定义一个函数,输入一个单向链表的头节点,反转该链表,并输出反转之后的头节点

链表

链表是一种物理结构(非逻辑结构),是数组的补充。
数组需要一段连续的内存空间,而链表不需要。

数据结构

  • 单向链表 { value, next }
  • 双向链表 { value, prev, next }

两者对比

  • 链表:查询慢,新增和删除较快
  • 数组:查询快,新增和删除较慢
export function createLinkList(arr) {
    const length = arr.length
    if (length === 0) throw new Error('arr is empty')

    let curNode = {
        value: arr[length - 1]
    }
    if (length === 1) return curNode

    for (let i = length - 2; i >= 0; i--) {
        curNode = {
            value: arr[i],
            next: curNode
        }
    }
    return curNode
}

export function reverseLinkList(listNode) {
    // 定义三个指针
    let prevNode = undefined;
    let curNode = undefined;
    let nextNode = listNode;
    /**
     * 第一次 
     * prev = undefined 
     * cur = undefined 
     * next = {value:100,next:{value:200, next: {value: 300, next: {value: 400}}}}
     * 
     * 第二次 
     * prev = undefined 
     * cur = {value:100} 
     * next = {value:200, next: {value: 300, next: {value: 400}}}
     * 
     * 第三次
     * prev = {value:100}
     * cur = {value:200, next: {value:100}}
     * next = {value: 300, next: {value: 400}}
     * 
     * 第四次
     * prev = {value:200, next: {value:100}}
     * cur = {value: 300, next: {value:200, next: {value:100}}}
     * next = {value: 400}
     * 
     * 第五次
     * prev = {value: 300, next: {value:200, next: {value:100}}}
     * cur = {value: 400, next: {value: 300, next: {value:200, next: {value:100}}}}
     * next = undefined
     */

    // 以 nextNode 为主,遍历链表
    while(nextNode) {
        // 第一个元素,删掉 next ,防止循环引用
        if (curNode && !prevNode) {
            delete curNode.next
        }

        // 反转指针
        if (curNode && prevNode) {
            curNode.next = prevNode
        }

        // 整体向后移动指针
        prevNode = curNode
        curNode = nextNode
        nextNode = nextNode?.next
    }

    // 最后一个的补充:当 nextNode 空时,此时 curNode 尚未设置 next
    curNode.next = prevNode

    return curNode
}

const arr = [100, 200, 300, 400]
const list = createLinkList(arr)
const list1 = reverseLinkList(list)
console.log('list1:', list1)

扩展

思考:用数组和链表实现队列,哪个性能更好?

  • 链表
  • 链表和数组的不同
    • 内存占用
    • 查询、新增、删除的效率
  • 如何保证 nextNode 不丢失
class MyQueue1 {
  head = null;
  tail = null;
  len = 0;
  add(n) {
    const newNode = { value: n, next: null };
    // 处理head
    if (this.head == null) {
      this.head = newNode;
    }
    // 处理tail
    const tailNode = this.tail;
    if (tailNode) {
      tailNode.next = newNode;
    }
    this.tail = newNode;
    this.len++;
  }

  delete() {
    const headNode = this.head;
    if (headNode == null) return null;
    if (this.len <= 0) return null;
    // 取值
    const value = headNode.value;
    // 处理head
    this.head = headNode.next;
    // 记录长度
    this.len--;

    return value;
  }

  get length() {
    return this.len;
  }
}

// 功能测试
const q = new MyQueue1();
q.add(100);
q.add(200);
q.add(300);
console.info("length1", q.length);
console.log(q.delete());