澳门网络娱乐游戏平台-澳门电子游戏娱乐网址-官方直营

最新赌博的网址大全前端学数据构造之字典和散列表

前方的话

  集合、字典和散列表能够积累不另行的值。在聚集中,大家感兴趣的是各类值小编,并把它看作重中之重元素。在字典中,我们用[键,值]的情势来储存数据。在散列表中也是相仿(也是以[键,值]没错情势来囤积数据)。不过三种数据布局的完成格局略有分化,本文将详细介绍字典和散列表那三种数据构造

 

而外聚焦之外,字典和散列表也足以用来存储唯风流倜傥值(不另行的值)。在聚集中,大家感兴趣的是种种值小编,并把它看做非常重要元素。在字典中,大家用[键,值]的样式来囤积数据,个中键名是用来查询特定成分的。字典也称作映射,即ES6中定义的Map类。

字典

  会集表示生龙活虎组互不相近的因素(不重复的要素)。在字典中,存款和储蓄的是[键,值]最新赌博的网址大全,对,在那之中键名是用来查询特定成分的。字典和聚焦很相通,集结以[值,值]的样式积累成分,字典则是以[键,值]的款式来积存元素。字典也称作映射

【创造字典】

  与Set类常常,ECMAScript 6雷同包涵了三个Map类的兑现,即我们所说的字典

  上边将在完毕的类正是以ECMAScript 6中Map类的落到实处为根底的。它和Set类很相似(但不相同于存款和储蓄[值,值]没有错款式,大家将在存款和储蓄的是[键,值]对)

  那是大家的Dictionary类的骨架:

