头图

字典

字典是一种以键-值对形式存储数据的数据结构,JavaScript的Object类就是以字典的形式设计的。下面用代码实现字典类以及相关操作方法

Dictionary类

datastore为数据集

class Dictionary{
  datastore=[]
  constructor(){
  }
}

add()添加键值对

add(key, value) {
    this.datastore[key]=value
  }

get()得到键的值

get(key) {
    return this.datastore[key]
  }

remove()移除元素

remove(key) {
    delete this.datastore[key]
  }

showAll()打印全部信息

showAll() {
    for(let key in this.datastore){
      console.log(`key=>${this.datastore[key]}`)
    }
  }

clear()清空操作

clear() {
    for(let key in this.datastore){
     delete this.datastore[key]
    }
  }

完整代码

class Dictionary {
    datastore = []
    constructor() {

    }
    add(key, value) {
        this.datastore[key] = value
    }
    find(key) {
        return this.datastore[key]
    }
    remove(key) {
        delete this.datastore[key]
    }
    showAll() {
        for (let key in this.datastore) {
            console.log(`key=>${this.datastore[key]}`)
        }
    }
    count() {
        let num = 0
        for (let key in this.datastore) {
            num++
        }
        return num
    }
    clear() {
        for (let key in this.datastore) {
            delete this.datastore[key]
        }
    }
}

散列

散列是一种常用的数据存储技术,散列后的数据可以快速地插入或取用。散列使用的数据结构叫做散列表。

整个散列过程其实就是两步。

  1. 在存储时,通过散列函数计算记录的散列地址,并按此散列地址存储该记录。
  2. 当查找记录时,我们通过同样的散列函数计算记录的散列地址,按此散列地址访问该记录。

实现HashTable类

class HashTable{
  table=new Array(137)
  constructor(){
  }
}

hash()散列函数使用霍纳算法计算键值

hash(string){
    const H = 37;
    var total = 0;
    for (var i = 0; i < string.length; ++i) {
        total += H * total + string.charCodeAt(i);
    }
    total = total % this.table.length;
    if (total < 0) {
         total += this.table.length-1;
    }
    return parseInt(total);
  }

put()用来将数据存入散列表

put(key,data){
    let pos = this.hash(key)
    this.table[pos]=data
  }

showDistro()示散列表中的数据

showDistro(){
    for(let index=0,length=this.table.length;index<length;index++){
      if(this.table[index]){
        console.log(`index:${this.table[index]}`)
      }
    }
  }

get()获取对应的键值

get(key) {
        return this.table[hash(key)]
    }

完整代码

class HashTable {
    table = new Array(137)
    constructor() {

    }
    hash(string) {
        const H = 37;
        var total = 0;
        for (var i = 0; i < string.length; ++i) {
            total += H * total + string.charCodeAt(i);
        }
        total = total % this.table.length;
        if (total < 0) {
            total += this.table.length - 1;
        }
        return parseInt(total);
    }
    showDistro() {
        for (let index = 0, length = this.table.length; index < length; index++) {
            if (this.table[index]) {
                console.log(`index:${this.table[index]}`)
            }
        }
    }
    put(key, data) {
        let pos = this.hash(key)
        this.table[pos] = data
    }
    get(key) {
        return this.table[hash(key)]
    }
}

碰撞处理

当散列函数对于多个输入产生同样的输出时,就产生了碰撞。处理两碰撞解决办法主要有两种:链地址法和开放定址法。

1.链地址法

链地址法是指实现散列表的底层数组中,每个数组元素又是一个新的数据结构,比如另一个数组,这样就能存储多个键了。使用这种技术,即使两个键散列后的值相同,依然被保存在同样的位置,只不过它们在第二个数组中的位置不一样罢了

image.png

构造散列表

class HashTableChains{
  table=new Array(137).fill([])
  constructor(){
  }
}

