cuicui.
返回全部文章
Web前端 共约 1031 字 预计阅读 4 分钟

数据结构学习-集合与字典

集合

Set 是一种数据结构,用于存储唯一值的集合。它类似于数组,但不允许重复元素。

代码实现

class mySet {
    item = {} as {
        [key: string]: any;
    };

    add(element: any) {
        if (!this.has(element)) {
            this.item[element] = element;
            return true;
        }
        return false;
    }

    delete(element: any) {
        if (this.has(element)) {
            delete this.item[element];
            return true;
        }
        return false;
    }

    has(element: any) {
        return element in this.item;
    }

    clear() {
        this.item = {};
        return true;
    }

    size() {
        return Reflect.ownKeys(this.item).length;
    }

    values() {
        return Object.values(this.item);
    }
}

ES6 的 Set 结构

  1. 创建一个新的 Set 对象:可以通过以下任意一种方式创建一个 Set 对象:

    let set = new Set(); // 空集合
    let set = new Set([1, 2, 3]); // 包含了元素 1,2 和 3 的集合
  2. 添加元素到集合中:可以使用 add()方法向集合中添加元素:

    let set = new Set();
    set.add(1);
    set.add(2);
    set.add(3);
  3. 删除集合中的元素:可以使用 delete()方法删除集合中的元素:

    let set = new Set([1, 2, 3]);
    set.delete(2);
  4. 检查集合中是否存在某个元素:可以使用 has()方法来检查集合中是否存在某个元素:

    let set = new Set([1, 2, 3]);
    set.has(2); // 返回 true
    set.has(4); // 返回 false
  5. 获取集合的大小:可以使用 size 属性获取集合中元素的数量:

    let set = new Set([1, 2, 3]);
    set.size; // 返回 3
  6. 迭代集合中的元素:可以使用 for…of 循环或者 forEach()方法来迭代 Set 中的所有元素:

    let set = new Set([1, 2, 3]);
    for (let item of set) {
        console.log(item);
    }
    
    set.forEach(function (value) {
        console.log(value);
    });

利用 set 取并集, 交集, 差集

// 取交集并集差集
const setA = new Set([1, 2, 3, 4, 5]);
const setB = new Set([3, 4, 5, 6, 7]);

// 并集
const c = new Set([...setA, ...setB]);
console.log(c);

// 交集
const d = new Set([...setA].filter(item => setB.has(item)));
console.log(d);

// 差集
// 给定两个集合A和B,它们的差集是指包含所有属于集合A但不属于集合B的元素所构成的集合
// setA的差集
const e = new Set([...setA].filter(item => !setB.has(item)));
console.log(e);

字典

字典和集合很类似, 集合以(值, 值)的形式存储数据, 字典则以(键, 值)

的形式存储数据, 字典也成为映射, 符号表, 或关联数组

ES6 中的 SetMap 都是集合(collection)类型,但它们有一些区别:

  1. Set ​ 是一组有序且唯一的值的集合,而 Map ​ 是一组键值对(key-value)的集合。
  2. Set ​ 中,每个元素只出现一次,可以用来去重;在 Map ​ 中,每个键(key)只能对应一个值(value),但同一个值可以被多个键所对应。
  3. Set ​ 采用类似数组的方式来访问其成员,而 Map 则采用键来访问其成员。
  4. Set ​ 的主要方法包括 adddeletehasclear ​ 等,而 Map ​ 的主要方法包括 setgethasdeleteclear ​ 等。

因此,如果需要存储一组唯一的值或进行去重操作,可以使用 Set;如果需要存储键值对,并且需要通过键来访问其对应的值,则可以使用 Map

代码实现

class Dictionary {
    table = {} as {
        [k: string]: any;
    };
    toStr(item: any) {
        if (item === null) return "null";
        if (item === undefined) return "undefined";
        if (typeof item === "string" || item instanceof String)
            return item as string;
        return JSON.stringify(item);
    }

    set(key: any, value: any) {
        if (key !== null && value !== null) {
            this.table[this.toStr(key)] = new keyPair(key, value);
            return true;
        }
        return false;
    }
    get(key: any) {
        const value = this.table[this.toStr(key)]?.value;
        if (value) {
            return value;
        }
        return undefined;
    }
    hasKey(key: any) {
        return this.table[this.toStr(key)] != null;
    }
    keys() {
        return this.keyValues().map(item => item.key);
    }
    values() {
        return this.keyValues().map(item => item.value);
    }
    keyValues() {
        return Object.values(this.table);
    }
    size() {
        return Object.keys(this.table).length;
    }
    isEmpty() {
        return this.size() === 0;
    }
    clear() {
        this.table = {};
    }
    foreach(cb: Function) {
        const pair = this.keyValues();
        for (let i = 0; i < this.size(); i++) {
            cb(pair[i].key, pair[i].value);
        }
    }
}
class keyPair {
    key: any;
    value: any;
    constructor(key: any, value: any) {
        this.key = key;
        this.value = value;
    }
}

