1.链表的数据结构
什么是链表?
- 链表是存储有序的元素集合,不同于数组,链表中的元素在内存中不是有序放置的。元素是一个由存储元素本身的节点和一个指向下一个元素的引用组成。
链表结构图:
链表的优点:
- 添加或移除元素时不需要移动其他元素。
元素的访问:
- 需要从起点(表头)开始迭代链表指导找到目标元素。
1.1 创建链表
- 链表基本类
/**
* 比较是否相等
* @param {*} a
* @param {*} b
* @returns Boolean
*/
function defaultEquals(a, b) {
return a === b;
}
/**
* 要添加到链表中节点
*/
class Node {
constructor(element, next) {
this.element = element; // 要加入的值
this.next = next; // 指向链表下一元素指针
}
}
/**
* 创建的链表类
*/
class LinkedList {
constructor(equalsFn = defaultEquals) {
this.count = 0; // 用来存储链表中的元素数量
this.head = undefined; // 保存元素引用
this.equalsFn= equalsFn;// 链表中的元素是否相等
}
}
复制代码
1.1.1 链表尾部添加元素方法
可能场景:
- 链表为空时;
- 不为空时;
方法实现:
/**
* 在链表尾部添加新元素
* @param {*} element
*/
push(element) {
// 创建Node项
const node = new Node(element);
let current;
// 链表为空时
if (this.head == null) {
this.head = node;
} else {
// 不为空时
current = this.head;
// 找到最后一项
while (current.next != null) {
current = current.next;
}
// 将next赋为新元素,建立连接
current.next = node;
}
// 递增链表的长度
this.count++;
}
复制代码
测试:
const linkedList = new LinkedList();
linkedList.push(1);
linkedList.push(2);
linkedList.push(3);
console.log("linkedList", linkedList);
复制代码
1.1.2 链表特定位置移除元素方法
移除方式:
- 特定位置
- 任意位置 方法实现:
/**
* 链表特定位置移除元素方法
*/
removeAt(index) {
// 检查越界值
if (index >= 0 && index < this.count) {
let current = this.head;
// 删除第一个元素
if (index === 0) {
this.head = current.next;
} else {
// 删除其余某个元素
let previous;
for (let i = 0; i < index; i++) {
previous = current;
current = current.next;
}
// 将previous与current的下一项连接起来,跳过current,从而移除它;
previous.next = current.next;
}
}
this.count--;
return undefined;
}
复制代码
1.1.3 获取链表特定位置元素方法
方法实现:
/**
* 获取链表特定位置元素方法
*/
getElementAt(index){
// 检查越界值
if (index >= 0 && index <= this.count) {
let node = this.head;
// 迭代整个链表直到目标
for (let i = 0; i < index&&node!=null; i++) {
node = node.next;
}
return node;
}
return undefined;
}
复制代码
1.1.4 在任意位置插入元素
/**
* 在任意位置插入元素
*/
insert(element, index) {
// 检查越界值
if (index >= 0 && index <= this.count) {
// 创建Node项
const node = new Node(element);
// 第一个位置添加
if (index === 0) {
const current = this.head;
node.next = current.next;
this.head = node;
} else {
// 其他位置添加
// 找到目标位置元素
const previous = this.getElementAt(index - 1);
const current = previous.next;
node.next = current.next;
previous.next = node;
}
}
}
复制代码
1.1.5 返回元素位置
/**
* 返回元素位置
*/
indexOf(element) {
let current = this.head;
for (let i = 0; i < this.count&¤t!=null; i++) {
if (this.equalsFn(element, current.element)) {
return i;
}
current = current.next;
}
return -1;
}
复制代码
1.1.6 从链表中移除元素
/**
* 从链表中移除元素
*/
remove(element) {
const index = this.indexOf(element);
return this.removeAt(index);
}
复制代码
1.1.7 isEmpty、size和getHead方法
/** 获取链表元素个数 */
size() {
return this.count;
}
/** 判断是否空链表 */
isEmpty() {
return this.size() === 0;
}
/** 获取链表 */
getHead() {
return this.head;
}
复制代码
1.1.8 将链表转换成一个字符串
/** 将链表转换成一个字符串 */
toString() {
if (this.head == null) {
return "";
}
let objString = `${this.head.element}`;
let current = this.head.next;
for (let i = 1; i < this.size()&¤t!=null; i++) {
objString = `${objString},${current.element}`;
current = current.next;
}
return objString;
}
复制代码