链表设计(关于链表取值,增加,删除常用操作)

链表操作的两种方式

  1. 直接使用原来的链表来进行操作。
  2. 设置一个虚拟头结点在进行操作。

思路

  • 注意在链表添加节点时指针的指向顺序,先将新节点指针指向下一节点,再将上一节点指针指向新节点,否则容易出现赋值错误
node.next = new LinkNode(val, node.next); // 插入新节点
//和以下等价-->
// 创建新节点,并将其指向当前节点的下一个节点
const newNode = new LinkNode(val, node.next);   
// 将当前节点的 next 指针指向新节点
node.next = newNode; 

题目

 

示例代码

// 定义链表节点类  
class LinkNode {
    constructor(val, next) {
        this.val = val; // 节点存储的值  
        this.next = next; // 指向下一个节点的指针  
    }
}

/**  
 * 初始化链表数据结构  
 * 储存头尾节点以及节点数量  
 */
var MyLinkedList = function () {
    this._size = 0; // 节点数量  
    this._tail = null; // 尾节点指针  
    this._head = null; // 头节点指针  
};

/**  
 * 获取链表中索引为 index 的节点值。如果索引无效,返回 -1。   
 * @param {number} index - 节点索引  
 * @return {number} - 返回该节点的值,或 -1  
 */
MyLinkedList.prototype.getNode = function (index) {
    if (index < 0 || index >= this._size) return null; // 检查索引是否无效  
    // 创建一个虚拟头节点,方便处理  
    let cur = new LinkNode(0, this._head); // 虚拟头节点指向实际的头节点  
    // 跳过虚拟头节点,向后遍历到目标节点 
    while (index>= 0) {//这里画图预演就清晰了
        cur = cur.next;//指针向后移
        index--// 遍历到下一个节点  
    }
    return cur; // 返回目标节点  
};

/**  
 * 获取链表中索引为 index 的节点值。如果索引无效,返回 -1。  
 * @param {number} index - 节点索引  
 * @return {number} - 返回该节点的值,或 -1  
 */
MyLinkedList.prototype.get = function (index) {
    if (index < 0 || index >= this._size) return -1; // 检查索引是否无效  
    // 获取当前节点并返回其值  
    return this.getNode(index).val;
};

/**  
 * 在链表首部添加一个值为 val 的节点。  
 * @param {number} val - 要添加的节点值  
 * @return {void}  
 */
MyLinkedList.prototype.addAtHead = function (val) {
    const node = new LinkNode(val, this._head); // 创建新节点,指向当前头节点  
    this._head = node; // 更新头节点  
    this._size++; // 增加节点数量  
    if (!this._tail) { // 如果链表原本为空,更新尾节点  
        this._tail = node;
    }
};

/**  
 * 在链表尾部添加一个值为 val 的节点。   
 * @param {number} val - 要添加的节点值  
 * @return {void}  
 */
MyLinkedList.prototype.addAtTail = function (val) {
    const node = new LinkNode(val, null); // 创建新节点  
    this._size++; // 增加节点数量  
    if (this._tail) { // 如果链表非空,更新尾节点的指针  
        this._tail.next = node;
        this._tail = node; // 更新尾节点  
        return;
    }
    this._tail = node; // 如果链表为空,将头尾都指向新节点  
    this._head = node;
};

/**  
 * 在链表第 index 个位置插入值为 val 的节点。  
 * 如果 index 等于链表的长度,节点将被添加到链表的末尾。  
 * 如果 index 大于长度,则节点不会插入。  
 * @param {number} index - 插入位置  
 * @param {number} val - 要插入的节点值  
 * @return {void}  
 */
MyLinkedList.prototype.addAtIndex = function (index, val) {
    if (index > this._size) return; // 如果 index 大于节点数,则不插入  
    if (index <= 0) { // 如果 index 小于等于 0,直接添加到头部  
        this.addAtHead(val);
        return;
    }
    if (index === this._size) { // 如果 index 等于当前长度,添加到尾部  
        this.addAtTail(val);
        return;
    }
    // 获取目标节点的上一个节点  
    const node = this.getNode(index - 1);
    node.next = new LinkNode(val, node.next); // 插入新节点  
    this._size++; // 增加节点数量  
};

/**  
 * 删除链表中索引为 index 的节点,如果索引有效。  
 * @param {number} index - 要删除的节点索引  
 * @return {void}  
 */
MyLinkedList.prototype.deleteAtIndex = function (index) {
    if (index < 0 || index >= this._size) return; // 检查索引是否无效  
    if (index === 0) { // 如果删除的是头节点  
        this._head = this._head.next; // 更新头节点为下一个节点  
        // 如果删除的节点同时是尾节点,需要处理尾节点  
        if (index === this._size - 1) {
            this._tail = this._head; // 更新尾节点  
        }
        this._size--; // 减少节点数量  
        return;
    }
    // 获取目标节点的上一个节点  
    const node = this.getNode(index - 1);
    node.next = node.next.next; // 删去目标节点  
    // 处理尾节点  
    if (index === this._size - 1) {
        this._tail = node; // 更新尾节点  
    }
    this._size--; // 减少节点数量  
};

// 输出链表的内容,供调试用(如果需要的情况下可以启用)  
// MyLinkedList.prototype.out = function() {  
//     let cur = this._head;  
//     const res = [];  
//     while(cur) {  
//         res.push(cur.val); // 将当前节点的值加入结果数组  
//         cur = cur.next; // 遍历到下一个节点  
//     }  
// };  

  • 5
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值