const dir = new Dictionary();

hashMap 散列表

散列表将 key 通过一个散列函数转化为固定长度, 解决了字典结构如果 key 过长会造成查找时间过长的问题

散列表的代码实现

import { keyPair } from "./map";

class hashMap {
    table = {} as {
        [k: string]: any;
    };
    toStr(item: any) {
        if (item === null) return "null";
        if (item === undefined) return "undefined";
        if (typeof item === "string" || item instanceof String)
            return item as string;
        return JSON.stringify(item);
    }
    hashCode(key: any) {
        // 将对象转换为字符串, 然后将字符串的ascii码值相加, 最后取余
        if (typeof key === "number") {
            return key;
        }
        const tableKey = this.toStr(key);
        let hash = 5381;
        [...tableKey].forEach(item => {
            hash = hash * 33 + item.charCodeAt(0);
        });
        return hash % 1013;
    }
    set(key: any, value: any) {
        if (key && value) {
            const position = this.hashCode(key);
            this.table[position] = new keyPair(key, value);
            return true;
        }
        return false;
    }
    get(key: any) {
        return this.table[this.hashCode(key)];
    }
    remove(key: any) {
        const hash = this.hashCode(key);
        if (this.table[hash]) {
            delete this.table[hash];
            return true;
        }
        return false;
    }
}

ES6 的 Map

ES6 中的 Map 结构可以用来存储键值对,其使用方法如下:

  1. 创建一个空的 Map 对象
const myMap = new Map();
  1. 添加键值对到 Map 中
myMap.set(key, value);
  1. 从 Map 中获取某个键对应的值
const value = myMap.get(key);
  1. 检查 Map 中是否存在指定的键
const hasKey = myMap.has(key);
  1. 获取 Map 中所有的键或值
const keys = myMap.keys();
const values = myMap.values();
  1. 获取 Map 中键值对的数量
const size = myMap.size;
  1. 遍历 Map 中的所有键值对
myMap.forEach((value, key) => {
    // 处理每个键值对
});

需要注意的是,Map 中的键可以是任何类型的值,而不仅限于字符串和数字。此外,Map 也提供了其他一些有用的方法,比如删除特定键的值,清空 Map 等。

WeakMap 和 WeakSet

WeakMap 和 WeakSet 是 ES6 中新增的两种集合类型,它们都具有以下特点:

  1. 只能存储对象作为键,不能使用原始值类型(如字符串、数字等)作为键。
  2. 对于存储在集合中的对象,当没有其他对象引用它们时,它们会被自动回收。

其中,WeakMap 是一种以弱引用方式存储键值对的类似 Map 的数据结构。与 Map 不同的是,WeakMap 中的键只能是对象,而且这些对象都是弱引用的。也就是说,当某个对象作为 WeakMap 的键时,如果没有其他对象引用该键所对应的对象,则这个键值对会被自动从 WeakMap 中删除,以释放其占用的内存。

以下是一个使用 WeakMap 的示例:

const myWeakMap = new WeakMap();

const key = {}; // 创建一个新对象

myWeakMap.set(key, "value"); // 将这个对象作为键存储到 WeakMap 中

console.log(myWeakMap.get(key)); // 输出 "value"

key = null; // 将原来的键对象置为 null

// 由于没有任何其他对象引用这个键所对应的值,因此这个键值对会被自动删除

另一方面,WeakSet 是一种以弱引用方式存储对象的类似 Set 的数据结构。与 Set 不同的是,WeakSet 中的元素只能是对象,而且这些对象都是弱引用的。也就是说,当某个对象作为 WeakSet 的元素时,如果没有其他对象引用该元素,则这个元素会被自动从 WeakSet 中删除,以释放其占用的内存。

以下是一个使用 WeakSet 的示例:

const myWeakSet = new WeakSet();

const obj1 = {}; // 创建两个新对象
const obj2 = {};

myWeakSet.add(obj1); // 将这两个对象添加到 WeakSet 中
myWeakSet.add(obj2);

console.log(myWeakSet.has(obj1)); // 输出 true

obj1 = null; // 将 obj1 置为 null

// 由于没有任何其他对象引用 obj1,因此它会被自动从 WeakSet 中删除