# 数据结构篇

js篇没有结束喔，只不过先复习一下数据结构吧

## 一、栈

• push 出栈
• pop 入栈
• peek 返回栈顶元素
• isEmpty 判空
• clear 清除栈中元素
• size 返回栈中元素个数

`````` class Stack {
constructor() {
this._count = 0 //可记录栈内元素长度也可以当做栈内指针
this._data = {} //用于存储栈内数据
}
isEmpty() {
return this._count === 0
}
push(value) {
this._data[this._count++] = value
}
pop() {
if (this.isEmpty()) {
return undefined
}
this._count--;

let res = this._data[this._count]
delete this._data[this._count]

return res
}
peek() {
return this._data[this._count - 1]
}
size() {
return this._count
}
clean() {
this._data = {}
this._count = 0
}

}

const stack = new Stack()
stack.push(5)
stack.push(8)
stack.push(10)

console.log(stack.peek())
console.log(stack.pop())
console.log(stack)
console.log(stack.size())

## 二、队列

### 2.1 普通队列

• enqueue（e）向队尾添加元素
• dequeue() 从对头出去一个元素
• peek（）返回队列中的第一个元素，也即：返回对头元素
• isEmpty（）判空
• size（）返回队列中元素的个数
• clear() 清空

``````        class Queue {
constructor() {
this._data = {}
this._count = 0
this._first = 0 //队头指针
}
isEmpty() {
return this._count === this._first
}
enqueue(value) {
this._data[this._count++] = value
}
dequeue() {
if (this.isEmpty()) {
return undefined
}
let res = this._data[this._first]
delete this._data[this._first]
this._first++;
return res

}
peek() {
if (this.isEmpty()) {
return undefined
}
return this._data[this._first]
}
size() {
return this._count - this._first
}
clean() {
this._data = {}
this._count = 0
this._first = 0
}
}
const q = new Queue()
q.enqueue(1)
q.enqueue(2)
q.enqueue(3)
q.enqueue(4)
console.log(q)
console.log(q.dequeue())
console.log(q.peek())
console.log(q.size())

### 2.2 双端队列

• isEmpty
• clear
• size
• removeFront 队头移出元素
• removeBack 队尾移出元素
• peekFront 取队头元素
• peekBack 取队尾元素

``````        class Deque {
constructor() {
this._data = {}
this._count = 0
this._first = 0
}
isEmpty() {
return this._count === this._first
}
//队尾进
enqueue(value) {
this._data[this._count++] = value
}
//队头出
dequeue() {
if (this.isEmpty()) {
return undefined
}
let res = this._data[this._first]
delete this._data[this._first]
this._first++;
return res

}
//队头进
if (this.isEmpty()) {
this.enqueue(value)
}
this._data[--this._first] = value
}
//队尾出
removeBack() {
if (this.isEmpty()) {
return undefined
}
this._count--
let res = this._data[this._count]
delete this._data[this._count]
return res
}
}

const d = new Deque()
d.enqueue(1)
d.enqueue(2)

//    此时队列的数据从头到尾应是3,1,2
//    调用队头出应是3
console.log(d.dequeue())

// 再掉队尾出应是2
console.log(d.removeBack())

### 2.3 循环队列

• isEmpty 判空
• isFull 判满
• put（e）队尾插
• poll（）队头取

``````        class SqQueue {
constructor() {
this._data = {}
this._front = 1 //头部指针
this._rear = 1 //尾部指针
this.MAX = 5
}
isEmpty() {
return this._front === this._rear
}
isFull() {
return (this._rear + 1) % this.MAX === this._front
}
put(value) {
if (this.isFull()) {
return 'FULL'
}
this._data[this._rear] = value

// 指针后移的同时也要考虑它是个环不能允许它超过最大值
//即如果此时它在5的位置，假设此时头在2或3等位置未满，那么尾指针后移应该1而不能是6
this._rear = (this._rear + 1) % this.MAX
}
poll() {
if (this.isEmpty()) {
return undefined
}
let res = this._data[this._front]
delete this._data[this._front]
this._front = (this._front + 1) % this.MAX
return res
}
}
let sq = new SqQueue()
sq.put(1)
sq.put(2)
sq.put(3)
sq.put(4)
console.log(sq.poll()) //1
console.log(sq.poll()) //2
console.log(sq.poll()) //3
sq.put(2)
sq.put(3)
sq.put(4)

