JS版数据结构之 链表、原型链、哈希表

一、链表

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属性。

  1. 所有的引用类型(数组,函数,对象)可以自由的扩展属性(null除外)
  2. 所有的引用类型都有一个_proto_属性(隐式原型,它是一个普通的对象)
  3. 所有的函数都有一个prototype属性(显示原型,它也是一个普通对象)
  4. 所有的引用类型的_proto_属性指向它的构造函数的prototype属性
  5. 当试图得到一个对象的属性是,如果这个对象不存在这个属性,那么就会去_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.再哈希法

猜你喜欢

转载自blog.csdn.net/ladream/article/details/119856978
今日推荐