要重新定义put()和get()方法。put()方法将键值散列,散列后的值对应数组中的一个位置,先尝试将数据放到该位置上的数组中的第一个单元格,如果该单元格里已经有数据了,put()方法会搜索下一个位置,直到找到能放置数据的单元格,并把数据存储进去

  put(key,data){
    let pos = this.hash(key)
    let index=0
    if(this.table[pos][index]==undefined){
      this.table[pos][index]=data
    }else{
      while(this.table[pos][index]!=undefined){
        index++
      }
      this.table[pos][index]=key
      this.table[pos][index+1]=data
    }  
  }
  get(key){
    let hash = this.hash(key)
    let index=0
    if(this.table[hash][index]==key){
      return this.table[hash][index+1]
    }else{
      while(this.table[hash][index]!=key&&this.table[hash][index]!=undefined){
        index+=2
      }
      if(this.table[hash][index]!=undefined){
        return this.table[hash][index+1]
      } 
    }
    return undefined
  }

完整代码

class HashTableChains{
  table=new Array(137).fill([])
  constructor(){
  }
  hash(string){
    const H = 37;
    var total = 0; 
    for (var i = 0; i < string.length; ++i) {
        total += H * total + string.charCodeAt(i); 
    }
    total = total % this.table.length; 
    if (total < 0) {
         total += this.table.length-1;
    }
    return parseInt(total);
  }
  showDistro(){
    for(let index=0,length=this.table.length;index<length;index++){
      if(this.table[index][0] != undefined){
        console.log(`index:${this.table[index]}`)
      }
    }
  }
  put(key,data){
    let pos = this.hash(key)
    let index=0
    if(this.table[pos][index]==undefined){
      this.table[pos][index]=data
    }else{
      while(this.table[pos][index]!=undefined){
        index++
      }
      this.table[pos][index]=key
      this.table[pos][index+1]=data
    }
  }
  get(key){
    let hash = this.hash(key)
    let index=0
    if(this.table[hash][index]==key){
      return this.table[hash][index+1]
    }else{
      while(this.table[hash][index]!=key&&this.table[hash][index]!=undefined){
        index+=2
      }
      if(this.table[hash][index]!=undefined){
        return this.table[hash][index+1]
      }  
    }
    return undefined
  } 
}
2. 开放定址法

开放定址法隶属于一种更一般化的散列技术:开放寻址散列。当发生碰撞时,开放定址法查散列表中的下一个位置是否为空。如果为空,就将数据存入该位置;如果不为空,则继续检查下一个位置,直到找到一个空的位置为止。
线性探测法工作,需要重写put()和get()方法。

构造散列表

新添加一个属性values用来存散列表每个键对应的值

class HashTableLinear{
  table=new Array(137)
  values=new Array(137)
  constructor(){
  }
}

重写put()和get()方法

put(key,data){
    let pos = this.hash(key)
    if(this.table[pos]==undefined){
      this.table[pos]=key
      this.values[pos]=data
    }else{
      while(this.table[pos]!=undefined){
        pos++
      }
      this.table[pos]=key
      this.values[pos]=data
    }
    
  }
  get(key){
    let pos = this.hash(key)
    if(this.table[pos]==key){
      return this.values[pos]=data
    }else{
      while(this.table[pos]!=key&&this.table[pos]!=undefined){
        pos++
      }
      if(this.table[pos]!=undefined){
        return this.values[pos]=data
      }
     
    }
    return undefined
  }

完整代码

class HashTableLinear{
  table=new Array(137)
  values=new Array(137)
  constructor(){

  }
  hash(string){
    const H = 37;
    var total = 0; 
    for (var i = 0; i < string.length; ++i) {
        total += H * total + string.charCodeAt(i); 
    }
    total = total % this.table.length; 
    if (total < 0) {
         total += this.table.length-1;
    }
    return parseInt(total);
  }
  showDistro(){
    for(let index=0,length=this.table.length;index<length;index++){
      if(this.table[index]){
        console.log(`index:${this.table[index]}=>${this.values[index]}`)
      }
    }
  }
  put(key,data){
    let pos = this.hash(key)
    if(this.table[pos]==undefined){
      this.table[pos]=key
      this.values[pos]=data
    }else{
      while(this.table[pos]!=undefined){
        pos++
      }
      this.table[pos]=key
      this.values[pos]=data
    }
    
  }
  get(key){
    let pos = this.hash(key)
    if(this.table[pos]==key){
      return this.values[pos]=data
    }else{
      while(this.table[pos]!=key&&this.table[pos]!=undefined){
        pos++
      }
      if(this.table[pos]!=undefined){
        return this.values[pos]=data
      }
     
    }
    return undefined
  }
}

