commit
4d1ff58273
106
typescript/06_linkedlist/LRUCache.ts
Normal file
106
typescript/06_linkedlist/LRUCache.ts
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
/**
|
||||||
|
* 基于Map和双向链表实现的LRU算法
|
||||||
|
* 使用泛型可以存储多种类型的数据
|
||||||
|
*/
|
||||||
|
class LRUCache<K, V> {
|
||||||
|
private cacheMap: Map<K, LinkedListNode<K, V>>
|
||||||
|
private readonly limit: number
|
||||||
|
private head: LinkedListNode<K, V> | null = null
|
||||||
|
private end: LinkedListNode<K, V> | null = null
|
||||||
|
|
||||||
|
constructor(limit: number) {
|
||||||
|
if (limit <= 0) throw new Error('limit of cache must > 0')
|
||||||
|
this.cacheMap = new Map()
|
||||||
|
this.limit = limit
|
||||||
|
}
|
||||||
|
|
||||||
|
public get(key: K): V | null {
|
||||||
|
const node = this.cacheMap.get(key)
|
||||||
|
if (!node) return null
|
||||||
|
this.refreshNode(node)
|
||||||
|
return node.value
|
||||||
|
}
|
||||||
|
|
||||||
|
public put(key: K, value: V) {
|
||||||
|
const node = this.cacheMap.get(key)
|
||||||
|
// 原缓存不存在则加入到队尾
|
||||||
|
if (!node) {
|
||||||
|
// 大于规定的size则删除最不常用的
|
||||||
|
if (this.cacheMap.size >= this.limit) {
|
||||||
|
const oldKey = this.removeNode(this.head!)
|
||||||
|
this.cacheMap.delete(oldKey)
|
||||||
|
}
|
||||||
|
// 在队尾添加
|
||||||
|
const newNode = new LinkedListNode(key, value)
|
||||||
|
this.addNode(newNode)
|
||||||
|
this.cacheMap.set(key, newNode)
|
||||||
|
} else {
|
||||||
|
node.value = value
|
||||||
|
this.refreshNode(node)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private refreshNode(node: LinkedListNode<K, V>) {
|
||||||
|
if (node === this.end) return
|
||||||
|
this.removeNode(node)
|
||||||
|
this.addNode(node)
|
||||||
|
}
|
||||||
|
|
||||||
|
private removeNode(node: LinkedListNode<K, V>): K {
|
||||||
|
if (node === this.end) {
|
||||||
|
this.end = this.end.prev
|
||||||
|
} else if (node === this.head) {
|
||||||
|
this.head = this.head.next
|
||||||
|
} else {
|
||||||
|
// 这个由于排除了首尾节点
|
||||||
|
node.prev!.next = node.next
|
||||||
|
node.next!.prev = node.prev
|
||||||
|
}
|
||||||
|
return node.key
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 这里向尾部追加节点
|
||||||
|
* @param node
|
||||||
|
*/
|
||||||
|
private addNode(node: LinkedListNode<K, V>) {
|
||||||
|
if (this.end) {
|
||||||
|
this.end.next = node
|
||||||
|
node.prev = this.end
|
||||||
|
}
|
||||||
|
this.end = node
|
||||||
|
if (this.head === null) {
|
||||||
|
this.head = node
|
||||||
|
}
|
||||||
|
// 消除之前的节点的下一个引用对象,防止无限循环
|
||||||
|
node.next = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class LinkedListNode<K, V> {
|
||||||
|
key: K
|
||||||
|
value: V
|
||||||
|
next: LinkedListNode<K, V> | null
|
||||||
|
prev: LinkedListNode<K, V> | null
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
key: K,
|
||||||
|
value: V,
|
||||||
|
next: LinkedListNode<K, V> | null = null,
|
||||||
|
prev: LinkedListNode<K, V> | null = null
|
||||||
|
) {
|
||||||
|
this.key = key
|
||||||
|
this.value = value
|
||||||
|
this.next = next
|
||||||
|
this.prev = prev
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const cache = new LRUCache<string,string>(3)
|
||||||
|
cache.put('lv','xzw')
|
||||||
|
cache.put('lv2','xzw2')
|
||||||
|
cache.put('lv3','xzw3')
|
||||||
|
cache.put('lv4','xzw4')
|
||||||
|
cache.put('lv5','xzw5')
|
||||||
|
|
||||||
|
console.log(cache)
|
132
typescript/06_linkedlist/LinkedList.ts
Normal file
132
typescript/06_linkedlist/LinkedList.ts
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
/**
|
||||||
|
* 双向链表,更加常用设计也更加复杂一些
|
||||||
|
* 需要更多的存储空间和操作复杂度
|
||||||
|
*/
|
||||||
|
import List from './List'
|
||||||
|
|
||||||
|
class LinkedList<T> implements List<T> {
|
||||||
|
size: number = 0
|
||||||
|
private head: LinkedListNode<T> | null = null
|
||||||
|
private last: LinkedListNode<T> | null = null
|
||||||
|
|
||||||
|
findByIndex(index: number): LinkedListNode<T> | null {
|
||||||
|
let p = this.head
|
||||||
|
let pos = 0
|
||||||
|
while (p && pos !== index) {
|
||||||
|
p = p.next
|
||||||
|
pos++
|
||||||
|
}
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
findByValue(value: T): LinkedListNode<T> | null {
|
||||||
|
let p = this.head
|
||||||
|
while (p && p.item !== value) {
|
||||||
|
p = p.next
|
||||||
|
}
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
insertToHead(value: T): void {
|
||||||
|
let p = this.head
|
||||||
|
const newNode = new LinkedListNode(value)
|
||||||
|
// 没有元素的时候需要初始化头节点和尾节点
|
||||||
|
if (!p) {
|
||||||
|
this.last = this.head = newNode
|
||||||
|
} else {
|
||||||
|
p.prev = newNode
|
||||||
|
newNode.next = p
|
||||||
|
this.head = newNode
|
||||||
|
}
|
||||||
|
this.size++
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 在指定的index后面插入节点
|
||||||
|
* @param value 节点的值
|
||||||
|
* @param index 指定的位置
|
||||||
|
*/
|
||||||
|
insertToIndex(value: T, index: number): void {
|
||||||
|
let p = this.head
|
||||||
|
let pos = 0
|
||||||
|
const newNode = new LinkedListNode(value)
|
||||||
|
while (p !== null && pos !== index) {
|
||||||
|
p = p.next
|
||||||
|
pos++
|
||||||
|
}
|
||||||
|
if (p === null) return
|
||||||
|
newNode.next = p.next
|
||||||
|
p.next = newNode
|
||||||
|
newNode.prev = p
|
||||||
|
this.size++
|
||||||
|
}
|
||||||
|
|
||||||
|
insertToTail(value: T): void {
|
||||||
|
let p = this.last
|
||||||
|
const newNode = new LinkedListNode(value)
|
||||||
|
if (p === null) {
|
||||||
|
this.head = this.last = newNode
|
||||||
|
} else {
|
||||||
|
p.next = newNode
|
||||||
|
newNode.prev = p
|
||||||
|
this.last = newNode
|
||||||
|
}
|
||||||
|
|
||||||
|
this.size++
|
||||||
|
}
|
||||||
|
|
||||||
|
remove(value: T): boolean {
|
||||||
|
let p = this.head
|
||||||
|
while (p && p.item !== value) {
|
||||||
|
p = p.next
|
||||||
|
}
|
||||||
|
if (!p) return false
|
||||||
|
if (p.prev) {
|
||||||
|
p.prev.next = p.next
|
||||||
|
} else {
|
||||||
|
this.head = p.next
|
||||||
|
}
|
||||||
|
if (p.next) {
|
||||||
|
p.next.prev = p.prev
|
||||||
|
} else {
|
||||||
|
this.last = p.prev
|
||||||
|
}
|
||||||
|
this.size--
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
toString(): string {
|
||||||
|
let ret: string = ''
|
||||||
|
let p = this.head
|
||||||
|
while (p) {
|
||||||
|
ret = `${ret} ${p.item} `
|
||||||
|
p = p.next
|
||||||
|
}
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class LinkedListNode<T> {
|
||||||
|
item: T
|
||||||
|
next: LinkedListNode<T> | null
|
||||||
|
prev: LinkedListNode<T> | null
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
item: T,
|
||||||
|
next: LinkedListNode<T> | null = null,
|
||||||
|
prev: LinkedListNode<T> | null = null
|
||||||
|
) {
|
||||||
|
this.item = item
|
||||||
|
this.next = next
|
||||||
|
this.prev = prev
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const linkedList = new LinkedList()
|
||||||
|
linkedList.insertToHead('12')
|
||||||
|
linkedList.insertToHead('haha')
|
||||||
|
linkedList.insertToHead('www')
|
||||||
|
linkedList.insertToTail('zxc')
|
||||||
|
linkedList.insertToIndex('12ooo', 0)
|
||||||
|
linkedList.remove('12oooo')
|
||||||
|
console.log(linkedList.toString())
|
19
typescript/06_linkedlist/List.ts
Normal file
19
typescript/06_linkedlist/List.ts
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
interface List<T> {
|
||||||
|
insertToHead(value: T): void
|
||||||
|
|
||||||
|
findByValue(value: T): any
|
||||||
|
|
||||||
|
findByIndex(index: number): any
|
||||||
|
|
||||||
|
insertToIndex(value: T, index: number): void
|
||||||
|
|
||||||
|
remove(value: T): boolean
|
||||||
|
|
||||||
|
insertToHead(value: T): void
|
||||||
|
|
||||||
|
insertToTail(value: T): void
|
||||||
|
|
||||||
|
toString(): string
|
||||||
|
}
|
||||||
|
|
||||||
|
export default List
|
121
typescript/06_linkedlist/SingleLinkedList.ts
Normal file
121
typescript/06_linkedlist/SingleLinkedList.ts
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
/**
|
||||||
|
* 1)单链表的插入、删除、查找操作;
|
||||||
|
* 2)链表支持任意类型数据
|
||||||
|
*/
|
||||||
|
import List from './List'
|
||||||
|
|
||||||
|
class SingleLinkedList<T> implements List<T> {
|
||||||
|
// 哨兵头节点
|
||||||
|
private readonly head: SingleNode<T>
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.head = new SingleNode<any>(null)
|
||||||
|
}
|
||||||
|
|
||||||
|
public findByValue(value: T): SingleNode<T> | null {
|
||||||
|
let p = this.head
|
||||||
|
while (p.next != null) {
|
||||||
|
if (p.next.value === value) return p.next
|
||||||
|
p = p.next
|
||||||
|
}
|
||||||
|
return p.next
|
||||||
|
}
|
||||||
|
|
||||||
|
public findByIndex(index: number): SingleNode<T> | null {
|
||||||
|
let p = this.head
|
||||||
|
let pos = 0
|
||||||
|
while (p.next != null && pos !== index) {
|
||||||
|
p = p.next
|
||||||
|
pos++
|
||||||
|
}
|
||||||
|
return p.next
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 向指定的位置插入节点
|
||||||
|
* @param value
|
||||||
|
* @param index
|
||||||
|
*/
|
||||||
|
public insertToIndex(value: T, index: number): void {
|
||||||
|
const newNode = new SingleNode(value)
|
||||||
|
let p = this.head
|
||||||
|
let pos = 0
|
||||||
|
while (p.next != null && pos !== index) {
|
||||||
|
p = p.next
|
||||||
|
pos++
|
||||||
|
}
|
||||||
|
if (p.next == null) return
|
||||||
|
newNode.next = p.next.next
|
||||||
|
p.next.next = newNode
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据值去删除节点
|
||||||
|
* @param value 1 表示删除成功,0 表示删除失败
|
||||||
|
*/
|
||||||
|
public remove(value: T): boolean {
|
||||||
|
let p = this.head
|
||||||
|
while (p.next != null) {
|
||||||
|
if (p.next.value === value) break
|
||||||
|
p = p.next
|
||||||
|
}
|
||||||
|
if (p.next === null) return false
|
||||||
|
p.next = p.next.next
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
public insertToHead(value: T): void {
|
||||||
|
const newNode = new SingleNode(value, null)
|
||||||
|
this.insertNodeToHead(newNode)
|
||||||
|
}
|
||||||
|
|
||||||
|
public insertToTail(value: T): void {
|
||||||
|
const newNode = new SingleNode(value, null)
|
||||||
|
this.insertNodeToTail(newNode)
|
||||||
|
}
|
||||||
|
|
||||||
|
private insertNodeToHead(node: SingleNode<T>): void {
|
||||||
|
node.next = this.head.next
|
||||||
|
this.head.next = node
|
||||||
|
}
|
||||||
|
|
||||||
|
public toString(): string {
|
||||||
|
let ret: string = ''
|
||||||
|
let p = this.head
|
||||||
|
while (p.next != null) {
|
||||||
|
ret = `${ret} ${p.next.value} `
|
||||||
|
p = p.next
|
||||||
|
}
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 单链表的尾插入比较费时
|
||||||
|
* @param newNode 插入的新节点
|
||||||
|
*/
|
||||||
|
private insertNodeToTail(newNode: SingleNode<T>): void {
|
||||||
|
let p = this.head
|
||||||
|
while (p.next != null) {
|
||||||
|
p = p.next
|
||||||
|
}
|
||||||
|
p.next = newNode
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class SingleNode<T> {
|
||||||
|
public value: T
|
||||||
|
public next: SingleNode<T> | null
|
||||||
|
|
||||||
|
constructor(value: T, next: SingleNode<T> | null = null) {
|
||||||
|
this.value = value
|
||||||
|
this.next = next
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const singleLinkedList = new SingleLinkedList<string>()
|
||||||
|
singleLinkedList.insertToTail('god')
|
||||||
|
singleLinkedList.insertToTail('my')
|
||||||
|
// console.log(singleLinkedList.printLinkedList())
|
||||||
|
singleLinkedList.insertToIndex('haha', 1)
|
||||||
|
singleLinkedList.remove('ha1')
|
||||||
|
singleLinkedList.toString()
|
134
typescript/07_linkedlist/LinkedListAlog.ts
Normal file
134
typescript/07_linkedlist/LinkedListAlog.ts
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
/**
|
||||||
|
* 单链表的常见操作包括
|
||||||
|
* 链表反转
|
||||||
|
* 链表中环的检测
|
||||||
|
* 有序链表的合并
|
||||||
|
* 删除链表倒数第n个节点
|
||||||
|
* 链表中间节点
|
||||||
|
*/
|
||||||
|
class LinkedListAlog {
|
||||||
|
/**
|
||||||
|
* 反转链表,依次将节点插入到头部
|
||||||
|
* @param list
|
||||||
|
*/
|
||||||
|
public static reverse<T>(list: SingleNode<T>): SingleNode<T> | null {
|
||||||
|
let currentNode: SingleNode<T> | null = list
|
||||||
|
let prevNode = null
|
||||||
|
while (currentNode) {
|
||||||
|
const nextNode: SingleNode<T> | null = currentNode.next
|
||||||
|
currentNode.next = prevNode
|
||||||
|
prevNode = currentNode
|
||||||
|
currentNode = nextNode
|
||||||
|
}
|
||||||
|
return prevNode
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过快慢指针来检测是否为一个环
|
||||||
|
* @param list
|
||||||
|
*/
|
||||||
|
public static checkCircle<T>(list: SingleNode<T>): boolean {
|
||||||
|
if (!list) return false
|
||||||
|
let fast: SingleNode<T> | null = list.next
|
||||||
|
let slow: SingleNode<T> | null = list
|
||||||
|
while (fast && fast.next) {
|
||||||
|
fast = fast.next.next
|
||||||
|
slow = slow!!.next
|
||||||
|
if (fast === slow) return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 倒序删除节点
|
||||||
|
* @param list
|
||||||
|
* @param index
|
||||||
|
*/
|
||||||
|
public static removeFromEnd<T>(list: SingleNode<T>, index: number): SingleNode<T> | null {
|
||||||
|
// 如果是个环,就没必要找了
|
||||||
|
if (this.checkCircle(list)) return list
|
||||||
|
let newNode = this.reverse(list)
|
||||||
|
let preNode = null
|
||||||
|
let pos = 0
|
||||||
|
while (newNode && pos !== index) {
|
||||||
|
newNode = newNode.next
|
||||||
|
pos++
|
||||||
|
preNode = newNode
|
||||||
|
}
|
||||||
|
if (!newNode) return null
|
||||||
|
if (preNode) {
|
||||||
|
preNode.next = newNode.next
|
||||||
|
}
|
||||||
|
return this.reverse(newNode)
|
||||||
|
}
|
||||||
|
|
||||||
|
public static findMidNode<T>(list: SingleNode<T>): SingleNode<T> | null {
|
||||||
|
if (!list) return null
|
||||||
|
let fast = list.next
|
||||||
|
let slow = list
|
||||||
|
while (fast && fast.next) {
|
||||||
|
fast = fast.next.next
|
||||||
|
slow = slow.next!!
|
||||||
|
}
|
||||||
|
return slow
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 有序链表的合并,根据不同的值进行插入
|
||||||
|
* @param a
|
||||||
|
* @param b
|
||||||
|
*/
|
||||||
|
public static mergeSortedLists<T>(a: SingleNode<T>, b: SingleNode<T>): SingleNode<T> | null {
|
||||||
|
if (!a || !b) return a ? a : b
|
||||||
|
let p: SingleNode<T> | null = a
|
||||||
|
let q: SingleNode<T> | null = b
|
||||||
|
// 新链表的头部指针
|
||||||
|
let newList: SingleNode<T> | null = null
|
||||||
|
if (p.value < q.value) {
|
||||||
|
newList = p
|
||||||
|
p = p.next
|
||||||
|
} else {
|
||||||
|
newList = q
|
||||||
|
q = q.next
|
||||||
|
}
|
||||||
|
let currNode = newList
|
||||||
|
while (p && q) {
|
||||||
|
if (p.value < q.value) {
|
||||||
|
currNode.next = p
|
||||||
|
p = p.next
|
||||||
|
} else {
|
||||||
|
currNode.next = q
|
||||||
|
q = q.next
|
||||||
|
}
|
||||||
|
currNode = currNode.next
|
||||||
|
}
|
||||||
|
if (p) {
|
||||||
|
currNode.next = p
|
||||||
|
} else {
|
||||||
|
currNode.next = q
|
||||||
|
}
|
||||||
|
return newList
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class SingleNode<T> {
|
||||||
|
public value: T
|
||||||
|
public next: SingleNode<T> | null
|
||||||
|
|
||||||
|
constructor(value: T, next: SingleNode<T> | null = null) {
|
||||||
|
this.value = value
|
||||||
|
this.next = next
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const node1 = new SingleNode(1)
|
||||||
|
node1.next = new SingleNode(3)
|
||||||
|
node1.next.next = new SingleNode(5)
|
||||||
|
|
||||||
|
const node2 = new SingleNode(2)
|
||||||
|
node2.next = new SingleNode(7)
|
||||||
|
node2.next.next = new SingleNode(8)
|
||||||
|
node2.next.next.next = new SingleNode(10)
|
||||||
|
|
||||||
|
console.log(LinkedListAlog.findMidNode(node1))
|
Loading…
Reference in New Issue
Block a user