// 此时从队尾 - > 队头应是4, 3, 2, 4
console.log(sq.poll()) //4
console.log(sq.poll()) //2
console.log(sq.poll()) //3
console.log(sq.poll()) //4

## 三、链表

### 3.1 单链表

``````  class LNode {
constructor(value) {
this._value = value
this._next = null //指针域
}
}

``````  //单链表类
constructor() {
this._count = 0
}
}

• push(element) 向尾部插一个
• insert(element, position) 向指定位置插一个
• getElementAt(index) 获取指定位置的元素
• remove(element) 移出元素
• indexOf(element) 返回该元素的位置
• removeAt(position) 移出指定位置的元素
• isEmpty() 判空
• size() 链表长度

#### push

`````` push(value) {
const node = new LNode(value)

if (current === null) {
} else {
// 不是空，顺着链条向下找,最后一个节点的指针域为空
while (current._next) {
current = current._next
}
current._next = node
}

this._count++
}

//最后的测试代码

l.push(1)
l.push(2)
l.push(3)
l.push(4)
console.log(l)

#### getElementAt及insert

``````  // 获取指定位置的节点
getElementAt(index) {
if (!(index >= 0 && index < this._count)) return undefined
for (let i = 0; i < index; i++) {
current = current._next
}
return current

}

// 在任意位置插入
insert(value, index) {
if (!(index >= 0 && index <= this._count)) return undefined

const node = new LNode(value)
// index==0
if (index === 0) {
} else {
// 还是先找要操作的前一位置
let pre = this.getElementAt(index - 1)
let current = pre._next

pre._next = node
node._next = current

}
this._count++;

}

//最后的测试代码
l.push(1)
l.push(2)
l.push(3)
l.push(4)
l.insert(5, 1)
console.log(l)

#### removeAt

``````// 移出指定位置的节点
removeAt(index) {
if (!(index >= 0 && index < this._count)) return undefined
if (index === 0) {
} else {
let previous;
for (let i = 0; i < index - 1; i++) {
current = current._next
}
previous = current //指向要删除节点的前一个
current = current._next //指向当前要删除节点
previous._next = current._next

return current._value
}
this._count--

}
//最后的测试代码
l.push(1)
l.push(2)
l.push(3)
l.push(4)
l.insert(5, 1)
l.removeAt(1)
console.log(l)

#### indexOf

`````` //返回指定节点元素的位置
indexOf(value) {
//遍历一下链表即可
for (let i = 0; i < this._count && current != null; i++) {
if (current._value === value) {
return i
} else {
current = current._next
}
}
}

//最后的测试代码
l.push(1)
l.push(2)
l.push(3)
l.push(4)
l.insert(5, 1)
l.removeAt(1)
console.log(l.indexOf(3));
console.log(l)

#### remove

``````  // 移出一个指定元素的节点
remove(value) {
let index = this.indexOf(value)
this.removeAt(index)
}

#### isEmpty及size()

`````` //链表长度
size() {
return this._count
}

// 判空
isEmpty() {
return this.size() === 0
}

### 3.2 双向链表

``````         class Node {
constructor(value) {
this.value = value
this.pre = null //前驱指针
this.next = null //后继指针
}
}

constructor() {
this.count = 0
this.q = null //指向尾节点
}

//根据位置返节点
getElementAt(index) {
if (index < 0 || index >= this.count) return undefined
for (let i = 0; i < index; i++) {
current = current.next
}
return current
}

//指定位置插入
insert(value, index) {
if (index < 0 || index > this.count) return false
const node = new Node(value)

// 解析考虑三种情况，在头、在尾、在中间

//头
if (index === 0) {
// 又分为链表开始为空与不空
this.q = node
} else {
}

}

// 尾部
else if (index === this.count) {
this.q.next = node
node.pre = this.q

// 再让q指回尾部
this.q = node
}
// 中间
else {
// 和单链表的操作一样，找到要操作的前一个
let pre = this.getElementAt(index - 1)
let current = pre.next

pre.next = node
node.next = current

node.pre = pre
current.pre = node
}
this.count++

}

