js数据结构与算法 第三天(集合,字典,哈希表)

集合

集合比较常见的实现方式是哈希表;
集合通常是由一组无序的,不能重复的元素构成
ES6中已经由Set类表示集合,这里自己重新实现封装
集合的封装

//封装集合类
function Set() {

    //属性 js的object对象
    this.items = {};

    //1.add()方法
    Set.prototype.add = function(value) {
        //判断集合中是否包含该元素
        //为什么这里是this.has而不是this.items.has
        if (this.has(value)) {
            return false;
        }
        this.items[value] = value;
        return true;
    }

    //2.has()方法
    Set.prototype.has = function(value) {
        return this.items.hasOwnProperty(value);
    }

    //3.remove()方法
    Set.prototype.remove = function(value) {
        //判断该集合中是否包含该元素
        //为什么这里是this.has而不是this.items.has
        if (!this.has(value)) {
            return false;
        } else {
            delete this.items[value];
            return true;
        }
    }

    //4.clear()方法
    Set.prototype.clear = function() {
        this.items = {};
    }

    //5.size()方法
    Set.prototype.size = function() {
        return Object.keys(this.items).length;
    }

    //6.values()获取集合中所有的值
    Set.prototype.values = function() {
        return Object.keys(this.items);
    }
}

集合间的操作
在这里插入图片描述

  • 并集
//集合间的操作
//并集
Set.prototype.union = function(otherSet) {
    //创建新的集合
    var unionSet = new Set();
    //取出A集合中的所有元素并添加到新集合中
    var values = this.values();
    for (var i = 0; i < values.length; i++) {
        unionSet.add(values[i]);
    }
    //取出B集合的元素并判断是否需要加到新集合中
    values = otherSet.values();
    for (var i = 0; i < values.length; i++) {
        unionSet.add(values[i]);
    }
    return unionSet;
}
 - 交集

//交集
Set.prototype.intersection = function(otherSet) {
    var intersectionSet = new Set();
    //从A中取出元素判断是否同时存在于B中
    //存在则存入新的集合中
    var values = this.values();
    for (var i = 0; i < values.length; i++) {
        var item = values[i];
        if (otherSet.has(item)) {
            intersectionSet.add(item);
        }
    }
    return intersectionSet;
}

 - 差集

//差集
Set.prototype.difference = function(otherSet) {
    var differenceSet = new Set();
    var values = this.values();
    for (var i = 0; i < values.length; i++) {
        var item = values[i];
        if (!otherSet.has(item)) {
            differenceSet.add(item);
        }
    }
    return differenceSet;
}

 - 子集

//子集
Set.prototype.subset = function(otherSet) {
    var values = this.values();
    for (var i = 0; i < values.length; i++) {
        var item = values[i];
        if (!otherSet.has(item)) {
            return false;
        }
    }
    return true;
}

字典

字典的主要特点是一一对应的关系;
存储的是键值对,没有顺序;
在这里插入图片描述
字典和映射的关系:有些编程语言中称这种映射关系为字典,有些称这种映射关系为Map

  • 属性
this.items = {};
  • 添加
//添加
Dictionary.prototype.set = function(key, value) {
    this.items[key] = value;
}
  • 判断是否有某个key
//判断字典中是否有某个key
Dictionary.prototype.has = function(key) {
    return this.items.hasOwnProperty(key);
}
  • 删除
//删除
Dictionary.prototype.remove = function(key) {
    if (!this.has(key)) {
        return false;
    } else {
        delete this.items[key];
        return true;
    }
}
  • 根据key获取value
//根据key获取value
Dictionary.prototype.get = function(key) {
    return this.has(key) ? this.items[key] : undefined;
}
  • 获取所有的keys
//获取所有的keys
Dictionary.prototype.keys = function() {
    return Object.keys(this.items);
}
  • 获取所有的value
//获取所有的value
Dictionary.prototype.has = function(key) {
    return Object.value(this.items);
}
  • size
//size
Dictionary.prototype.size = function(key) {
    return this.keys().length;
}
  • clear
//clear
Dictionary.prototype.clear = function(key) {
    this.items = {};
}

哈希表

哈希表的结构就是数组,但是它神奇的地方在于对下标值的一种变换,这种变换称之为哈希函数,通过哈希函数可以获取到HashCode
哈希表通常是基于数组进行实现的,但是相对于数组,它有很多的优势
提供非常快速的插入,删除,查找操作;
哈希表的速度比树还要快
不足
哈希表中的数据是没有顺序的,所以不能以一种固定的方式(比如从小到大)来遍历其中的元素;
哈希表中的key是不允许重复的,不能放置相同的key,用于保存不同的元素
解决冲突的两种方案

- 链地址法(拉链法)
在这里插入图片描述

- 开放地址法
开放地址法就是寻找空白的位置来放置冲突的数据项,有三种方法:
线性探测
线性探测就是从index的位置+1开始线性的查找空位置
在这里插入图片描述
在这里插入图片描述

二次探测
在这里插入图片描述

再哈希法
在这里插入图片描述
设计好的哈希函数应具备的优点:快速的计算和均匀的分布
哈希表的封装:
首先封装哈希函数:

//将字符串转换成比较大的数字
//将大的数字hashCode压缩到size范围之内
HashTable.prototype.hashFunc = function(str, size) {
    var hashCode = 0;
    //霍纳法则,计算hashCode的值
    for (var i = 0; i < str.length; i++) {
        // str.charCodeAt(i) 获取字符串的unicode编码;
        hashCode = 37 * hashCode + str.charCodeAt(i);
    }
    //取余操作
    var index = hashCode % size;
    return index;

}

判断质数:
常规算法:

