【TS数据结构】链表
链表
链表存储有序的元素集合,但不同于数组,链表中的元素在内存中并不是连续放置的。每个元素都由一个存储匀速本身的节点和一个指向下一个元素的引用组成。
链表中的一些方法
- push(element):向链表尾部添加一个新元素
- insert(element, position):在链表的指定位置插入一个新的元素
- getElementAt(index):返回链表中特点位置的元素。如果链表中不存在这样的元素,则返回undefined
- remove(element):从链表中移除一个元素
- indexOf(element):返回元素在链表中的索引。如果链表中没有该元素则返回-1
- removeAt(position):从链表的特定位置移除一个元素
- isEmpty():返回链表是否为空
- size():返回链表内包含的元素的个数
- toString():返回表示这个那个链表的字符串。
一般链表
import { defaultEqualFunction } from '../util/defaultEqualFunction'
export default class LinkedList<T> {
private count: number
private head: Node<T>
private equalFn: Function
constructor(equalFn = defaultEqualFunction) {
this.count = 0
this.head = undefined
this.equalFn = equalFn
}
[Symbol.iterator]() {
let current = this.head
return {
next() {
if (current) {
let res = current
current = current.next
return { done: false, value: res.element }
} else {
return { done: true, value: undefined }
}
},
}
}
/**
* 向链表尾部添加一个新元素
* @param element
*/
push(element: T) {
let node = new Node(element)
if (!this.head) {
this.head = node
} else {
let current = this.head
while (current.next) {
current = current.next
}
current.next = node
}
this.count++
}
/**
* 在链表的指定位置插入一个新的元素
* @param element
* @param position
*/
insert(element: T, position: number) {
position = position > this.count ? this.count : position
let newborn: Node<T>
switch (true) {
case position < 0:
throw new Error('invalid position')
case position === 0:
newborn = new Node<T>(element, this.head)
this.head = newborn
this.count++
case position === this.count:
this.push(element)
break
default:
let previous = this.getNodeAt(position - 1),
current = previous.next
newborn = new Node(element, current)
previous.next = newborn
this.count++
}
}
/**
* 获取第一个元素
* @return T
*/
getHead(): T {
return this.head.element
}
/**
* 返回链表中特点位置的元素。如果链表中不存在这样的元素,则返回undefined
* @param index
*/
getElementAt(index: number): T {
if (index < 0 || index >= this.count) return undefined
let current = this.head
for (let i = 0; i < this.count && current; i++) {
current = current.next
}
return current.element
}
/**
* 从链表中移除一个元素
* @param element
*/
remove(element: T) {
let current = this.head,
previous: Node<T>
while (current) {
previous = current
current = current.next
if (this.equalFn(current.element, element)) break
}
previous.next = current.next
this.count--
}
/**
* 返回元素在链表中的索引。如果链表中没有该元素则返回-1
* @param element
*/
indexOf(element: T) {
let current = this.head
for (let i = 0; i < this.count && current; i++) {
if (this.equalFn(current.element, element)) {
return i
}
current = current.next
}
return -1
}
/**
* 返回元素在链表中的索引。如果链表中没有该元素则返回-1
* @param index
* @return 移除的元素
*/
removeAt(index: number): T {
if (index < 0 || index >= this.count) return undefined
let current = this.head
if (index === 0) {
this.head = current.next
} else {
let previous = this.getNodeAt(index - 1)
current = previous.next
// 将previous和current的下一项连接起来,跳过current
previous.next = current.next
}
this.count--
return current.element
}
/**
* 返回链表是否为空
* @return boolean
*/
isEmpty() {
return this.size() === 0
}
/**
* 返回链表内包含的元素的个数
* @return size
*/
size(): number {
return this.count
}
/**
* 返回表示这个那个链表的字符串
* @return string
*/
toString() {
return [...this].join(' -> ')
}
/**
* 返回目标元素Node
* @param index 元素的下标
* @returns
*/
private getNodeAt(index: number): Node<T> {
if (index < 0 || index >= this.count) return undefined
let current = this.head
for (let i = 0; i < index && current; i++) {
current = current.next
}
return current
}
}
export class Node<T> {
public element: T
public next: Node<T> | undefined
constructor(element: T, next: Node<T> = undefined) {
this.element = element
this.next = next
}
}
从链表中移除元素

