add readme.md
This commit is contained in:
parent
cf8a24c43a
commit
7b33f33b1e
1 changed files with 151 additions and 0 deletions
151
hash_set/readme.md
Normal file
151
hash_set/readme.md
Normal file
|
@ -0,0 +1,151 @@
|
|||
|
||||
# Introduction
|
||||
|
||||
A hash set is a data structure that allows storing elements inside a set using a hash function.
|
||||
|
||||
The set is a data structure that offers efficient access to its elements and does not allow duplicates. The uniqueness
|
||||
of an element in the hash set is determined by the hash function, in this implementation hash
|
||||
collisions are not handled. If the hash of "a" is 123 and the hash of "b" is 123 as well then we consider "a" and "b"
|
||||
to have a hash collision and if "a" is already present in the set adding "b" has no effect.
|
||||
|
||||
# Space and Time Complexity
|
||||
|
||||
The space and time complexity depends on the underlying data structure used, in this case a map is used.
|
||||
|
||||
The time complexity of Golang's maps is on average O(1) for all operations and the space complexity is O(n).
|
||||
|
||||
# Operations
|
||||
|
||||
The following operations have been implemented:
|
||||
|
||||
## Add
|
||||
|
||||
Add adds an element to the set, it doesn't handle collisions.
|
||||
|
||||
```golang
|
||||
func (s *MySet[T, H]) Add(element T) {
|
||||
// Hash element
|
||||
hash := element.Hash()
|
||||
|
||||
// Save
|
||||
_, ok := s.storage[hash]
|
||||
if !ok {
|
||||
s.storage[hash] = element
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## AddAll
|
||||
|
||||
AddAll adds all the elements to the set. It's a convenience method that allows only one method call.
|
||||
|
||||
```golang
|
||||
// AddAll adds all the elements to the set.
|
||||
func (s *MyHashSet[T, H]) AddAll(elements ...T) {
|
||||
for _, element := range elements {
|
||||
s.Add(element)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Contains
|
||||
|
||||
```golang
|
||||
// Contains checks if the hash set contains the element T.
|
||||
// Returns true if the element is part of the set, false otherwise.
|
||||
func (s *MyHashSet[T, H]) Contains(element T) bool {
|
||||
// Hash element
|
||||
hash := element.Hash()
|
||||
_, ok := s.storage[hash]
|
||||
return ok
|
||||
}
|
||||
```
|
||||
|
||||
## Delete
|
||||
|
||||
```golang
|
||||
// Delete deletes an element from the set.
|
||||
// Returns true if the element was deleted, false otherwise.
|
||||
func (s *MyHashSet[T, H]) Delete(element T) bool {
|
||||
// Hash element
|
||||
hash := element.Hash()
|
||||
_, ok := s.storage[hash]
|
||||
if ok {
|
||||
delete(s.storage, hash)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## Union
|
||||
|
||||
```golang
|
||||
// Union creates a union of two sets
|
||||
func (s *MyHashSet[T, H]) Union(other *MyHashSet[T, H]) {
|
||||
for _, v := range other.storage {
|
||||
s.Add(v)
|
||||
}
|
||||
}
|
||||
```
|
||||
## Sub
|
||||
|
||||
```golang
|
||||
// Sub creates a difference of two sets
|
||||
func (s *MyHashSet[T, H]) Sub(other *MyHashSet[T, H]) {
|
||||
for _, v := range other.storage {
|
||||
s.Delete(v)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
# Additional Notes
|
||||
|
||||
To implement the Set in a generic manner a custom interface has been defined to represent a hash:
|
||||
|
||||
```golang
|
||||
type MyHash interface {
|
||||
~string | ~int | ~uint | ~int64 | ~uint64 | ~int32 | ~uint32 | ~int16 | ~uint16 | ~int8 | ~uint8
|
||||
}
|
||||
```
|
||||
|
||||
The ~ (tilda) defines a type constraint which translates to ~string - all subtypes of string and string.
|
||||
|
||||
It allows you to write code like:
|
||||
|
||||
```golang
|
||||
type String string
|
||||
|
||||
func (a String) Hash() string {
|
||||
return string(a)
|
||||
}
|
||||
|
||||
func TestMyHashSet_Constraint(t *testing.T) {
|
||||
// Setup
|
||||
newSet := NewSet[String, string]()
|
||||
|
||||
// Test
|
||||
newSet.AddAll("type", "constraints", "rock")
|
||||
|
||||
// Then
|
||||
assert.True(t, newSet.Contains("type"))
|
||||
assert.True(t, newSet.Contains("constraints"))
|
||||
assert.True(t, newSet.Contains("rock"))
|
||||
}
|
||||
```
|
||||
The hash set structure is defined as:
|
||||
|
||||
```golang
|
||||
// MyHashSet is a hash set implementation.
|
||||
type MyHashSet[T Hasher[H], H MyHash] struct {
|
||||
storage map[H]T
|
||||
}
|
||||
```
|
||||
|
||||
The generic parameters are specified in the form `[T Hasher[H], H MyHash]` where T is the `Hasher[H]` and
|
||||
H is a concrete type of MyHash. Hasher cannot be initialized without a concrete type.
|
||||
|
||||
When initializing the hash set you will need to specify the `String`
|
||||
|
||||
You can browse the [full implementation](https://github.com/dnutiu/dsa-go/tree/master/hash_set) on my GitHub.
|
Loading…
Reference in a new issue