JavaScript--链表操作

在 JavaScript 里,链表是一种常见的数据结构,由多个节点构成,每个节点包含数据和指向下一个节点的引用。下面是对链表的详细介绍,包含链表的创建、插入、删除、查找等操作。
链表节点的定义

class ListNode {
    constructor(value) {
        this.value = value;
        this.next = null;
    }
}

链表类的定义

class LinkedList {
    constructor() {
        this.head = null;
        this.tail = null;
        this.length = 0;
    }

    // 在链表尾部添加节点
    append(value) {
        const newNode = new ListNode(value);
        if (!this.head) {
            this.head = newNode;
            this.tail = newNode;
        } else {
            this.tail.next = newNode;
            this.tail = newNode;
        }
        this.length++;
        return this;
    }

    // 在链表头部添加节点
    prepend(value) {
        const newNode = new ListNode(value);
        if (!this.head) {
            this.head = newNode;
            this.tail = newNode;
        } else {
            newNode.next = this.head;
            this.head = newNode;
        }
        this.length++;
        return this;
    }

    // 根据索引获取节点
    getNodeByIndex(index) {
        if (index < 0 || index >= this.length) return null;
        let counter = 0;
        let currentNode = this.head;
        while (counter !== index) {
            currentNode = currentNode.next;
            counter++;
        }
        return currentNode;
    }

    // 在指定索引位置插入节点
    insert(index, value) {
        if (index === 0) return this.prepend(value);
        if (index === this.length) return this.append(value);
        const newNode = new ListNode(value);
        const leader = this.getNodeByIndex(index - 1);
        newNode.next = leader.next;
        leader.next = newNode;
        this.length++;
        return this;
    }

    // 删除指定索引位置的节点
    remove(index) {
        if (index < 0 || index >= this.length) return null;
        if (index === 0) {
            const removedNode = this.head;
            this.head = this.head.next;
            if (this.length === 1) {
                this.tail = null;
            }
            this.length--;
            return removedNode;
        }
        const leader = this.getNodeByIndex(index - 1);
        const removedNode = leader.next;
        leader.next = removedNode.next;
        if (index === this.length - 1) {
            this.tail = leader;
        }
        this.length--;
        return removedNode;
    }

    // 将链表转换为数组
    toArray() {
        const nodes = [];
        let currentNode = this.head;
        while (currentNode) {
            nodes.push(currentNode.value);
            currentNode = currentNode.next;
        }
        return nodes;
    }
}

使用示例

// 创建一个新的链表
const linkedList = new LinkedList();

// 在链表尾部添加节点
linkedList.append(1);
linkedList.append(2);
linkedList.append(3);

// 在链表头部添加节点
linkedList.prepend(0);

// 在指定索引位置插入节点
linkedList.insert(2, 1.5);

// 删除指定索引位置的节点
linkedList.remove(3);

// 将链表转换为数组并打印
console.log(linkedList.toArray()); 

上述代码中,ListNode 类用来表示链表的节点,LinkedList 类则用来表示链表。LinkedList 类包含了添加节点、删除节点、插入节点等操作的方法。最后,展示如何创建链表、添加节点、插入节点、删除节点以及将链表转换为数组。

链表的使用场景

实现栈和队列

栈和队列是常见的线性数据结构,链表可用于实现它们。栈遵循后进先出(LIFO)原则,队列遵循先进先出(FIFO)原则。借助链表,能够轻松实现这些数据结构的基本操作。

管理动态数据集合

当需要处理动态变化的数据集合时,链表能发挥很好的作用。与数组不同,链表在插入和删除元素时不需要移动大量元素,其时间复杂度为 (O(1))(在已知节点位置的情况下),所以适合频繁进行插入和删除操作的场景。

实现哈希表的冲突处理

哈希表在发生哈希冲突时,可使用链表来解决。每个哈希桶存储一个链表,当多个键映射到同一个哈希桶时,这些键值对会以链表节点的形式存储在该链表中。

class HashTableNode {
    constructor(key, value) {
        this.key = key;
        this.value = value;
        this.next = null;
    }
}

class HashTable {
    constructor(size = 10) {
        this.buckets = new Array(size);
    }

    hash(key) {
        let hashValue = 0;
        for (let i = 0; i < key.length; i++) {
            hashValue += key.charCodeAt(i);
        }
        return hashValue % this.buckets.length;
    }

    set(key, value) {
        const index = this.hash(key);
        const newNode = new HashTableNode(key, value);
        if (!this.buckets[index]) {
            this.buckets[index] = newNode;
        } else {
            let current = this.buckets[index];
            while (current.next) {
                current = current.next;
            }
            current.next = newNode;
        }
    }

    get(key) {
        const index = this.hash(key);
        let current = this.buckets[index];
        while (current) {
            if (current.key === key) {
                return current.value;
            }
            current = current.next;
        }
        return null;
    }
}
浏览器历史记录管理

在浏览器里,历史记录的管理可以借助双向链表来实现。双向链表的每个节点代表一个浏览过的页面,用户可以通过前进和后退按钮在历史记录中移动。

任务调度

在任务调度系统中,链表可用于管理待执行的任务队列。新任务可添加到链表尾部,调度器按顺序从链表头部取出任务执行。

这些场景都体现了链表在动态数据处理、频繁插入删除操作等方面的优势,能够提高程序的性能和效率。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值