数据结构学习-集合与字典
集合
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 结构
-
创建一个新的 Set 对象:可以通过以下任意一种方式创建一个 Set 对象:
let set = new Set(); // 空集合 let set = new Set([1, 2, 3]); // 包含了元素 1,2 和 3 的集合 -
添加元素到集合中:可以使用 add()方法向集合中添加元素:
let set = new Set(); set.add(1); set.add(2); set.add(3); -
删除集合中的元素:可以使用 delete()方法删除集合中的元素:
let set = new Set([1, 2, 3]); set.delete(2); -
检查集合中是否存在某个元素:可以使用 has()方法来检查集合中是否存在某个元素:
let set = new Set([1, 2, 3]); set.has(2); // 返回 true set.has(4); // 返回 false -
获取集合的大小:可以使用 size 属性获取集合中元素的数量:
let set = new Set([1, 2, 3]); set.size; // 返回 3 -
迭代集合中的元素:可以使用 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 中的 Set 和 Map 都是集合(collection)类型,但它们有一些区别:
Set 是一组有序且唯一的值的集合,而Map 是一组键值对(key-value)的集合。- 在
Set 中,每个元素只出现一次,可以用来去重;在Map 中,每个键(key)只能对应一个值(value),但同一个值可以被多个键所对应。 Set 采用类似数组的方式来访问其成员,而 Map 则采用键来访问其成员。Set 的主要方法包括add、delete、has、clear 等,而Map 的主要方法包括set、get、has、delete、clear 等。
因此,如果需要存储一组唯一的值或进行去重操作,可以使用 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 结构可以用来存储键值对,其使用方法如下:
- 创建一个空的 Map 对象
const myMap = new Map();
- 添加键值对到 Map 中
myMap.set(key, value);
- 从 Map 中获取某个键对应的值
const value = myMap.get(key);
- 检查 Map 中是否存在指定的键
const hasKey = myMap.has(key);
- 获取 Map 中所有的键或值
const keys = myMap.keys();
const values = myMap.values();
- 获取 Map 中键值对的数量
const size = myMap.size;
- 遍历 Map 中的所有键值对
myMap.forEach((value, key) => {
// 处理每个键值对
});
需要注意的是,Map 中的键可以是任何类型的值,而不仅限于字符串和数字。此外,Map 也提供了其他一些有用的方法,比如删除特定键的值,清空 Map 等。
WeakMap 和 WeakSet
WeakMap 和 WeakSet 是 ES6 中新增的两种集合类型,它们都具有以下特点:
- 只能存储对象作为键,不能使用原始值类型(如字符串、数字等)作为键。
- 对于存储在集合中的对象,当没有其他对象引用它们时,它们会被自动回收。
其中,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 中删除