//链表是一个此案型结构,同时也是一个天然的递归结构。链表结构可以充分利用计算机内存空间,
//实现灵活的内存动态管理。但是链表失去了数组随机读取的优点,同时链表由于增加了节点的指针域,
//空间开销比较大
//链表是一个线性结构,也是一个天然的递归结构,可以充分利用计算机内存空间,实现灵活的
//内存动态管理,但是失去了数组可以随机读取的优点,同时增加了节点的指针域,空间开销较大
//单向链表
class Node {
constructor(v, next) {
this.value = v
this.next = next
}
}
class LinkList {
constructor() {
//链表长度
this.size = 0
//虚拟头部
this.dummyNode = new Node(null, null)
}
find(header, index, currentIndex) {
if (index === currentIndex) {
return header
}
return this.find(header.next, index, currentIndex + 1)
}
addNode(v, index) {
this.checkIndex(index)
//当往链表末尾插入时,prev.next为空,其他情况时,因为要插入节点,所以
//插入的节点的next应该是prev.next,然后设置prev.next 为插入的节点
let prev = this.find(this.dummyNode, index, 0)
prev.next = new Node(v, prev.next)
this.size++
return prev.next
}
insertNode(v, index) {
return this.addNode(v, index)
}
addToFirst(v) {
return this.addNode(v, 0)
}
addToLast(v) {
return this.addNode(v, this.size)
}
removeNode(index, isLast) {
this.checkIndex(index)
index = isLast ? index - 1 : index
let prev = this.find(this.dummyNode, index, 0)
let node = prev.next
prev.next = node.next
node.next = null
this.size--
return node
}
removeFirstNode() {
return this.removeNode(0)
}
removeLastNode() {
return this.removeNode(this.size, true)
}
checkIndex(index) {
if (index < 0 || index > this.size) {
throw Error('index Error')
}
}
getNode(index) {
this.checkIndex(index)
if (this.isEmpty()) return
return
}
isEmpty() {
return this.size === 0
}
getSize() {
return this.size
}
}
var list = new LinkList()
list.addToFirst(100)
console.log(list)
//双向链表
// 双向链表的节点类(继承单向链表的节点类)
class DoublyNode extends Node {
constructor(element) {
super(element);
this.prev = null;
}
}
// 双向链表类继承单向链表类
class DoublyLinkedList extends LinkedList {
constructor() {
super();
this.tail = null;
}
}
// append(element) 往双向链表尾部追加一个新的元素
// 重写 append()
function append(element) {
// 1、创建双向链表节点
const newNode = new DoublyNode(element);
// 2、追加元素
if (this.head === null) {
this.head = newNode;
this.tail = newNode;
} else {
// !!跟单向链表不同,不用通过循环找到最后一个节点
// 巧妙之处
this.tail.next = newNode;
newNode.prev = this.tail;
this.tail = newNode;
}
this.length++;
}
// insert(position, data) 插入元素
// 重写 insert()
function insert(position, element) {
// 1、position 越界判断
if (position < 0 || position > this.length) return false;
// 2、创建新的双向链表节点
const newNode = new DoublyNode(element);
// 3、判断多种插入情况
if (position === 0) { // 在第 0 个位置插入
if (this.head === null) {
this.head = newNode;
this.tail = newNode;
} else {
//== 巧妙之处:相处腾出 this.head 空间,留个 newNode 来赋值 ==//
newNode.next = this.head;
this.head.perv = newNode;
this.head = newNode;
}
} else if (position === this.length) { // 在最后一个位置插入
this.tail.next = newNode;
newNode.prev = this.tail;
this.tail = newNode;
} else { // 在 0 ~ this.length 位置中间插入
let targetIndex = 0;
let currentNode = this.head;
let previousNode = null;
// 找到要插入位置的节点
while (targetIndex++ < position) {
previousNode = currentNode;
currentNode = currentNode.next;
}
// 交换节点信息
previousNode.next = newNode;
newNode.prev = previousNode;
newNode.next = currentNode;
currentNode.prev = newNode;
}
this.length++;
return true;
}
// removeAt() 删除指定位置的节点
// 重写 removeAt()
function removeAt(position) {
// 1、position 越界判断
if (position < 0 || position > this.length - 1) return null;
// 2、根据不同情况删除元素
let currentNode = this.head;
if (position === 0) { // 删除第一个节点的情况
if (this.length === 1) { // 链表内只有一个节点的情况
this.head = null;
this.tail = null;
} else { // 链表内有多个节点的情况
this.head = this.head.next;
this.head.prev = null;
}
} else if (position === this.length - 1) { // 删除最后一个节点的情况
currentNode = this.tail;
this.tail.prev.next = null;
this.tail = this.tail.prev;
} else { // 删除 0 ~ this.length - 1 里面节点的情况
let targetIndex = 0;
let previousNode = null;
while (targetIndex++ < position) {
previousNode = currentNode;
currentNode = currentNode.next;
}
previousNode.next = currentNode.next;
currentNode.next.perv = previousNode;
}
this.length--;
return currentNode.data;
}
// update(position, data) 修改指定位置的节点
// 重写 update()
function update(position, data) {
// 1、删除 position 位置的节点
const result = this.removeAt(position);
// 2、在 position 位置插入元素
this.insert(position, data);
return result;
}
forwardToString()
// forwardToString() 链表数据从前往后以字符串形式返回
function forwardToString() {
let currentNode = this.head;
let result = '';
// 遍历所有的节点,拼接为字符串,直到节点为 null
while (currentNode) {
result += currentNode.data + '--';
currentNode = currentNode.next;
}
return result;
}
// backwardString() 链表数据从后往前以字符串形式返回
function backwardString() {
let currentNode = this.tail;
let result = '';
// 遍历所有的节点,拼接为字符串,直到节点为 null
while (currentNode) {
result += currentNode.data + '--';
currentNode = currentNode.prev;
}
return result;
}