// 指定位置移出
removeAt(index) {
if (index < 0 || index >= this.count)
return false

// 处理情况也分为在头在尾在中间

// 头
if (index === 0) {

// 不能马上将前驱指针设为null，不能保证有没有第二个节点
if (this.count === 1) {
this.q = null
} else {

}
}

//尾
else if (index == this.count - 1) {
let current = this.q.pre
current.next = null
this.q = current
}

// 中间
else {
// 还是先找它的前一个
let preNode = getElementAt(index - 1)
let current = preNode.next

preNode.next = current.next
current.next.pre = preNode
}

this.count--

}
}

test.insert(1, 0)
test.insert(2, 1)
test.insert(3, 2)
test.insert(4, 3)
test.removeAt(3)
console.log(test)

### 3.3 循环链表

#### insert

`````` class Node {
constructor(value) {
this.value = value
this.pre = null //前驱指针
this.next = null //后继指针
}
}

constructor() {
this.count = 0
this.q = null //指向尾节点
}
//根据位置返节点
getElementAt(index) {
if (index < 0 || index >= this.count) return undefined
for (let i = 0; i < index; i++) {
current = current.next
}
return current
}

insert(value, index) {
if (index < 0 || index > this.count) return false
const node = new Node(value)

// 头
if (index === 0) {
this.q = node

node.pre = node
node.next = node
} else {

}
}
// 尾
else if (index == this.count) {
this.q.next = node
node.pre = this.q
this.q = node
}
// 中间
else {
// 和原来一样
let preNode = this.getElementAt(index - 1)
let current = preNode.next

preNode.next = node
node.pre = preNode
current.pre = node
node.next = current

}
this.count++

}
}
test.insert(1, 0)
test.insert(2, 1)
test.insert(3, 2)

console.log(test)

1-2-3-1-2-3，最后的指针又指回了第一个节点实现循环

#### removeAt

``````remove(index) {
if (index < 0 || index > this.count - 1) return false

// 头
if (index === 0) {

// 又分只有一个元素和多个
if (this.count === 1) {
this.q = null
} else {
}

}
// 尾
else if (index === this.count - 1) {
let current = this.q.pre
this.q = current
}
// 中间
else {
// 和原来一样，取到前一个
let preNode = this.getElementAt(index - 1)
let current = preNode.next

preNode.next = current.next
current.next.pre = preNode

}
this.count--

}

//最后的测试

## 四、集合、字典、哈希表

### 4.1 集合

#### 集合的实现

• delete(element)：从集合移除一个元素。
• has(element)：如果元素在集合中，返回 true，否则返回 false。
• clear()：移除集合中的所有元素。
• size()：返回集合所包含元素的数量。它与数组的 length 属性类似。
• values()：返回一个包含集合中所有值（元素）的数组

`````` class Set {
constructor() {
this.container = {}
}
has(value) {
return value in this.container
}
if (this.has(value)) return false
this.container[value] = value
}
delete(value) {
if (!this.has(value)) return false
delete this.container[value]
}
clear() {
this.container = {}
}
size() {
return Object.keys(this.container).length
}
value(){
return Object.values(this.container)
}
}

#### 集合的运算

• 并集
• 交集
• 差集
• 子集
##### 并集

``````        function union(set01, set02) {
const newSet = new Set()
return newSet
}

##### 交集

``````function intersection(set01, set02) {
const newSet = new Set()
set01.value().forEach(item => {
if (set02.has(item)) {
}
})
return newSet
}

##### 差集A-B

``````        function difference(set01, set02) {
const newSet = new Set()
set01.value().forEach(item => {
if (!set02.has(item)) {
}
})
}

##### 子集

``````       function isSubsetOf(a, b) {
if (a.size() > b.size()) return false

let flag = a.value().every(item => {
return b.has(item)
})

return flag
}

### 4.2 字典

• set(key,value)：向字典中添加新元素。如果 key 已经存在，那么已存在的 value 会被新的值覆盖
• remove(key)：通过使用键作为参数来从字典中移除键值对应的数据值。
• get(key)：通过以键值作为参数查找特定的数值并返回。
• clear()：删除该字典中的所有值。
• isEmpty()：在 size 等于零的时候返回 true，否则返回 false。
• keys()：将字典所包含的所有键名以数组形式返回。
• values()：将字典所包含的所有数值以数组形式返回。
• keyValues()：将字典中所有[键，值]对返回。
• forEach(callbackFn)：迭代字典中所有的键值对。 callbackFn 有两个参数： key 和value。