双向链表
链表有多种不同的类型,双向链表就是链表的一种变形。双向链表和一般链表的区别在于,在链表中一个节点只有链向下一个节点的链接;而在双向链表中,链接是双向的:一个链向下一个节点,一个链向前一个元素。
实现双向链表
import LinkedList, { Node } from './linked-list'
import { defaultEqualFunction } from '../util/defaultEqualFunction'
export default class DoublyLinkedList<T> extends LinkedList<T> {
protected tail: DoublyNode<T>
protected head: DoublyNode<T>
constructor(equalFn = defaultEqualFunction) {
super(equalFn)
this.tail = undefined
this.head = undefined
}
/**
* 在任意位置插入元素
* @param element 待插入的元素
* @param position 任意位置
* @returns 是否插入成功
*/
insert(element: T, position: number): boolean {
if (position < 0) throw new Error('Invalid position')
position = position > this.count ? this.count : position
const newborn = new DoublyNode(element)
let current = this.head
switch (true) {
case !current:
// 当链表为空时,直接将this.head设置为新生节点
this.head = newborn
this.tail = newborn
break
case position === 0:
// 当添加的位置是第一个时
current.prev = newborn
newborn.next = current
this.head = newborn
break
case position === this.count:
current = this.tail
current.next = newborn
newborn.prev = current
this.tail = newborn
break
default:
// 在中间添加元素
let previous = this.getNodeAt(position - 1) as DoublyNode<T>
current = previous.next
previous.next = newborn
newborn.prev = previous
newborn.next = current
current.prev = newborn
}
// 链表数量++
this.count++
return true
}
removeAt(index: number): T {
if (index < 0 || index >= this.count) throw new Error('invalid index')
let current = this.head
if (index === 0) {
current = current
this.head = current.next
this.head.prev = undefined
} else if (index === this.count - 1) {
current = this.tail
this.tail = current.prev
this.tail.next = undefined
} else {
let previous = this.getNodeAt(index - 1)
current = previous.next
previous.next = current.next
current.next.prev = previous
}
this.count--
return current.element
}
push(element: T) {
if (!this.head) {
let newborn = new DoublyNode(element)
this.head = newborn
this.tail = newborn
} else {
let newborn = new DoublyNode(element, undefined, this.tail)
this.tail.next = newborn
this.tail = newborn
}
this.count++
}
/**
* 返回目标元素Node
* @param index 元素的下标
* @returns
*/
protected getNodeAt(index: number): DoublyNode<T> {
if (index < 0 || index >= this.count) return undefined
let current = this.count / 2 < index ? this.tail : this.head
if (index > this.count / 2) {
for (let i = this.count - 1; i > index && current; i--) {
current = current.prev
}
} else {
for (let i = 0; i < index && current; i++) {
current = current.next
}
}
return current
}
toString(): string {
return [...this].join(' <-> ')
}
}
export class DoublyNode<T> extends Node<T> {
public prev: DoublyNode<T>
public next: DoublyNode<T>
constructor(
element: T,
next: DoublyNode<T> = undefined,
prev: DoublyNode<T> = undefined
) {
super(element, next)
this.prev = prev
}
}
双向链表的大部分逻辑和一般链表是相同的,所以我们让它继承自一般链表LinkedList只需要修改insert、push、removeAt方法即可。
循环链表
循环链表可以向链表一样只有单向引用,也可以像双向链表一样有双向引用。循环链表和链表之间的唯一区别在于,最后一个元素指向下一个元素的指针不是undefined,而是指向第一个元素head。

如果是双向循环链表,那么第一个节点head的prev指向的就是最后一个节点tail,相反tail的next指向的就是head。
实现单向循环链表
import { defaultEqualFunction } from './../util/defaultEqualFunction'
import LinkedList, { Node } from './linked-list'
export default class CircularLinkedList<T> extends LinkedList<T> {
constructor(equalFn = defaultEqualFunction) {
super(equalFn)
}
[Symbol.iterator]() {
let current = this.head
let _self = this
let i = 0
return {
next() {
if (i++ < _self.count) {
let res = current
current = current.next
return { done: false, value: res.element }
} else {
return { done: true, value: undefined }
}
},
}
}
/**
* 在指定的位置插入元素
* @param element 待插入的元素
* @param position 插入元素的位置
*/
insert(element: T, position: number) {
if (position < 0) throw new Error('invalid positive')
position = position > this.count ? this.count : position
let current = this.head
const newborn = new Node(element)
switch (position) {
case 0:
if (this.head) {
newborn.next = this.head
current = this.getNodeAt(this.count - 1)
this.head = newborn
current.next = newborn
} else {
this.head = newborn
}
break
default:
const previous = this.getNodeAt(position - 1)
current = previous.next
newborn.next = current
previous.next = newborn
}
this.count++
}
/**
* 在链表末尾添加元素
* @param element 待添加的元素
*/
push(element: T) {
this.insert(element, this.count)
}
/**
* 移除任意位置的元素
* @param position 位置
*/
removeAt(position: number): T {
if (position < 0 || position >= this.count)
throw new Error('Invalid position')
let current = this.head
if (position === 0) {
if (this.size() === 1) {
this.head = undefined
} else {
const lastNode = this.getNodeAt(this.count - 1)
lastNode.next = current.next
this.head = current.next
}
} else {
const previous = this.getNodeAt(position - 1)
current = previous.next
previous.next = current.next
}
this.count--
return current.element
}
}

浙公网安备 33010602011771号