//常规算法
// function isPrime(number) {
//     for (var i = 2; i < number; i++) {
//         if (number % i == 0) {
//             return false;
//         }
//     }
//     return true;
// }

更高效的算法:

HashTable.prototype.isPrime = function(number) {
   //获取number的平方根
   var temp = parseInt(Math.sqrt(number));
   for (var i = 2; i <= temp; i++) {
       if (number % i == 0) {
           return false;
       }
   }
   return true;
}

获取质数的方法:

//获取质数的方法
HashTable.prototype.getPrime = function(number) {
    while (!this.isPrime(number)) {
        number++;
    }
    return number;
}

扩容:

//扩容
HashTable.prototype.resize = function(newlimit) {
    //保存旧的数组的内容
    var oldstorage = this.storage;
    //重置所有属性
    this.storage = [];
    this.count = 0;
    this.limit = newlimit;
    //遍历pldstorage中所有的bucket
    for (var i = 0; i < oldstorage.length; i++) {
        //取出每一个bucket
        var bucket = oldstorage[i];
        //如果当前bucket是空则不继续直接进行下一次遍历
        if (bucket == null) {
            continue;
        }
        //如果不为空 则取出里面的内容并添加到新的容器中
        for (var j = 0; j < bucket.length; j++) {
            var turple = bucket[j];
            this.put(turple[0], turple[1]);
        }
    }
}

哈希表的封装:

function HashTable() {
    //属性
    //存储元素的数组
    this.storage = [];
    //当前哈希表中存放的元素个数
    this.count = 0;
    //总长度
    this.limit = 7;

    //方法
    //将字符串转换成比较大的数字
    //将大的数字hashCode压缩到size范围之内
    HashTable.prototype.hashFunc = function(str, size) {
        var hashCode = 0;
        //霍纳法则,计算hashCode的值
        for (var i = 0; i < str.length; i++) {
            // str.charCodeAt(i) 获取字符串的unicode编码;
            hashCode = 37 * hashCode + str.charCodeAt(i);
        }
        //取余操作
        var index = hashCode % size;
        return index;

    }

    //插入和修改操作
    HashTable.prototype.put = function(key, value) {
        //根据key值获取index
        var index = this.hashFunc(key, this.limit);
        //根据index取出相应位置的桶
        var bucket = this.storage[index];
        //判断是否为空
        if (bucket == null) {
            bucket = [];
            this.storage[index] = bucket;
        }
        //判断是否是修改数据
        for (var i = 0; i < bucket.length; i++) {
            var tuple = bucket[i];
            if (tuple[0] == key) {
                tuple[1] = value;
                return;
            }
        }
        //进行添加操作
        bucket.push([key, value]);
        this.count += 1;

        //判断是否需要扩容
        if (this.count > this.limit * 0.75) {
            var newSize = this.limit * 2;
            var newPrime = this.getPrime(newSize);
            this.resize(newPrime);
        }
    }

    //根据key获取value
    HashTable.prototype.get = function(key) {
        //根据key值获取index
        var index = this.hashFunc(key, this.limit);
        //根据index取出相应位置的桶
        var bucket = this.storage[index];
        if (bucket == null) {
            return null;
        } else {
            for (var i = 0; i < bucket.length; i++) {
                var tuple = bucket[i];
                if (tuple[0] == key) {
                    return tuple[1];
                }
            }
            return null;
        }
    }

    //删除方法
    HashTable.prototype.remove = function(key) {
        //根据key值获取index
        var index = this.hashFunc(key, this.limit);
        //根据index取出相应位置的桶
        var bucket = this.storage[index];
        if (bucket == null) {
            return null;
        } else {
            for (var i = 0; i < bucket.length; i++) {
                var tuple = bucket[i];
                if (tuple[0] == key) {
                    bucket.splice(i, 1);
                    this.count -= 1;
                    return tuple[1];

                    //缩小容量
                    if (this.limit > 7 && this.count < this.limit * 0.25) {
                        var newSize = Math.floor(this.limit / 2);
                        var newPrime = this.getPrime(newSize);
                        this.resize(newPrime);
                    }
                }
            }
            return null;
        }
    }

    //isEmpty()方法
    HashTable.prototype.isEmpty = function() {
        return this.count == 0;
    }

    //size()方法
    HashTable.prototype.size = function() {
        return this.count;
    }

    //扩容
    HashTable.prototype.resize = function(newlimit) {
        //保存旧的数组的内容
        var oldstorage = this.storage;
        //重置所有属性
        this.storage = [];
        this.count = 0;
        this.limit = newlimit;
        //遍历pldstorage中所有的bucket
        for (var i = 0; i < oldstorage.length; i++) {
            //取出每一个bucket
            var bucket = oldstorage[i];
            //如果当前bucket是空则不继续直接进行下一次遍历
            if (bucket == null) {
                continue;
            }
            //如果不为空 则取出里面的内容并添加到新的容器中
            for (var j = 0; j < bucket.length; j++) {
                var turple = bucket[j];
                this.put(turple[0], turple[1]);
            }
        }
    }

    //判断质数
    //更高效的方法
    HashTable.prototype.isPrime = function(number) {
        //获取number的平方根
        var temp = parseInt(Math.sqrt(number));
        for (var i = 2; i <= temp; i++) {
            if (number % i == 0) {
                return false;
            }
        }
        return true;
    }

    //常规算法
    // function isPrime(number) {
    //     for (var i = 2; i < number; i++) {
    //         if (number % i == 0) {
    //             return false;
    //         }
    //     }
    //     return true;
    // }

    //获取质数的方法
    HashTable.prototype.getPrime = function(number) {
        while (!this.isPrime(number)) {
            number++;
        }
        return number;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值