``````        class Dictionary {
constructor() {
this.container = {}
}

// 根据指定键，判字典中有无
return key in this.container
}
set(key, value) {
if (key !== null && value !== null) {
this.container[key] = value
}
}
remove(key) {
delete this.container[key]

}
}
get(key) {
return this.container[key]
} else {
return undefined
}
}
keys() {
return Object.keys(this.container)
}
values() {
return Object.values(this.container)
}
keyValues() {
return Object.entries(this.container)
}
size() {
return this.keys().length
}
isEmpty() {
return this.size() === 0
}
clear() {
this.container = {}
}

forEach(fn) {
const keys = this.keys()

keys.forEach(item => fn(item, this.container[item]))
}
}

const dic = new Dictionary();
dic.set(1, "a");
dic.set(2, "b");
dic.set(3, "c");
dic.set(4, "d");
dic.set(5, "e");
dic.remove(2);
console.log(dic.get(3));
console.log(dic.keyValues());
console.log(dic.keys());
dic.forEach((key, val) => {
console.log(`key:\${key} val:\${val}`);

})

### 4.3 哈希表

#### djb2HashCode(目前最好用的哈希函数)

``````      function djb2HashCode(key) {
const tableKey = this.toStrFn(key);
let hash = 5381;
for (let i = 0; i < tableKey.length; i++) {
hash = (hash * 33) + tableKey.charCodeAt(i);
}
return hash % 1013;
}

#### loseloseHashCode(好理解，它只是将字符串的ascii码与37取余)

``````        function loseloseHashCode(key) {
if (typeof key === 'number') {
return key;
}
let hash = 0;
for (let i = 0; i < key.length; i++) {
hash += tableKey.charCodeAt(i);
}
return hash % 37;
}

#### 哈希表的基本实现

`````` class HashTable {
constructor() {
this.table = {}
}

// 要使用的散列函数
_loseloseHashCode(key) {
if (typeof key === "number") {
return key
} else {
let hash = 0;
for (let i = 0; i < key.length; i++) {
hash = hash + key.charCodeAt(i);
}
return hash % 37;
}
}
put(key, value) {
if (key != null && value != null) {
let position = this._loseloseHashCode(key)
this.table[position] = value
}
}
get(key) {
let position = this._loseloseHashCode(key)
if (this.table[position]) {
return this.table[position]
} else {
return undefined
}
}
remove(key) {
let position = this._loseloseHashCode(key)
if (this.table[position]) {
delete this.table[position]
return true
} else {
return false
}
}
}

#### hash表完善之分离链接

``````        // 节点类
class LNode {
constructor(value) {
this._value = value
this._next = null //指针域
}
}

//单链表类
constructor() {
this._count = 0
}
push(value) {
const node = new LNode(value)

if (current === null) {
} else {
// 不是空，顺着链条向下找,最后一个节点的指针域为空
while (current._next) {
current = current._next
}
current._next = node
}

this._count++
}

// 移出指定位置的节点
removeAt(index) {
if (!(index >= 0 && index < this._count)) return undefined
if (index === 0) {
}
let previous;
for (let i = 0; i < index - 1; i++) {
current = current._next
}
previous = current //指向要删除节点的前一个
current = current._next //指向当前要删除节点
previous._next = current._next

this._count--;
return current._value

}

// 获取指定位置的节点
getElementAt(index) {
if (!(index >= 0 && index < this._count)) return undefined
for (let i = 0; i < index; i++) {
current = current._next
}
return current

}

// 在任意位置插入
insert(value, index) {
if (!(index >= 0 && index < this._count)) return undefined

const node = new LNode(value)
// index==0
if (index === 0) {
} else {
// 还是先找要操作的前一位置
let pre = this.getElementAt(index - 1)
let current = pre._next

pre._next = node
node._next = current

}
this._count++;

}

//返回指定节点元素的位置
indexOf(value) {
//遍历一下链表即可
for (let i = 0; i < this._count && current != null; i++) {
if (current._value === value) {
return i
} else {
current = current._next
}
}
}

// 移出一个指定元素的节点
remove(value) {
let index = this.indexOf(value)
this.removeAt(index)
}

//链表长度
size() {
return this._count
}

