1. 链表数据结构
-
链表是线性表的一种,所谓的线性表包含顺序线性表和链表,顺序线性表是用数组实现的,在内存中有顺序排列,通过改变数组大小实现。而链表不是用顺序实现的,用指针实现,在内存中不连续。意思就是说,链表就是将一系列不连续的内存联系起来,将那种碎片内存进行合理的利用,解决空间的问题。
-
相对于传统的数组,链表的一个好处在于,==添加或移除元素的时候不需要移动其他元素==。然而,链表需要使用指针,因此实现链表时需要额外注意。在数组中,我们可以直接访问任何位置的任何元素,而要想访问链表中间的一个元素,则需要从==起点(表头)开始迭代链表直到找到所需的元素==。
function defaultEquals(a, b) { return a === b; } class Node { constructor(element) { this.element = element; this.next = undefined; } } class LinkedList { constructor(equalsFn = defaultEquals) { this.conut = 0; this.head = undefined; this.equalsFn = equalsFn; } push(element) { //向链表尾部添加一个元素 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; } current.next = node; } this.conut++; } 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; } 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 current } return undefined } remove(element) { const index = this.indexOf(element); return this.removeAt(index); } insert(element, index) { if (index >= 0 && index <= this.count) { const node = new Node(element) if (index === 0) {//在第一个位置添加 const current = this.head node.next = current this.head = node } else { const previous = this.getElementAt(index - 1) const current = previous.next node.next = current previous.next = node } this.count++ return true } return false } indexOf(element) { //返回一个元素的位置 let current = this.head; for (let i = 0; i < this.size() && current != null; i++) { if (this.equalsFn(element, current.element)) { return i; } current = current.next; } return -1; } isEmpty() { return this.size() === 0; } size() { return this.count; } getHead() { return this.head; } clear() { this.head = undefined; this.count = 0; } toString() { if (this.head == null) { return ''; } let objString = `${this.head.element}`; let current = this.head.next; for (let i = 1; i < this.size() && current != null; i++) { objString = `${objString},${current.element}`; current = current.next; } return objString; } }
2. 双向链表
- 双向链表和普通链表的区别在于,在普通链表中,一个节点只有链向下一个节点的链接;而在双向链表中,链接是双向的:一个链向上一个元素,一个链向下一个元素。
//双向链表
class DoublyNode extends Node{
constructor(element, next, prev) {
super(element, next)
this.prev = prev
}
}
class DoublyLinkedList extends LinkedList{
constructor(equalsFn = defaultEquals) {
super(equalsFn)
this.tail = undefined
}
insert(element, index) {
if (index >= 0 && index <= this.count) {
const node = new DoublyNode(element)
let current = this.head
if (index === 0) {//在第一项中插入
if (this.head == null) {
this.head = node
this.tail = node
} else {
node.next = this.head
current.prev = node
this.head = node
}
} else if (index === this.count) {//在最后一项插入
current = this.tail
current.next = node
node.prev = current
this.tail = node
} else {
const previous = this.getElementAt(index - 1)
current = previous.next
node.next = current
previous.next = node
current.prev = node
node.prev = previous
}
this.count++
return true
}
return false
}
removeAt(index) {
if (index >= 0 && index < this.count) {
let current = this.head
if (index === 0) {//移除第一项
this.head = current.next
//r如果只有一项,更新tail
if (this.conut === 1) {
this.tail = undefined
} else {
this.head.prev = undefined
}
} else if (index === this.count - 1) {//最后一项
current = this.tail
this.tail = current.prev
this.tail.next = undefined
} else {
current = this.getElementAt(index)
const previous = current.prev
previous.next = current.next
current.next.prev = previous
}
this.count--
return current.element
}
return undefined
}
}
3. 循环链表
- 循环链表可以像链表一样只有单向引用,也可以像双向链表一样有双向引用。循环链表和链表之间唯一的区别就是==最后一个元素指向下一个元素不是引用undefined,而是指向第一个元素==。
//循环链表
class CircularLinkedList extends LinkedList{
constructor(equalsFn = defaultEquals) {
super(equalsFn)
}
insert(element, index) {
if (index >= 0 && index <= this.count) {
const node = new Node(element)
let current = this.head
if (index === 0) {
if (this.head == null) {
this.node = node
node.next = this.head
} else {
node.next = current
current = this.getElementAt(this.size())
this.head = node
current.next = this.head
}
} else {
const previous = this.getElementAt(index-1)
node.next = previous.next
previous.next = node
}
this.count++
return true
}
return false
}
removeAt(index) {
if (index >= 0 & index < this.count) {
if (index === 0) {
if (this.size() === 1) {
this.head = undefined
} else {
const removed = this.head
current = this.getElementAt(this.size())
this.head = this.head.next
current.next = this.head
current = removed
}
} else {
const previous = this.getElementAt(index - 1)
current = previous.next
previous.next = current.next
}
this.count--
return current.element
}
return undefined
}
}
4. 有序链表
- 有序链表是指==保持元素有序==的链表结构
//有序链表
const Compare = {
LESS_THAN: -1,
BIGGER_THAN: 1
}
function defaultCompare(a, b) {
if (a === b) {
return 0
}
return a < b ? Compare.LESS_THAN : Compare.BIGGER_THAN
}
class SortLinkedList extends LinkedList{
constructor(equalsFn = defaultEquals, compareFn = defaultCompare) {
super(equalsFn)
this.compareFn = compareFn
}
insert(element, index = 0) {
if (this.isEmpty()) {
return super.insert(element, 0)
}
const pos = this.getIndexNextSortedElement(element)
return super.insert(element, pos)
}
getIndexNextSortedElement(element) {
let current = this.head
let i = 0
for (; i < this.size() && current; i++){
const comp = this.compareFn(element, current.element)
if (comp === Compare.LESS_THAN) {
return i
}
current = current.next
}
return i
}
}