链表操作的两种方式
- 直接使用原来的链表来进行操作。
- 设置一个虚拟头结点在进行操作。
思路
- 注意在链表添加节点时指针的指向顺序,先将新节点指针指向下一节点,再将上一节点指针指向新节点,否则容易出现赋值错误
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; // 遍历到下一个节点
// }
// };