// 判空
isEmpty() {
return this.size === 0
}

}

``````  class Node {
constructor(key, value) {
this.key = key
this.value = value
}
}
class HashTable {
constructor() {
this.table = {}
}

// 要使用的散列函数
_loseloseHashCode(key) {
if (typeof key === "number") {
return key
} else {
let hash = 0;
for (let i = 0; i < key.length; i++) {
hash = hash + key.charCodeAt(i);
}
return hash % 37;
}
}
put(key, value) {
if (key != null && value != null) {
let position = this._loseloseHashCode(key)
// 事先判断一下此位置是否有数据
if (!this.table[position]) {
}
this.table[position].push(new Node(key, value))
}
}
get(key) {
let position = this._loseloseHashCode(key)
if (this.table[position]) {

while (current) {
if (current._value.key === key) {
return current._value.value
}
current = current.next
}
//没找到
return undefined
} else {
return undefined
}
}
remove(key) {
let position = this._loseloseHashCode(key)
if (this.table[position]) {

while (current) {
if (current._value.key === key) {
this.table[position].remove(current._value)

// 删除完如此时链表空了则删除它
if (this.table[position].isEmpty()) {
delete this.table[position]
}
return true
}
current = current._next
}
// 在链表中没有找到
return false

} else {
return false
}
}
}

const h = new HashTable()
h.put('name', 'gongxiaobai')
h.put('name', 'zhangsan')
h.put('age', '18')
h.remove('age')
console.log(h)
console.log(h.get('name'))

#### hash表完善之线性探查

``````  class Node {
constructor(key, val) {
this.key = key
this.val = val
}
}
class LineHashTable {
constructor() {
this.table = {}
}

// 先创建散列函数
_loseloseHashCode(key) {
if (typeof key === "number") {
return key
} else {
let hash = 0
for (let i = 0; i < key.length; i++) {
hash = hash + key.charCodeAt(i)
}
return hash % 37
}
}

// 新增一条到散列表
put(key, val) {
if (key != null && val != null) {
const position = this._loseloseHashCode(key);
if (this.table[position] == null) {
// 为空放入节点
this.table[position] = new Node(key, val);
} else {
// 向下找空的储存空间
let index = position + 1;
while (this.table[index]) {
index++;
}
this.table[index] = new Node(key, val)
}
return true
}
return false
}
// 取值
get(key) {
let position = this._loseloseHashCode(key)

//    先直接到lost函数所能快速定位的地方
if (this.table[position] != null) {
// 再判是不是我们要的值
if (this.table[position].key === key) {
return this.table[position].val
}
// 不是则需要在此地的基础上向下寻找了
let index = position + 1
while (this.table[index] != null && this.table[index].key != key) {
index++
}
// 上面出来了有两种可能
// 1.找到目标
// 2.有一个空的地址
if (this.table[index].key === key) {
return this.table[index].val
} else {
return undefined
}

}
return undefined
}

// 移出值
remove(key) {
const position = this._loseloseHashCode(key);
if (this.table[position] != null) {
// 判此时这个位置上的使我们要的吗
if (this.table[position].key === key) {
delete this.table[position]
// 修复下面的位置
this._move(key, position)
return true
} else {
let index = position + 1
while (this.table[index] != null && this.table[index].key !== key) {
index++
}
if (this.table[index].key === key) {
delete this.table[index]

// 修复下面的位置
this._move(key, index)
return true
} else {
return false
}
}

}
return false

}

//难点
_move(key, removedPosition) {
let hash = this._loseloseHashCode(key)
let index = removedPosition + 1
while (this.table[index] != null) {

let posHash = this._loseloseHashCode(this.table[index].key)
// 如果当前元素的 hash 值小于或等于原始的 hash 值（行{5}）或者当前元素的 hash 值小于或等于 removedPosition（也就是上一个被移除 key 的 hash 值），表示我们需要将当前元素移动至 removedPosition 的位置
if (posHash <= hash || posHash <= removedPosition) {
this.table[removedPosition] = this.table[index]
delete this.table[index]
removedPosition = index
}
index++
}
}
}
const h = new LineHashTable()
h.put('name', 'gongxiaobai')
h.put('name', 'zhangsan')
h.put('age', '18')
h.remove('age')
console.log(h)
console.log(h.get('name'))