一、链表
1.定义
链表: 每个元素由一个存储元素本身的结点和指向下一个元素的引用(指针)构成。
线性表: 0个或n个数据元素的有限序列。
物理存储结构:
顺序存储:用一段连续的存储单元依次存储线性表的数据元素。
链式存储:内存地址可以是连续的也可以是不连续的,用指针来存放数据元素的地址。
2.实现
// 链点类
class Node {
constructor(element) {
this.element = element
this.next = null
}
}
// 链表
class LikedList {
constructor() {
// 链表头
this.head = null
// 链表的长度
this.length = 0
}
// 链表的尾部添加元素
append(element) {
// 创建结点
let node = new Node(element)
// 链表为空
if (this.length === 0) {
this.head = node
}
else {
// 通过head找到其他节点
let current = this.head
// 遍历,看是不是最后一项
while (current.next) {
current = current.next
}
current.next = node
}
// length加一
this.length += 1
}
// 获取链表的头
getHead() {
return this.head
}
// toString方法
toString() {
let current = this.head
let linkString = ''
while (current) {
linkString += ',' + current.element
current = current.next
}
// 返回最终结果
return linkString.slice(1)
}
// 在任意位置插入元素
insert(element, position) {
// 位置不能为负数
if (position < 0 || position >= this.length) {
return false
}
let index = 0
let current = this.head
let prev = null
let node = new Node(element)
// 判断插入的是不是第一个
if (position === 0) {
node.next = this.head
this.head = node
} else {
while (index < position) {
prev = current
current = current.next
index++
}
node.next = current
prev.next = node
}
this.length += 1
return true
}
// 获取对应位置的元素
get(position) {
if (position < 0 || position >= this.length) {
return false
}
let current = this.head
let index = 0
while (index < position) {
current = current.next
index++
}
return current.element
}
// 根据元素的位置和删除结点
removeAt(position) {
if (position < 0 || position >= this.length) {
return false
}
let index = 0
let current = this.head
let privious = null
if (position === 0) {
this.head = this.head.next
}
else {
while (index < position) {
privious = current
current = current.next
index++
}
}
privious.next = current.next
this.length--
return current.element
}
}
const likedList = new LikedList()
likedList.append(1)
likedList.append(2)
likedList.append(3)
likedList.append(4)
console.log(likedList)
console.log(likedList.toString())
likedList.removeAt(2)
console.log(likedList.toString())
/* 结果:
LikedList {
head: Node { element: 1, next: Node { element: 2, next: [Node] } },
length: 4
}
1,2,3,4
1,2,4
*/
二、原型链
原型链: js每个对象包括原型对象都有一个内置的_proto_属性指向它的原型对象,及prorotype属性。
- 所有的引用类型(数组,函数,对象)可以自由的扩展属性(null除外)
- 所有的引用类型都有一个_proto_属性(隐式原型,它是一个普通的对象)
- 所有的函数都有一个prototype属性(显示原型,它也是一个普通对象)
- 所有的引用类型的_proto_属性指向它的构造函数的prototype属性
- 当试图得到一个对象的属性是,如果这个对象不存在这个属性,那么就会去_proto_属性寻找。
例子:
function Teacher(name, hobby) {
this.name = name
this.hobby = hobby
this.say = () => {
console.log('teacher函数')
}
}
function TianTian() {
}
TianTian.prototype = new Teacher('lizhi', '睡觉')
var tiantian = new TianTian()
tiantian.say()
三、哈希表(hash)
hash:一般翻译为散列,是把任意长度的输入通过散列算法变换成固定长度的输出,该输出的值就是散列值。这种转换是一种压缩映射,映射表达的是一一对应的关系,即散射值的空间通常会小于输入的空间。
哈希算法不能从结果去推算出输入,哈希算法是不可逆的.
1.定义
哈希表: 将字符串name转换成数组的所有,利用索引查询内容,提高查询速度。
哈希表的结构: 数组。与数组不同的是哈希表对于索引的一种转换。这种转换称为哈希函数。
最简单的哈希函数:就是把一个字符与它的ASCII码加在一起,再去模一个数字。
2.编码方式
哈希表是以键值对的形式存储的数据结构,键是经过散列函数计算的出来的,称为关键码,每一个键对应一个值。我们把关键码->值的形式存储数据的数组成为哈希表。
3.实现
class HashTable {
constructor() {
this.table = []
}
// 哈希函数
loseloseHashCode(key) {
let hash = ''
for (let i = 0; i < key.length; i++) {
hash += key[i].charCodeAt()
}
// 取模
return hash % 37
}
// 新增元素
put(key, value) {
const position = this.loseloseHashCode(key)
this.table[position] = value
}
// 移出元素
remove(key, value) {
const position = this.loseloseHashCode(key)
this.table[position] = undefined
}
// 获取元素
get(key) {
const position = this.loseloseHashCode(key)
return this.table[position]
}
}
var hashList = new HashTable()
hashList.put('abc', 'abc')
hashList.put('34', '34')
hashList.put('56', '56')
console.log(hashList)
console.log(hashList.get('abc'))
/* 结果:
HashTable {
table: [
<9 empty items>,
'34',
<16 empty items>,
'56',
<1 empty item>,
'abc'
]
}
abc
*/
4.优缺点
优点:可以提供非常快的插入、删除、查找操作。
缺点:哈希表会出现覆盖的情况,不能完全避免。
5.解决冲突的方法
- 链地址法:数组存储的不是实际的值,而是存储一个链表,该链表用来放实际的数据
- 开放地址法:
1.线性探测法
2.二次探测
3.再哈希法