Implement hash set
This commit is contained in:
parent
031c9f6be8
commit
acae9a6b41
5 changed files with 234 additions and 25 deletions
92
hash_set/hash_set/hash_set.go
Normal file
92
hash_set/hash_set/hash_set.go
Normal file
|
@ -0,0 +1,92 @@
|
|||
package hash_set
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type MyHash interface {
|
||||
~string | ~int | ~uint | ~int64 | ~uint64 | ~int32 | ~uint32 | ~int16 | ~uint16 | ~int8 | ~uint8
|
||||
}
|
||||
|
||||
type Hasher[H MyHash] interface {
|
||||
Hash() H
|
||||
}
|
||||
|
||||
// MyHashSet is a hash set implementation.
|
||||
type MyHashSet[T Hasher[H], H MyHash] struct {
|
||||
storage map[H]T
|
||||
}
|
||||
|
||||
// NewSet initializes a new hash set.
|
||||
func NewSet[T Hasher[H], H MyHash]() MyHashSet[T, H] {
|
||||
return MyHashSet[T, H]{
|
||||
storage: make(map[H]T, 100),
|
||||
}
|
||||
}
|
||||
|
||||
// Add adds an element to a set.
|
||||
func (s *MyHashSet[T, H]) Add(element T) {
|
||||
// Hash element
|
||||
hash := element.Hash()
|
||||
|
||||
// Save
|
||||
_, ok := s.storage[hash]
|
||||
if !ok {
|
||||
s.storage[hash] = element
|
||||
}
|
||||
}
|
||||
|
||||
// AddAll adds all the elements to the set.
|
||||
func (s *MyHashSet[T, H]) AddAll(elements ...T) {
|
||||
for _, element := range elements {
|
||||
s.Add(element)
|
||||
}
|
||||
}
|
||||
|
||||
// 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 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
|
||||
}
|
||||
|
||||
// String returns the string representation of the set.
|
||||
func (s *MyHashSet[T, H]) String() string {
|
||||
var sb strings.Builder
|
||||
sb.WriteString("MyHashSet{")
|
||||
for _, value := range s.storage {
|
||||
sb.WriteString(fmt.Sprintf("%v,", value))
|
||||
}
|
||||
sb.WriteString("}")
|
||||
return sb.String()
|
||||
}
|
||||
|
||||
// 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 creates a difference of two sets
|
||||
func (s *MyHashSet[T, H]) Sub(other *MyHashSet[T, H]) {
|
||||
for _, v := range other.storage {
|
||||
s.Delete(v)
|
||||
}
|
||||
}
|
85
hash_set/hash_set/hash_set_test.go
Normal file
85
hash_set/hash_set/hash_set_test.go
Normal file
|
@ -0,0 +1,85 @@
|
|||
package hash_set
|
||||
|
||||
import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type MyString struct {
|
||||
Value string
|
||||
}
|
||||
|
||||
func (m MyString) Hash() string {
|
||||
return m.Value
|
||||
}
|
||||
|
||||
func TestNewSet(t *testing.T) {
|
||||
newSet := NewSet[MyString, string]()
|
||||
assert.NotNil(t, newSet)
|
||||
}
|
||||
|
||||
func TestMyHashSet_Add(t *testing.T) {
|
||||
// Given
|
||||
newSet := NewSet[MyString, string]()
|
||||
newSet.Add(MyString{Value: "some"})
|
||||
|
||||
// Then
|
||||
assert.True(t, newSet.Contains(MyString{Value: "some"}))
|
||||
}
|
||||
|
||||
func TestMyHashSet_AddAll(t *testing.T) {
|
||||
// Given
|
||||
newSet := NewSet[MyString, string]()
|
||||
newSet.AddAll(MyString{Value: "some"}, MyString{Value: "another"})
|
||||
|
||||
// Then
|
||||
assert.True(t, newSet.Contains(MyString{Value: "some"}))
|
||||
assert.True(t, newSet.Contains(MyString{Value: "another"}))
|
||||
}
|
||||
|
||||
func TestMyHashSet_Delete(t *testing.T) {
|
||||
// Given
|
||||
newSet := NewSet[MyString, string]()
|
||||
newSet.AddAll(MyString{Value: "some"}, MyString{Value: "another"})
|
||||
newSet.Delete(MyString{Value: "some"})
|
||||
|
||||
// Then
|
||||
assert.False(t, newSet.Contains(MyString{Value: "some"}))
|
||||
assert.True(t, newSet.Contains(MyString{Value: "another"}))
|
||||
}
|
||||
|
||||
func TestMyHashSet_Union(t *testing.T) {
|
||||
// Setup
|
||||
newSet := NewSet[MyString, string]()
|
||||
newSet.AddAll(MyString{Value: "some"}, MyString{Value: "another"})
|
||||
|
||||
anotherSet := NewSet[MyString, string]()
|
||||
anotherSet.AddAll(MyString{Value: "Batman"}, MyString{Value: "Robin"})
|
||||
|
||||
// Test
|
||||
newSet.Union(&anotherSet)
|
||||
|
||||
// Then
|
||||
assert.True(t, newSet.Contains(MyString{Value: "some"}))
|
||||
assert.True(t, newSet.Contains(MyString{Value: "another"}))
|
||||
assert.True(t, newSet.Contains(MyString{Value: "Batman"}))
|
||||
assert.True(t, newSet.Contains(MyString{Value: "Robin"}))
|
||||
}
|
||||
|
||||
func TestMyHashSet_Sub(t *testing.T) {
|
||||
// Setup
|
||||
newSet := NewSet[MyString, string]()
|
||||
newSet.AddAll(MyString{Value: "some"}, MyString{Value: "another"}, MyString{Value: "Batman"})
|
||||
|
||||
anotherSet := NewSet[MyString, string]()
|
||||
anotherSet.AddAll(MyString{Value: "Batman"}, MyString{Value: "Robin"})
|
||||
|
||||
// Test
|
||||
newSet.Sub(&anotherSet)
|
||||
|
||||
// Then
|
||||
assert.True(t, newSet.Contains(MyString{Value: "some"}))
|
||||
assert.True(t, newSet.Contains(MyString{Value: "another"}))
|
||||
assert.False(t, newSet.Contains(MyString{Value: "Batman"}))
|
||||
assert.False(t, newSet.Contains(MyString{Value: "Robin"}))
|
||||
}
|
51
hash_set/main.go
Normal file
51
hash_set/main.go
Normal file
|
@ -0,0 +1,51 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"go-dsa/hash_set/v2/hash_set"
|
||||
)
|
||||
|
||||
type Person struct {
|
||||
Name string
|
||||
Age int
|
||||
}
|
||||
|
||||
// Hash returns the has of a person, it conforms to the hash_set.Hasher interface
|
||||
func (p Person) Hash() string {
|
||||
return fmt.Sprintf("%s-%d", p.Name, p.Age)
|
||||
}
|
||||
|
||||
func main() {
|
||||
mySet := hash_set.NewSet[Person, string]()
|
||||
|
||||
// Add
|
||||
mySet.Add(Person{
|
||||
Name: "Batman",
|
||||
Age: 28,
|
||||
})
|
||||
mySet.Add(Person{
|
||||
Name: "Robin",
|
||||
Age: 16,
|
||||
})
|
||||
mySet.Add(Person{
|
||||
Name: "Batman",
|
||||
Age: 28,
|
||||
})
|
||||
|
||||
// Print
|
||||
fmt.Printf("%s\n", mySet.String())
|
||||
|
||||
// Contains
|
||||
result := mySet.Contains(Person{
|
||||
Name: "Batman",
|
||||
Age: 28,
|
||||
})
|
||||
fmt.Printf("Set contains batman %v\n", result)
|
||||
|
||||
// Deletion
|
||||
mySet.Delete(Person{
|
||||
Name: "Batman",
|
||||
Age: 28,
|
||||
})
|
||||
fmt.Printf("%s\n", mySet.String())
|
||||
}
|
25
main.go
25
main.go
|
@ -1,25 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
//TIP To run your code, right-click the code and select <b>Run</b>. Alternatively, click
|
||||
// the <icon src="AllIcons.Actions.Execute"/> icon in the gutter and select the <b>Run</b> menu item from here.
|
||||
|
||||
func main() {
|
||||
//TIP Press <shortcut actionId="ShowIntentionActions"/> when your caret is at the underlined or highlighted text
|
||||
// to see how GoLand suggests fixing it.
|
||||
s := "gopher"
|
||||
fmt.Println("Hello and welcome, %s!", s)
|
||||
|
||||
for i := 1; i <= 5; i++ {
|
||||
//TIP You can try debugging your code. We have set one <icon src="AllIcons.Debugger.Db_set_breakpoint"/> breakpoint
|
||||
// for you, but you can always add more by pressing <shortcut actionId="ToggleLineBreakpoint"/>. To start your debugging session,
|
||||
// right-click your code in the editor and select the <b>Debug</b> option.
|
||||
fmt.Println("i =", 100/i)
|
||||
}
|
||||
}
|
||||
|
||||
//TIP See GoLand help at <a href="https://www.jetbrains.com/help/go/">jetbrains.com/help/go/</a>.
|
||||
// Also, you can try interactive lessons for GoLand by selecting 'Help | Learn IDE Features' from the main menu.
|
6
readme.md
Normal file
6
readme.md
Normal file
|
@ -0,0 +1,6 @@
|
|||
# Data Structures and Algorithms
|
||||
|
||||
This repository is my self study guide for data structures and algorithms. I implement them from scratch in Go
|
||||
and then write unit test for them.
|
||||
|
||||
What better way to learn a language and new concepts exists other than practicing them.
|
Loading…
Reference in a new issue