集合以[值,值]的形式存储元素,而字典和散列表以[键,值]的形式存储元素

一、字典

创建字典

function Dictionary() {
    var items = {};

    /*has(key)如果某个键值存在于这个字典中,则返回true*/
    this.has = function(key) {
        return key in items;
    };

    /*set(key, value)向字典添加新元素*/
    this.set = function(key, value) {
        items[key] = value;
    };

    /*remove(key)从字典中移除键值对应的数据*/
    this.remove = function(key) {
        if (this.has(key)) {
            delete items[key];
            return true;
        }
        return false;
    };

    /*get(key)通过键值查找特定的数值并返回*/
    this.get = function(key) {
        return this.has(key) ? items[key] : undefined;
    };

    /*values()将字典所包含的所有数值以数组的形式返回*/
    this.values = function() {
        var values = [];
        for (var k in items) {  //包含了对象原型中的属性
            if (this.has(k)) {  //过滤掉对象原型中的属性
                values.push(items[k]);
            }
        }
        return values;
    };

    /*clear(), size, keys, getItems*/
    this.clear = function() {
        items = {};
    };
    this.size  = function() {
        return Object.keys(items).length;
    };
    this.keys = function() {
        return Object.keys(items);  //Object.keys()返回一个包含对象所有属性的数组
    };
    this.getItems = function() {
        return items;
    };
}

二、散列表

不是遍历键值来找到匹配的值,而是将每个属性转化为一个索引,通过数组的形式,检索到想要的值

创建散列表

先创建一个散列函数:给定key参数,就能够根据组成key的每个字符的ASCII码值的和得到一个数字

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;
    };

    /*添加、获取和移除等方法*/
    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;
    };
}

散列表中的冲突

当添加多个键值时,有一些键会有相同的散列值

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

先添加一个print()辅助方法,在控制台中输出HashTable中的值。

遍历数组中的所有元素,当某个位置上有值的时候,在控制台输出位置和对应的值

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

使用print()方法

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

相同的位置,后添加的值将前面的值覆盖掉了

处理散列表中的冲突

1.分离链接法

首先在HashTable类内部添加一个新的辅助类,表示将要加入LinkedList实例的元素,此类将key和value存储在一个Object实例中

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

重写put()方法,首先验证加入的新元素的位置是否已经被占据。如果没有,则在此位置初始化一个LinkedList类的实例;如果有则使用append()方法,向LinkedList实例中添加一个ValuePair实例

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

重写get()方法,

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

重写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) {
                table[position].remove(current.element);
                if (table[position].isEmpty()) {
                    table[position] = undefined;
                }
                return true;
            }
            current = current.next;
        }
        if (current.element.key === key) {
            table[position].remove(current.element);
            if (table[position].isEmpty()) {
                table[position] = undefined;
            }
        }
    }
    return false;
};

未完待续~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

2.线性探查

创建更好的散列函数