集合

集合是一种包含不同元素的数据结构。集合中的元素称为成员。集合的两个最重要特性是:首先,集合中的成员是无序的;其次,集合中不允许相同成员存在。当你想要创建一个数据结构,用来保存一些独一无二的元素时,集合就变得非常有用。

Set类的实现

class SetList{
  dataStore=[]
  constructor(){
  }
}

add()添加元素

add(ele) {
        if (this.dataStore.indexOf(ele) == -1) {
            this.dataStore.push(ele)
            return true
        } else {
            return false
        }

    }

remove()移除元素

remove(ele) {
        let position = this.dataStore.indexOf(ele)
        if (position != -1) {
            this.dataStore.splice(position, 1)
            return true
        } else {
            return false
        }
    }

size()返回数据量

  size() {
        return this.dataStore.length
    }

show() 展示数据集

show(){
    return this.dataStore
  }

contains(),该方法检查一个成员是否属于该集合

contains(ele) {
        return this.dataStore.indexOf(ele) != -1
    }

union() 方法执行并集操作

  union(set) {
        let unionSet = new SetList()
        this.dataStore.forEach(item => {
            unionSet.add(item)
        })
        set.dataStore.forEach(item => {
            unionSet.add(item)
        })
        return unionSet
    }

intersect() 方法求两个集合的交集

intersect() {
        let intersectSet = new SetList()
        this.dataStore.forEach(item => {
            if (set.contains(item)) {
                intersectSet.add(item)
            }
        })
        return intersectSet
    }

subset() 判断是否是目标集合的子集

subset(set) {
        if (set.size() < this.size()) {
            return false
        }
        this.dataStore.forEach(item => {
            if (!set.contains(item)) {
                return false;
            }
        })
        return true
    }

difference(),该方法返回一个新集合,该集合包含的是那些属于第一个集合但不属于第二个集合的成员。

difference(set) {
        let differencetSet = new SetList()
        this.dataStore.forEach(item => {
            if (!set.contains(item)) {
                differencetSet.add(item)
            }
        })
        return differencetSet
    }

完成代码

class SetList {
    dataStore = []
    constructor() {

    }
    add(ele) {
        if (this.dataStore.indexOf(ele) == -1) {
            this.dataStore.push(ele)
            return true
        } else {
            return false
        }

    }
    remove(ele) {
        let position = this.dataStore.indexOf(ele)
        if (position != -1) {
            this.dataStore.splice(position, 1)
            return true
        } else {
            return false
        }
    }
    size() {
        return this.dataStore.length
    }
    contains(ele) {
        return this.dataStore.indexOf(ele) != -1
    }
    union(set) {
        let unionSet = new SetList()
        this.dataStore.forEach(item => {
            unionSet.add(item)
        })
        set.dataStore.forEach(item => {
            unionSet.add(item)
        })
        return unionSet
    }
    intersect() {
        let intersectSet = new SetList()
        this.dataStore.forEach(item => {
            if (set.contains(item)) {
                intersectSet.add(item)
            }
        })
        return intersectSet
    }
    subset(set) {
        if (set.size() < this.size()) {
            return false
        }
        this.dataStore.forEach(item => {
            if (!set.contains(item)) {
                return false;
            }
        })
        return true
    }
    difference(set) {
        let differencetSet = new SetList()
        this.dataStore.forEach(item => {
            if (!set.contains(item)) {
                differencetSet.add(item)
            }
        })
        return differencetSet
    }
    show() {
        return this.dataStore
    }
}

麻路平
8 声望0 粉丝