Skip to content

structure: set #111

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Mar 12, 2023
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,19 +1,34 @@
/**
* Represents a hash table.
* This interface is a representation of the Map data structure.
*/
export interface Map<K, V> {
getSize(): number;
set(key: K, value: V): void;
get(key: K): V | null;
delete(key: K): void;
has(key: K): boolean;
clear(): void;
keys(): K[];
values(): V[];
entries(): HashMapEntry<K, V>[];
}

/**
* Represents a hash map.
* Time complexity:
* - Set, Get, Delete, Has: O(1) on average, O(n) in the worst case.
* - Clear: O(m) where m is the number of buckets.
* - Keys, Values, Entires: O(n + m).
*
* @template K The key type.
* @template V The value type.
* @param size The size of the hash table.
* @param size The size of the hash map.
* @param buckets The buckets in which to store the key-value pairs.
* @param loadFactor The load factor to determine when to resize the hash table.
* @param loadFactor The load factor to determine when to resize the hash map.
*/
export class HashTable<K, V> {
export class HashMap<K, V> implements Map<K, V> {
private size!: number;
private buckets!: HashTableEntry<K, V>[][];
private buckets!: HashMapEntry<K, V>[][];
private readonly loadFactor = 0.75;

constructor() {
Expand Down Expand Up @@ -45,7 +60,7 @@ export class HashTable<K, V> {
const bucket = this.buckets[index];

if (bucket.length === 0) {
bucket.push(new HashTableEntry(key, value));
bucket.push(new HashMapEntry(key, value));
this.size++;
return;
}
Expand All @@ -57,7 +72,7 @@ export class HashTable<K, V> {
}
}

bucket.push(new HashTableEntry(key, value));
bucket.push(new HashMapEntry(key, value));
this.size++;
}

Expand Down Expand Up @@ -118,7 +133,7 @@ export class HashTable<K, V> {
}

/**
* Clears the hash table.
* Clears the hash map.
*/
clear(): void {
this.size = 0;
Expand Down Expand Up @@ -162,8 +177,8 @@ export class HashTable<K, V> {
*
* @returns The entries.
*/
entries(): HashTableEntry<K, V>[] {
const entries: HashTableEntry<K, V>[] = [];
entries(): HashMapEntry<K, V>[] {
const entries: HashMapEntry<K, V>[] = [];
for (const bucket of this.buckets) {
for (const entry of bucket) {
entries.push(entry);
Expand Down Expand Up @@ -204,7 +219,7 @@ export class HashTable<K, V> {
}

/**
* Resizes the hash table by doubling the amount of buckets.
* Resizes the hash map by doubling the amount of buckets.
*/
private resize(): void {
this.initializeBuckets(this.buckets.length * 2);
Expand All @@ -224,7 +239,7 @@ export class HashTable<K, V> {
* @param key The key.
* @param value The value.
*/
class HashTableEntry<K, V> {
class HashMapEntry<K, V> {
key: K;
value: V;

Expand Down
13 changes: 13 additions & 0 deletions data_structures/hashing/hash_map_set.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { MapSet } from "../map_set";

/**
* This class is a representation of the Set data structure based on a hash map.
*
* @template K The value type.
* @extends MapSet<K>
*/
export class HashMapSet<K> extends MapSet<K> {
constructor() {
super();
}
}
91 changes: 91 additions & 0 deletions data_structures/hashing/test/hash_map.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import { HashMap } from "../hash_map";

describe("Hash Map", () => {
let hashMap: HashMap<string, number>;
beforeEach(() => {
hashMap = new HashMap();
});

it("should set a value", () => {
hashMap.set("a", 1);

expect(hashMap.values()).toEqual([1]);
});

it("should override a value", () => {
hashMap.set("a", 1);
hashMap.set("a", 2);

expect(hashMap.values()).toEqual([2]);
});

it("should get a value", () => {
hashMap.set("a", 1);

expect(hashMap.get("a")).toBe(1);
});

it("should get null if key does not exist", () => {
expect(hashMap.get("a")).toBeNull();
});

it("should delete a value", () => {
hashMap.set("a", 1);
hashMap.delete("a");

expect(hashMap.get("a")).toBeNull();
});

it("should do nothing on delete if key does not exist", () => {
hashMap.delete("a");

expect(hashMap.get("a")).toBeNull();
});

it("should return true if key exists", () => {
hashMap.set("a", 1);

expect(hashMap.has("a")).toBe(true);
});

it("should return false if key does not exist", () => {
expect(hashMap.has("a")).toBe(false);
});

it("should clear the hash table", () => {
hashMap.set("a", 1);
hashMap.set("b", 2);
hashMap.set("c", 3);
hashMap.clear();

expect(hashMap.getSize()).toBe(0);
});

it("should return all keys", () => {
hashMap.set("a", 1);
hashMap.set("b", 2);
hashMap.set("c", 3);

expect(hashMap.keys()).toEqual(["a", "b", "c"]);
});

it("should return all values", () => {
hashMap.set("a", 1);
hashMap.set("b", 2);
hashMap.set("c", 3);

expect(hashMap.values()).toEqual([1, 2, 3]);
});

it("should return all key-value pairs", () => {
hashMap.set("a", 1);
hashMap.set("b", 2);
hashMap.set("c", 3);

expect(hashMap.entries()).toEqual([
{ key: "a", value: 1 },
{ key: "b", value: 2 },
{ key: "c", value: 3 },
]);
});
});
91 changes: 0 additions & 91 deletions data_structures/hashing/test/hash_table.test.ts

This file was deleted.

92 changes: 92 additions & 0 deletions data_structures/map_set.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import { HashMap } from "./hashing/hash_map";

/**
* This interface is a representation of the Set data structure.
*/
export interface Set<K> {
getSize(): number;
add(value: K): void;
get(value: K): K | null;
delete(value: K): void;
has(value: K): boolean;
clear(): void;
values(): K[];
}

/**
* This class is a representation of the Set data structure based on a hash map.
*
* @template K The value type.
* @implements Set<K>
* @property {Map<K, null>} hashTable The hash map used to store the set.
*/
export abstract class MapSet<K> implements Set<K> {
private hashTable: HashMap<K, null>;

constructor() {
this.hashTable = new HashMap();
}

/**
* Adds a new element to the set.
*
* @param value The value to add to the set.
*/
add(value: K): void {
this.hashTable.set(value, null);
}

/**
* Gets a value from the set.
*
* @param value The value to get from the set.
* @returns The value if it exists, null otherwise.
*/
get(value: K): K | null {
return this.hashTable.get(value);
}

/**
* Removes an element from the set.
*
* @param value The value to remove from the set.
*/
delete(value: K): void {
this.hashTable.delete(value);
}

/**
* Checks if the set contains a given value.
*
* @param value The value to check for.
* @returns Whether the set contains the value.
*/
has(value: K): boolean {
return this.hashTable.has(value);
}

/**
* Removes all elements from the set.
*/
clear(): void {
this.hashTable.clear();
}

/**
* Returns an array of all the values in the set.
*
* @returns An array of all the values in the set.
*/
values(): K[] {
return this.hashTable.keys();
}

/**
* Returns the number of elements in the set.
*
* @returns The number of elements in the set.
*/
getSize(): number {
return this.hashTable.getSize();
}
}