Javascript常见数据结构四——集合、字典、哈希表
五、集合
1.创建集合结构
集合是由一组无序且唯一的数据组成
ES6 Set 结构就是集合,接下来我们基于Set数据结构进行讨论
功能需求分析:
add 新增集合元素
has 判断该元素是否存在于该集合
delete 删除指定集合元素
size 返回集合长度
clear 清空集合
let Set = (function (){
let symbol = Symbol()
return class {
constructor(arr) {
this[symbol] = []
if(Array.isArray(arr)){
arr.forEach(item=>{
if(!this[symbol].includes(item)){
this[symbol].push(item)
}
})
}
}
add(data){
if(!this[symbol].includes(data)){
this[symbol].push(data)
}
}
has(data){
return this[symbol].includes(data)
}
delete(data){
let index = this[symbol].indexOf(data)
if(index===-1)return
this[symbol].splice(index,1)
}
size(){
return this[symbol].length
}
clear(){
this[symbol]=[]
}
}
})()
2.并集、交集、差集、子集
并集 -- 将两个集合合并
function union(a,b){
return new Set([...a,...b])
}
// 交集 -- 找到两个集合相交的地方
function intersection(a,b){
let set = new Set()
for (const aElement of a) {
if(b.has(aElement)){
set.add(aElement)
}
}
return set
}
// 差集 找到两个集合不相交的数据
// a-b 顺序是有影响的 是用第二个数据去排除第一个数据里拥有的数据
function difference(a,b){
let set = new Set()
for (const aElement of a) {
if(!b.has(aElement)){
set.add(aElement)
}
}
return set
}
// 子集 -- 检测 b是不是 a 的子集
function subset(a,b){
for (const x of b) {
if(!a.has(x)){
return false
}
}
return true
}
六、字典
1.创建字典结构
字典是一种以(键值)的形式存储数据的数据结构,键用来查找对应的值,就像字典里面的每个字(键)都有对应的有他的解释(值),再比如电话簿,名字(键)对应电话(值)。
ES6 Map 数据结构就是一种字典
字典中的键可以是任意的数据类型
功能需求分析
设置数据 set
获取数据 get
删除数据 delete
是否存在 has
返回长度 size
// js对象
本身是不允许对象作为键值的 只允许 数字 字符串
所有的非字符串数字的 的 键值 会被强制转化为字符串
对象被转为字符串 [object Object]
// map
只要两个对象不是同一个 都可以 进行分开存储
map 存值的前提是 两个值不一样
原始值 键名相同的原始值 都会被覆盖
引用值 只要不是同一个地址 就不会存在覆盖的问题
如果参数是一个对象 直接返回undefined 因为 参数的引用是独立的
console.log(map.get({x:10}));// undefined
let Map = (function () {
const symbol = Symbol()
return class {
constructor() {
this[symbol] = []
}
// 清空字典
clear(){
this[symbol] = []
}
// 字典中删除某个数据
delete(data){
for (let i = 0, len = this[symbol].length; i < len; i++) {
let thisData = this[symbol][i]
let k = thisData[0]
if (k === data) {
return this[symbol].splice(i,1)
}
}
}
// 检测某个数据在字典中是否存在
has(data){
for (let i = 0, len = this[symbol].length; i < len; i++) {
let thisData = this[symbol][i]
let k = thisData[0]
if (k === data) {
return true
}
}
return false
}
// 返回字典的长度
size(){
return this[symbol].length
}
// 设置某个属性
set(key, value) {
// 避免重复定义
for (let i = 0, len = this[symbol].length; i < len; i++) {
let thisData = this[symbol][i]
let k = thisData[0]
if (k === key) {
thisData[1] = value
return
}
}
let arr = [key, value]
this[symbol].push(arr)
}
// 获取某个属性
get(key) {
for (let i = 0, len = this[symbol].length; i < len; i++) {
let thisData = this[symbol][i]
let k = thisData[0]
let v = thisData[1]
if (k === key) {
return v
}
}
}
// 打印所有key值
keys(){
let arr = []
this[symbol].forEach(([key,value])=>{
arr.push(key)
})
return arr
}
// 打印所有values
values(){
let arr = []
this[symbol].forEach(([key,value])=>{
arr.push(value)
})
return arr
}
}
})()
七、哈希表
1.创建哈希表结构
哈希表也叫散列表 ,也是一种基于键值对存储值的一种数据结构
与数组的区别在于,哈希表能够快速的定位值得位置,而不需要逐个遍历匹配
js对象 就具有哈希表结构的特性
创建一个简单的哈希表数据类型:
let Hash = (function () {
// 哈希函数
function HASH(key) {
// 通过算法 得到key值对应的下标值
let code = 0;
[...key].forEach(item => {
code += item.charCodeAt(0)
})
return code
}
const symbol = Symbol
return class {
constructor() {
this[symbol] = []
}
set(key,value) {
let hashCode = HASH(key)
console.log(hashCode)
this[symbol][hashCode] = value
}
get(key){
let hashCode = HASH(key)
return this[symbol][hashCode]
}
}
})()
当前哈希表存在两个明显的问题:
1. 数组太长 --- 数组利用率比较低 存了几个数据开辟了几百个空间
2. 下标重复率高 --- 哈希函数不合理
这个时候需要我们解决当前这两个比较严重的问题,此时 ,我做了如下修改
// 解决空间利用率低的问题 和 下标重复率高的问题
let Hash = (function () {
// 哈希函数
function HASH(key) {
// 通过算法 得到key值对应的下标值
let code = 0;
[...key].forEach(item => {
code += item.charCodeAt(0)
})
// 解决数组利用率过大问题
// 使用除法和减法效果都不好
// 可以采用求模运算 最好是质数
return code % 13
}
const symbol = Symbol
return class {
constructor() {
this[symbol] = []
}
set(key, value) {
let hashCode = HASH(key)
// let i = 1
// 进行线性向下探索存储
while (this[symbol][hashCode] !== undefined) {
// 说明已经存在对应的hash
hashCode = (hashCode + 1) % 13
// 以下情况适用于范围比较大的线性探索
/*hashCode += i **2
i++*/
}
this[symbol][hashCode] = [key,value]
}
get(key) {
let hashCode = HASH(key)
// 不存在对应的code
if(!this[symbol][hashCode]){
return undefined
}
// 存在就判断对应的key值等不等于 不等于 就继续探索
while(this[symbol][hashCode][0]!==key){
hashCode = (hashCode + 1) %13
// 如果 hash对应的数据 不存在
if(!this[symbol][hashCode]){
return undefined
}
}
return this[symbol][hashCode]
}
}
})()