function Dictionary() {
    var items = {};
}

  与Set类相仿,我们就要五个Object的实例并不是数组中贮存成分。 然后,大家必要声Bellamy(Bellamy卡塔尔国些辉映/字典所能使用的法子

set(key,value):向字典中添加新元素。
remove(key):通过使用键值来从字典中移除键值对应的数据值。
has(key):如果某个键值存在于这个字典中,则返回true,反之则返回false。
get(key):通过键值查找特定的数值并返回。
clear():将这个字典中的所有元素全部删除。
size():返回字典所包含元素的数量。与数组的length属性类似。
keys():将字典所包含的所有键名以数组形式返回。
values():将字典所包含的所有数值以数组形式返回。

【has】

  首先来贯彻has(key卡塔尔(قطر‎方法。之所以要先完毕那些法子,是因为它会被set和remove等任何情势调用。那个点子的落实和前边在Set类中的完毕是相符的。使用JavaScript中的in操作符来证实一个key是不是是items对象的多个属性。能够透过如下代码来贯彻:

this.has = function(key) { 
  return key in items;
}

【set】

  该情势选取贰个key和三个value作为参数。大家直接将value设为items对象的key属性的值。它能够用来给字典增加四个新的值,可能用于更新三个本来就有的值

this.set = function(key, value) {
  items[key] = value; //{1}
}

【remove】

  它和Set类中的remove方法很相近,唯大器晚成的不一样点在于我们将先物色key(实际不是value),然后大家得以动用JavaScript的delete操作符来从items对象中移除key属性

this.remove = function(key) { 
  if (this.has(key)) {
    delete items[key];
    return true;
  }
  return false;
}

【get】

  get方法首先会注明我们想要检索的值是或不是留存(通过寻觅key值),假如存在,将重返该值, 反之将回来叁个undefined值

this.get = function(key) {
  return this.has(key) ? items[key] : undefined;
};

【values】

  首先,大家遍历items对象的持有属性值(行{1})。为了显著值存在,大家利用has函数来注脚key确实存在,然后将它的值插足values数组(行{2})。最终,大家就会回去全体找到的值。这几个格局以数组的花样重返字典中所有values实例的值:

this.values = function() { 
  var values = {};
  for (var k in items) { //{1} 
    if (this.has(k)) {
      values.push(items[k]); //{2}
    }
  }
  return values;
};

澳门博彩排名,【clear】

    this.clear = function(){
        items = {};
    };

【size】

    this.size = function(){
        return Object.keys(items).length;
    };

【keys】

  keys方法重临在Dictionary类中持有用于标记值的键名。要抽出八个JavaScript对象中有所的键名,能够把那么些指标作为参数字传送入Object类的keys方法,如下:

this.keys = function() {
 return Object.keys(items);
}; 

【items】

  上边来验证items属性的输出值。大家能够实现一个回到items变量的主意,叫作getItems:

this.getItems = function() {
 return items;
} 

【完整代码】

  Dictionary类的欧洲经济共同体代码如下所示

function Dictionary(){

    var items = {};

    this.set = function(key, value){
        items[key] = value; //{1}
    };

    this.delete = function(key){
        if (this.has(key)){
            delete items[key];
            return true;
        }
        return false;
    };

    this.has = function(key){
        return items.hasOwnProperty(key);
        //return value in items;
    };

    this.get = function(key) {
        return this.has(key) ? items[key] : undefined;
    };

    this.clear = function(){
        items = {};
    };

    this.size = function(){
        return Object.keys(items).length;
    };

    this.keys = function(){
        return Object.keys(items);
    };

    this.values = function(){
        var values = [];
        for (var k in items) {
            if (this.has(k)) {
                values.push(items[k]);
            }
        }
        return values;
    };

    this.each = function(fn) {
        for (var k in items) {
            if (this.has(k)) {
                fn(k, items[k]);
            }
        }
    };

    this.getItems = function(){
        return items;
    }
}

【使用Dictionary类】

  首先,我们来创制二个Dictionary类的实例,然后给它加多三条电子邮件地址。大家将会使用那个dictionary实例来兑现三个电子邮件地址簿。使用大家创设的类来施行如下代码:

var dictionary = new Dictionary(); 
dictionary.set('Gandalf', 'gandalf@email.com'); 
dictionary.set('John', 'johnsnow@email.com'); 
dictionary.set('Tyrion', 'tyrion@email.com');

  尽管实践了之类代码,输出结果将会是true:

console.log(dictionary.has('Gandalf'));

  上边包车型客车代码将会输出3,因为大家向字典实例中增加了八个要素:

console.log(dictionary.size());

  以往,推行下边包车型地铁几行代码:

console.log(dictionary.keys()); 
console.log(dictionary.values()); 
console.log(dictionary.get('Tyrion'));

  输出结果个别如下所示:

["Gandalf", "John", "Tyrion"]
["gandalf@email.com", "johnsnow@email.com", "tyrion@email.com"] 
tyrion@email.com

  最终,再实行几行代码:

dictionary.remove('John');

  再举办上边包车型大巴代码:

console.log(dictionary.keys()); 
console.log(dictionary.values()); 
console.log(dictionary.getItems());

  输出结果如下所示:

["Gandalf", "Tyrion"] 
["gandalf@email.com", "tyrion@email.com"]
Object {Gandalf: "gandalf@email.com", Tyrion: "tyrion@email.com"}

  移除了一个要素后,今后的dictionary实例中只包含多个元素了

 

function Dictionary() {
    var items = {};
    this.has = function (key) {
        return key in items;//使用in操作符来验证一个key是否是items对象的一个属性
        //return items.hasOwnProperty(key)
    }
    this.set = function (key, value) {
        items[key] = value;//添加一个新的值或更新一个已有的值
    }
    this.remove = function (key) {
        if (this.has(key)) {
            delete items[key];
            return true;
        }
        return false;
    }
    this.get = function (key) {
        return this.has(key) ? items[key] : undefined;
    }
    this.values = function () {
        var values = [];
        for (let i in items) {
            if (this.has(i)) {
                values.push(items[i]);
            }
        }
        return values;
    }
    this.clear = function () {
        items = {};
    }
    this.size = function () {
        return Object.keys(items).length;
    }
    this.keys = function () {
        return Object.keys(items);
    }
    this.getItems = function () {
        return items;
    }
}

散列表

  下边将详细介绍HashTable类,也叫HashMap类,是Dictionary类的生机勃勃种散列表完毕格局

  散列算法的效果与利益是尽量快地在数据构造中找到多少个值。假若要在数据构造中拿到三个值(使用get方法),需求遍历整个数据布局来找到它。假如选取散列函数,就知道值的具体地方,因而能够快捷搜索到该值。散列函数的效能是给定叁个键值,然后重返值在表中之处

  举个例证,大家后续接收在前方使用的电子邮件地址簿。我们即将利用最普遍的散列函数——“lose lose”散列函数,方法是粗略地将种种键值中的种种字母的ASCII值相加

澳门博彩排名 1

【创设散列表】

  大家将动用数组来表示我们的数据构造,从搭建类的骨架早先:

function HashTable(){
  var table = [];
}

  然后,给类增添一些方法。大家给每个类完毕四个根底的方法

put(key,value):向散列表增加一个新的项(也能更新散列表)。
remove(key):根据键值从散列表中移除值。
get(key):返回根据键值检索到的特定的值。

  在得以完毕那多少个办法从前,要兑现的首先个点子是散列函数,它是HashTable类中的二个民用方法:

var loseloseHashCode = function (key) {
 var hash = 0; //{1}
 for (var i = 0; i < key.length; i++) { //{2}
     hash += key.charCodeAt(i); //{3}
 }
 return hash % 37; //{4}
};

  给定多个key参数,就会依据组成key的种种字符的ASCII码值的和获得多少个数字。所以,首先要求贰个变量来囤积那几个总和(行{1})。然后,遍历key(行{2})并将从ASCII表中查到的各样字符对应的ASCII值加到hash变量中(能够选择JavaScript的String类中的charCodeAt方法——行{3})。最终,重回hash值。为了获得一点都异常的小的数值,大家会采取hash值和四个任意数做除法的余数(mod)

【put】

  今后,有了散列函数,我们就足以兑现put方法了:

this.put = function(key, value) {
 var position = loseloseHashCode(key); //{5}
 console.log(position + ' - ' + key); //{6}
 table[position] = value; //{7}
}; 

  首先,依据给定的key和所创办的散列函数总结出它在表中的岗位(行{5})。为了有扶助突显消息,我们将总结出的职位输出至调控台(行{6})。由于它不是必得的,大家也足以将那行代码移除。然后要做的,是将value参数增多到用散列函数总计出的对应的职位上(行{7})

【get】

  从HashTable实例中搜索三个值也很简短。为此,将会促成四个get方法。首先,大家会采用所开创的散列函数来求出给定key所对应的地点。那一个函数会重返值的岗位,由此大家所要做的正是依据那些职务从数组table中获取那些值。

this.get = function (key) {
 return table[loseloseHashCode(key)];
}; 

【remove】

  要从HashTable实例中移除二个成分,只需须求出元素之处(能够行使散列函数来赢得)并赋值为undefined。

  对于HashTable类来讲,大家无需像ArrayList类同样从table数组中校地方也移除。由于成分遍布于豆蔻梢头体数组范围内,一些地点会未有别的因素私吞,并默以为undefined值。我们也不能够将地方本人从数组中移除(那会改换其余因素的职位),不然,当下一次要求拿到或移除一个因素的时候,这一个因素会不在我们用散列函数求出的职责上

this.remove = function(key) {
 table[loseloseHashCode(key)] = undefined;
}; 

【完整代码】

  HashTable类的完好代码如下所示 

function HashTable() {

    var table = [];

    var loseloseHashCode = function (key) {
        var hash = 0;
        for (var i = 0; i < key.length; i++) {
            hash += key.charCodeAt(i);
        }
        return hash % 37;
    };

    var djb2HashCode = function (key) {
        var hash = 5381;
        for (var i = 0; i < key.length; i++) {
            hash = hash * 33 + key.charCodeAt(i);
        }
        return hash % 1013;
    };

    var hashCode = function (key) {
        return loseloseHashCode(key);
    };

    this.put = function (key, value) {
        var position = hashCode(key);
        console.log(position + ' - ' + key);
        table[position] = value;
    };

    this.get = function (key) {
        return table[hashCode(key)];
    };

    this.remove = function(key){
        table[hashCode(key)] = undefined;
    };

    this.print = function () {
        for (var i = 0; i < table.length; ++i) {
            if (table[i] !== undefined) {
                console.log(i + ": " + table[i]);
            }
        }
    };
}

【使用HashTable类】

  上边试行一些代码来测试HashTable类:

var hash = new HashTable();
hash.put('Gandalf', 'gandalf@email.com');
hash.put('John', 'johnsnow@email.com');
hash.put('Tyrion', 'tyrion@email.com'); 

  试行上述代码,会在调节新竹得到如下输出:

19 - Gandalf
29 - John
16 - Tyrion 

  下边包车型地铁图片表现了蕴藏那七个成分的HashTable数据结构:

澳门博彩排名 2

  以后来测验get方法:

console.log(hash.get('Gandalf'));
console.log(hash.get('Loiane')); 

  获得如下的输出:

gandalf@email.com
undefined 

  由于Gandalf是八个在散列表中留存的键,get方法将会回去它的值。而出于Loiane是一个不设有的键,当大家打算在数组中依照岗位获取值的时候(三个由散列函数生成的地点),重临值将会是undefined(即子虚乌有)

  然后,大家搜求从散列表中移除Gandalf:

hash.remove('Gandalf');
console.log(hash.get('Gandalf'));

  由于Gandalf不再存在于表中,hash.get('Gandalf'卡塔尔国方法将会在调控台上给出undefined的出口结果

【散列集结】

  在一些编制程序语言中,还也许有风姿罗曼蒂克种叫作散列集结的完结。散列集结由七个聚焦构成,不过插入、移除或拿到成分时,使用的是散列函数。大家能够引用本章中完毕的具备代码来促成散列群集,分裂之处在于,不再增加键值对,而是只插入值而从不键。举个例子,能够应用散列群集来积存全数的拉脱维亚语单词(不满含它们的概念)。和聚合印象,散列群集只存款和储蓄唯风华正茂的不重复的值

 

在散列表中也是以[键,值]对的款式来存款和储蓄数据,然则与字典的贯彻情势略有区别。HashTable类,也叫HashMap类,是Dictionary类的一种散列表落成形式。散列算法的功用是竭尽快地在数据构造中找到多少个值。假若接纳散列函数,给定三个键值,就可以重回值在表中的地点,因此能够高效搜索到该值。

处理冲突

  有的时候候,一些键会有同生龙活虎的散列值。不一样的值在散列表中对应平等地方的时候,大家称其为矛盾。比方,我们看看上面的代码会收获哪些的输出结果:

var hash = new HashTable();
hash.put('Gandalf', 'gandalf@email.com');
hash.put('John', 'johnsnow@email.com');
hash.put('Tyrion', 'tyrion@email.com');
hash.put('Aaron', 'aaron@email.com');
hash.put('Donnie', 'donnie@email.com');
hash.put('Ana', 'ana@email.com');
hash.put('Jonathan', 'jonathan@email.com');
hash.put('Jamie', 'jamie@email.com');
hash.put('Sue', 'sue@email.com');
hash.put('Mindy', 'mindy@email.com');
hash.put('Paul', 'paul@email.com');
hash.put('Nathan', 'nathan@email.com'); 

  输出结果如下:

19 - Gandalf
29 - John
16 - Tyrion
16 - Aaron
13 - Donnie
13 - Ana
5 - Jonathan
5 - Jamie
5 - Sue
32 - Mindy
32 - Paul
10 – Nathan

  Tyrion和亚伦有生机勃勃致的散列值(16)。Donnie和Ana有同等的散列值(13),Jonathan、Jamie和Sue有平等的散列值(5),Mindy和Paul也是有相仿的散列值(32)

  那HashTable实例会怎么着呢?试行在此之前的代码后散列表中会有怎么样值吗?为了获取结果,大家来得以达成一个叫作print的支持方法,它会在调整台上输出HashTable中的值:

this.print = function() {
 for (var i = 0; i < table.length; ++i) { //{1}
   if (table[i] !== undefined) { //{2}
     console.log(i + ": " + table[i]);//{3}
   }
 }
}; 

  首先,遍历数组中的全数因素(行{1})。当有些地点上有值的时候(行{2}),会在调控台上输出地点和对应的值(行{3})。以后来使用那些法子:

hash.print();

  在调整台上获取如下的输出结果:

5:sue@email.com
10:nathan@email.com
13:ana@email.com
16:aaron@email.com
19:gandalf@email.com
29:johnsnow@email.com
32:paul@email.com

  Jonathan、詹米和Sue有相同的散列值,也正是5。由于Sue是最终三个被抬高的,Sue将是在HashTable实例中背公营私地点5的因素。首先,Jonathan会占有那一个职位,然后詹米会覆盖它,然后Sue会再一次覆盖。那对于其余发生矛盾的成分来讲也是同样的。

  使用二个数据构造来保存数据的目标显而易见不是去遗失那个多少,而是通过某种方式将它们整个保存起来。由此,当这种景色时有发生的时候将要去消除它。管理矛盾有二种办法:分离链接、线性探查和双散列法

【分离链接】

  抽离链接法蕴含为散列表的每一个职位创设一个链表并将元素存储在里面。它是消除冲突的最简便易行的点子,可是它在HashTable实例之外还亟需额外的存放空间

  比如,大家在前边的测量试验代码中使用分别链接的话,输出结果将会是这么:

澳门博彩排名 3

  在地方5上,将会有隐含八个要素的LinkedList实例;在岗位13、16和32上,将会有隐含三个因素的LinkedList实例;在职位10、19和29上,将会有隐含单个成分的LinkedList实例

  对于抽离链接和线性探查来讲,只供给重写四个措施:put、get和remove。这多个艺术在每一个才干达成中都以例外的

  为了兑现多个选用了分别链接的HashTable实例,大家要求一个新的扶助类来表示将在加盟LinkedList实例的因素。大家管它叫ValuePair类(在HashTable类内部定义):

var ValuePair = function(key, value){
 this.key = key;
 this.value = value;
 this.toString = function() {
  return '[' + this.key + ' - ' + this.value + ']'; 
  }
};

  那些类只会将key和value存款和储蓄在三个Object实例中。我们也重写了toString方法,以便之后在浏览器调控新北输出结果

  大家来落到实处率先个艺术,put方法,代码如下:

this.put = function(key, value){
 var position = loseloseHashCode(key);
 if (table[position] == undefined) { //{1}
   table[position] = new LinkedList();
 }
 table[position].append(new ValuePair(key, value)); //{2}
}; 

  在这里个艺术中,将表达要加入新因素的职分是或不是已经被占据(行{1})。假如这一个地方是首先次被投入元素,大家会在此个岗位上开首化叁个LinkedList类的实例(你早已在第5章中上学过)。然后,使用append方法向LinkedList实例中加多叁个ValuePair实例(键和值)(行{2})

  然后,我们兑现用来收获特定值的get方法:

this.get = function(key) {
 var position = loseloseHashCode(key);
 if (table[position] !== undefined){ //{3}
  //遍历链表来寻找键/值
  var current = table[position].getHead(); //{4}
    while(current.next){ //{5}
    if (current.element.key === key){ //{6}
      return current.element.value; //{7}
    }
    current = current.next; //{8}
  }
  //检查元素在链表第一个或最后一个节点的情况
  if (current.element.key === key){ //{9}
    return current.element.value;
  }
 }
 return undefined; //{10}
}; 

  大家要做的率先个验证,是鲜明在一定的岗位上是或不是有成分存在(行{3})。若无,则赶回三个undefined表示在HashTable实例中从未找到这些值(行{10})。要是在此个岗位上有值存在,大家了然那是叁个LinkedList实例。未来要做的是遍历这一个链表来寻觅大家须求的因素。在遍历在此以前先要获取链表表头的援引(行{4}),然后就可以从链表的尾部遍历到尾巴部分(行{5},current.next将会是null)。

  Node链表富含next指针和element属性。而element属性又是ValuePair的实例,所以它又有value和key属性。能够透过current.element.next来收获Node链表的key属性,并由此比较它来显著它是不是就是我们要找的键(行{6})。(那正是要利用ValuePair那些援救类来囤积成分的源委。大家无法轻巧地蕴藏值小编,那样就不能够明确哪些值对应着一定的键。)假若key值相同,就回来Node的值(行{7});假如不平等,就继续遍历链表,访问下一个节点(行{8})。

  如若要找的要素是链表的率先个或最终三个节点,那么就不会进去while循环的里边。由此,须求在行{9}管理这种极度的动静

  使用分别链接法从HashTable实例中移除叁个成分和从前在本章完毕的remove方法有意气风发部分不意气风发。今后接收的是链表,大家供给从链表中移除八个成分。来探访remove方法的完成:

this.remove = function(key){
 var position = loseloseHashCode(key);
 if (table[position] !== undefined){
  var current = table[position].getHead();
  while(current.next){
    if (current.element.key === key){ //{11}
      table[position].remove(current.element); //{12}
      if (table[position].isEmpty()){ //{13}
        table[position] = undefined; //{14}
      }
      return true; //{15}
    }
    current = current.next;
  }
  // 检查是否为第一个或最后一个元素
  if (current.element.key === key){ //{16}
    table[position].remove(current.element);
  if (table[position].isEmpty()){
    table[position] = undefined;
  }
  return true;
  }
 }
 return false; //{17}
}; 

  在remove方法中,大家运用和get方法相符的手续找到要找的成分。遍历LinkedList实例时,若是链表中的current成分正是要找的因素(行{11}),使用remove方法将其从链表中移除。然后进行一步额外的认证:借使链表为空了(行{13}——链表中不再有别的因素了),就将散列表那些地点的值设为undefined(行{14}),那样搜索一个因素或打字与印刷它的剧情的时候,就足以跳过那么些任务了。最后,再次回到true表示那几个因素已经被移除(行{15})或许在最后回来false表示那些因素在散列表中不设有(行{17})。雷同,须求和get方法相似,管理成分在首先个或最终一个的情状(行{16})

  重写了那五个法子后,我们就具备了贰个利用了分别链接法来管理矛盾的HashMap实例

  分离链接的HashMap的欧洲经济共同体代码如下所示

function HashTableSeparateChaining(){

    var table = [];

    var ValuePair = function(key, value){
        this.key = key;
        this.value = value;

        this.toString = function() {
            return '[' + this.key + ' - ' + this.value + ']';
        }
    };

    var loseloseHashCode = function (key) {
        var hash = 0;
        for (var i = 0; i < key.length; i++) {
            hash += key.charCodeAt(i);
        }
        return hash % 37;
    };

    var hashCode = function(key){
        return loseloseHashCode(key);
    };

    this.put = function(key, value){
        var position = hashCode(key);
        console.log(position + ' - ' + key);

        if (table[position] == undefined) {
            table[position] = new LinkedList();
        }
        table[position].append(new ValuePair(key, value));
    };

    this.get = function(key) {
        var position = hashCode(key);

        if (table[position] !== undefined  && !table[position].isEmpty()){

            //iterate linked list to find key/value
            var current = table[position].getHead();

            do {
                if (current.element.key === key){
                    return current.element.value;
                }
                current = current.next;
            } while(current);
        }
        return undefined;
    };

    this.remove = function(key){

        var position = hashCode(key);

        if (table[position] !== undefined){

            //iterate linked list to find key/value
            var current = table[position].getHead();

            do {
                if (current.element.key === key){
                    table[position].remove(current.element);
                    if (table[position].isEmpty()){
                        table[position] = undefined;
                    }
                    return true;
                }
                current = current.next;
            } while(current);
        }

        return false;
    };

    this.print = function() {
        for (var i = 0; i < table.length; ++i) {
            if (table[i] !== undefined) {
               console.log(table[i].toString());
            }
        }
    };
}

【线性探查】

  另风流倜傥种缓和冲突的办法是线性探查。当想向表中有个别地点出席一个新因素的时候,假如索引为index之处已经被攻陷了,就尝试index+1的岗位。如若index+1的岗位也被占用了,就尝试index+2的任务,就那样类推

  继续完结内需重写的八个主意。第2个是put方法:

this.put = function(key, value){
 var position = loseloseHashCode(key); // {1}
 if (table[position] == undefined) { // {2}
   table[position] = new ValuePair(key, value); // {3}
 } else {
  var index = ++position; // {4}
  while (table[index] != undefined){ // {5}
    index++; // {6}
  }
  table[index] = new ValuePair(key, value); // {7}
 }
}; 

  和此前近似,先得到由散列函数生成的岗位(行{1}),然后验证那几个任务是不是有成分存在(假如那么些职位被攻下了,将会经过行{2}的辨证)。若无成分存在,就在此个职分加入新因素(行{3}——一个ValuePair的实例)

  如果这些任务已经被占有了,必要找到下贰个并未有被并吞的地方(position的值是undefined),由此大家声可瑞康(Karicare卡塔尔(قطر‎(Karicare卡塔尔(Aptamil卡塔尔(英语:State of Qatar)个index变量并赋值为position+1(行{4}——在变量名前使用自增运算符++会先依次增加变量值然后再将其赋值给index)。然后验证这么些地方是不是被祛除(行{5}),若是被挤占了,继续将index依次增加(行{6}),直到找到七个从没有过被占领的职位。然后要做的,就是将值分配到这几个地方(行{7})

  假若重复实践后面实例中插入数据的代码,下图展现使用了线性探查的散列表的末尾结果:

澳门博彩排名 4

  让我们来模拟一下散列表中的插入操作

  1、试着插入Gandalf。它的散列值是19,由于散列表刚刚被创制,地点19依然空的——能够在那地插入数据

  2、试着在地方29插入John。它也是空的,所以能够插入这厮名

  3、试着在地点16插入Tyrion。它是空的,所以能够插入此人名

  4、试着插入亚伦,它的散列值也是16。地方16早已被Tyrion占领了,所以必要检查索引值为position+1的位置(16+1)。地点17是空的,所以能够在岗位17插入亚伦

  5、接着,试着在岗位13插入Donnie。它是空的,所以能够插入这厮名

  6、想在任务13插入Ana,但是这些职位被攻陷了。由此在职位14实行尝试,它是空的,所以能够在此边插入姓名

  7、然后,在地方5插入Jonathan,那几个岗位是空的,所以能够插入此人名

  8、试着在岗位5插入Jamie,可是那一个职责被占了。所以跳至地方6,那一个职位是空的,因而得以在这里个地方插入姓名

  9、试着在岗位5插入Sue,不过地点被占用了。所以跳至地方6,但也被占了。接着跳至地点7,这里是空的,所以可以在此插入姓名。由此及彼

  今后布置了具备的成分,上面完毕get方法来得到它们的值

this.get = function(key) {
 var position = loseloseHashCode(key);
 if (table[position] !== undefined){ //{8}
  if (table[position].key === key) { //{9}
    return table[position].value; //{10}
  } else {
    var index = ++position;
    while (table[index] === undefined  || table[index].key !== key){ //{11}
      index++;
    }
    if (table[index].key === key) { //{12}
      return table[index].value; //{13}
    }
  }
 }
 return undefined; //{14}
}; 

  要获得叁个键八方呼应的值,先要明确那个键存在(行{8})。假设这一个键海市蜃楼,表达要找出的值不在散列表中,由此得以重临undefined(行{14})。假若这么些键存在,必要检讨大家要找的值是或不是就是以此任务上的值(行{9})。就算是,就赶回那些值(行{10})。

  如若不是,就在散列表中的下贰个任务三回九转搜寻,直到找到叁个键值与大家要找的键值相像的因素(行{11})。然后,验证一下当下项正是我们要找的项(行{12}——只是为了确认一下)何况将它的值重临(行{13})。

  大家力所不及分明要找的成分实际上在哪些岗位,那正是应用ValuePair来表示HashTable成分的原故

  remove方法和get方法基本相近,分裂之处在于行{10}和{13},它们将会由上边的代码替代:

table[index]=undefined;

  要移除二个因素,只需求给其赋值为undefined,来表示那一个职位不再被侵夺同一时间能够在必要时选取二个新因素

  线性探查的HashTable的完好代码如下所示

function HashLinearProbing(){

    var table = [];

    var ValuePair = function(key, value){
        this.key = key;
        this.value = value;

        this.toString = function() {
            return '[' + this.key + ' - ' + this.value + ']';
        }
    };

    var loseloseHashCode = function (key) {
        var hash = 0;
        for (var i = 0; i < key.length; i++) {
            hash += key.charCodeAt(i);
        }
        return hash % 37;
    };

    var hashCode = function(key){
        return loseloseHashCode(key);
    };

    this.put = function(key, value){
        var position = hashCode(key);
        console.log(position + ' - ' + key);

        if (table[position] == undefined) {
            table[position] = new ValuePair(key, value);
        } else {
            var index = ++position;
            while (table[index] != undefined){
                index++;
            }
            table[index] = new ValuePair(key, value);
        }
    };

    this.get = function(key) {
        var position = hashCode(key);

        if (table[position] !== undefined){
            if (table[position].key === key) {
                return table[position].value;
            } else {
                var index = ++position;
                while (table[index] !== undefined && (table[index] && table[index].key !== key)){
                    index++;
                }
                if (table[index] && table[index].key === key) {
                    return table[index].value;
                }
            }
        } else { //search for possible deleted value
            var index = ++position;
            while (table[index] == undefined || index == table.length ||
                (table[index] !== undefined && table[index] && table[index].key !== key)){
                index++;
            }
            if (table[index] && table[index].key === key) {
                return table[index].value;
            }
        }
        return undefined;
    };

    this.remove = function(key){
        var position = hashCode(key);

        if (table[position] !== undefined){
            if (table[position].key === key) {
                table[position] = undefined;
            } else {
                var index = ++position;
                while (table[index] === undefined || table[index].key !== key){
                    index++;
                }
                if (table[index].key === key) {
                    table[index] = undefined;
                }
            }
        }
    };

    this.print = function() {
        for (var i = 0; i < table.length; ++i) {
            if (table[i] !== undefined) {
                console.log(i + ' -> ' + table[i].toString());
            }
        }
    };
}

【越来越好的散列函数】

  “loselose”散列函数并非一个展现优秀的散列函数,因为它会发生太多的冲突。如若利用那个函数的话,会生出形形色色的冲突。多少个展现美好的散列函数是由多少个方面构成的:插入和查找成分的岁月(即质量),当然也包蕴比较低的冲突大概

  另二个得以兑现的比“loselose”更加好的散列函数是djb2:

var djb2HashCode = function (key) {
 var hash = 5381; //{1}
 for (var i = 0; i < key.length; i++) { //{2}
     hash = hash * 33 + key.charCodeAt(i); //{3}
 }
 return hash % 1013; //{4}
}; 

  它富含初步化一个hash变量并赋值为二个质数(行{1}——大多数贯彻都选用5381),然后迭代参数key(行{2}),将hash与33相乘(用来作为一个吸重力数),并和近年来迭代到的字符的ASCII码值相加(行{3})

  最终,大家将应用相加的和与另八个随机质数(比大家以为的散列表的大小要大——在本例中,我们感到散列表的轻重缓急为1000)相除的余数。

  尽管重复施行前面实例中插入数据的代码,那将是选用djb2HashCode代替loseloseHashCode的最后结果:

798-Gandalf
838-John
624-Tyrion
215-Aaron
278-Donnie
925-Ana
288-Jonathan
962-Jamie
502-Sue
804-Mindy
54-Paul
223-Nathan

  未有冲突!那而不是最佳的散列函数,但那是最被社区引入的散列函数之生龙活虎

 

function HashTable() {
    var table = [];
    //散列函数
    var loseloseHashCode = function (key) {
        var hash = 0;
        for (let i = 0; i < key.length; i++) {
            hash += key.charCodeAt(i);
        }
        return hash % 37;
    }
    this.put = function (key, value) {
        var position = loseloseHashCode(key);
        console.log(position + ' - ' + key);
        table[position] = value;
    }
    this.get = function (key) {
        return table[loseloseHashCode(key)];
    }
    this.remove = function (key) {
        table[loseloseHashCode(key)] = undefined;//不同于ArrayList类一样将位置也删除,移动元素,这会改变其他元素的位置
    }
}

ES6

  ECMAScript 二〇一四大幅度增涨了Map类。大家得以基于ES6的Map类开辟大家的Dictionary类

  看看原生的Map类怎么用。依然用大家原本测量试验Dictionary类的事例:

var map = new Map();
map.set('Gandalf', 'gandalf@email.com');
map.set('John', 'johnsnow@email.com');
map.set('Tyrion', 'tyrion@email.com');
console.log(map.has('Gandalf')); //输出true
console.log(map.size); //输出3
console.log(map.keys()); //输出["Gandalf", "John", "Tyrion"]
console.log(map.values()); //输出["gandalf@email.com",
"johnsnow@email.com", "tyrion@email.com"]
console.log(map.get('Tyrion')); //输出tyrion@email.com 

  和Dictionary类差别,ES6的Map类的values方法和keys方法都回到Iterator,实际不是值或键构成的数组。另二个分裂是,我们兑现的size方法重返字典中存款和储蓄的值的个数,而ES6的Map类则有二个size属性

  删除map中的成分得以用delete方法:

map.delete('John');

  clear方法会重新设置map数据布局,那跟大家在Dictionary类里福寿绵绵的均等

  除了Set和Map那三种新的数据构造,ES6还扩充了它们的减少版本,WeakSet和WeakMap。基本上,Map和Set与其弱化版本之间仅局部不一致是:

  1、WeakSet或WeakMap类没有entries、keys和values等方法;

  2、只好用对象作为键

  成立和利用那七个类体贴是为着质量。WeakSet和WeakMap是弱化的(用对象作为键),未有强援用的键。那使得JavaScript的废品回笼器能够从当中消弭整个入口。另一个优点是,必需用键才方可抽取值。这几个类未有entries、keys和values等迭代器方法,由此,除非知道键,不然未有主意抽取值

  使用WeakMap类的事比方下:

var map = new WeakMap();
var ob1 = {name:'Gandalf'}, //{1}
    ob2 = {name:'John'},
    ob3 = {name:'Tyrion'};
map.set(ob1, 'gandalf@email.com'); //{2}
map.set(ob2, 'johnsnow@email.com');
map.set(ob3, 'tyrion@email.com');
console.log(map.has(ob1)); //{3} 输出true
console.log(map.get(ob3)); //{4} 输出tyrion@email.com
map.delete(ob2); //{5}

  WeakMap类也足以用set方法,但不能够利用数字、字符串、布尔值等骨干数据类型,须要将名字调换为对象(行{1}和行{2})。寻找(行{3})、读取(行{4})和删除值(行{5}),也要传播作为键的靶子。相像的逻辑也适用于WeakSet类

 

突发性,一些键会有同等的散列值。分歧的键值在散列表中对应同等地方的时候,大家称其为冲突。发生冲突时对应平等职位的末梢的二个键的值会覆盖掉前边的值,分明使用三个数据布局来保存数据的目标不是去遗失这个数量,而是通过某种方式将它们整个保存起来。管理冲突有二种办法:分离链接、线性探查和双散列法。

  1. 暌违链接
    分离链接法为散列表的每叁个地点创立一个链表并将成分存款和储蓄在其间,那是化解冲突的最轻便易行的艺术,可是它在HashTable 实例之外还需求万分的仓库储存空间。代码如下:

本文由澳门网络娱乐游戏平台发布于Web前端,转载请注明出处:最新赌博的网址大全前端学数据构造之字典和散列表

相关阅读