From d29998a7979c4c771a203d36c30f985d5191b134 Mon Sep 17 00:00:00 2001 From: "Zed A. Shaw" Date: Fri, 26 Sep 2025 21:49:41 -0400 Subject: [PATCH] First night of doing the data structures. --- .gitignore | 32 ++++++++++ Makefile | 6 ++ dlist/impl.go | 100 +++++++++++++++++++++++++++++++ go.mod | 11 ++++ go.sum | 10 ++++ llist/impl.go | 106 ++++++++++++++++++++++++++++++++ main.go | 8 +++ tests/double_list_test.go | 41 +++++++++++++ tests/linked_list_test.go | 37 ++++++++++++ tests/ternary_tree_test.go | 30 ++++++++++ tst/impl.go | 120 +++++++++++++++++++++++++++++++++++++ 11 files changed, 501 insertions(+) create mode 100644 .gitignore create mode 100644 Makefile create mode 100644 dlist/impl.go create mode 100644 go.mod create mode 100644 go.sum create mode 100644 llist/impl.go create mode 100644 main.go create mode 100644 tests/double_list_test.go create mode 100644 tests/linked_list_test.go create mode 100644 tests/ternary_tree_test.go create mode 100644 tst/impl.go diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..611ea8f --- /dev/null +++ b/.gitignore @@ -0,0 +1,32 @@ +# ---> Vim +# Swap +[._]*.s[a-v][a-z] +!*.svg # comment out if you don't need vector files +[._]*.sw[a-p] +[._]s[a-rt-v][a-z] +[._]ss[a-gi-z] +[._]sw[a-p] + +# Session +Session.vim +Sessionx.vim + +# Temporary +.netrwhist +*~ +# Auto-generated tag files +tags +# Persistent undo +[._]*.un~ + +backup +*.exe +*.dll +coverage +coverage/* +.venv +*.gz +config.toml +public +*.idx +*.sqlite3 diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..377a9b1 --- /dev/null +++ b/Makefile @@ -0,0 +1,6 @@ + +test: + go test MY/dsa/tests -v + +build: + go build . diff --git a/dlist/impl.go b/dlist/impl.go new file mode 100644 index 0000000..2b100e0 --- /dev/null +++ b/dlist/impl.go @@ -0,0 +1,100 @@ +package dlist + +import ( + "fmt" +) + +type Node struct { + Data any + Next *Node + Prev *Node +} + +type DLinkedList struct { + Front *Node + End *Node + Count int +} + +func (l *DLinkedList) Add(data any) { + el := Node{data, nil, nil} + + if l.Front == nil { + l.Front = &el + l.End = &el + } else { + l.End.Next = &el + el.Prev = l.End + l.End = &el + } + + l.Count++ +} + +func (l *DLinkedList) Find(data any) (*Node) { + for el := l.Front; el != nil; el = el.Next { + if el.Data == data { + return el + } + } + + return nil +} + +func (l *DLinkedList) Delete(target *Node) { + if target == l.Front { + l.PopFront() + } else if target == l.End { + l.PopBack() + } else { + prev := target.Prev + prev.Next = target.Next + } + + l.Count-- +} + +func (l *DLinkedList) PopBack() (*Node) { + if l.Front == nil { + return nil + } else if l.Front == l.End { + el := l.End + l.Front = nil + l.End = nil + l.Count = 0 + return el + } else { + el := l.End + l.End = el.Prev + l.End.Next = nil + l.Count-- + return el + } +} + +func (l *DLinkedList) PopFront() (*Node) { + if l.Front == nil { + return nil + } else if l.Front == l.End { + el := l.Front + l.Front = nil + l.End = nil + l.Count = 0 + return el + } else { + el := l.Front + next := l.Front.Next + l.Front = next + next.Prev = nil + l.Count-- + return el + } +} + +func (l *DLinkedList) Dump() { + fmt.Println("----------------", l.Count, "nodes") + + for cur := l.Front; cur != nil; cur = cur.Next { + fmt.Println(cur.Data) + } +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..f9e156a --- /dev/null +++ b/go.mod @@ -0,0 +1,11 @@ +module MY/dsa + +go 1.24.2 + +require github.com/stretchr/testify v1.11.1 + +require ( + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..c4c1710 --- /dev/null +++ b/go.sum @@ -0,0 +1,10 @@ +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= +github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/llist/impl.go b/llist/impl.go new file mode 100644 index 0000000..8049a5a --- /dev/null +++ b/llist/impl.go @@ -0,0 +1,106 @@ +package llist + +import ( + "fmt" +) + +type Node struct { + Data any + Next *Node +} + +type LinkedList struct { + Front *Node + End *Node + Count int +} + +func (l *LinkedList) Add(data any) { + el := Node{data, nil} + + if l.Front == nil { + l.Front = &el + l.End = &el + } else { + l.End.Next = &el + l.End = &el + } + + l.Count++ +} + +func (l *LinkedList) Find(data any) (*Node) { + for el := l.Front; el != nil; el = el.Next { + if el.Data == data { + return el + } + } + + return nil +} + +func (l *LinkedList) Delete(target *Node) { + if l.Front == target { + l.PopFront() + } else if l.End == target { + l.PopBack() + } else { + el := l.Front + + for el.Next != target { + el = el.Next + } + + el.Next = el.Next.Next + target.Next = nil + l.Count-- + } +} + +func (l *LinkedList) PopBack() (*Node) { + el := l.End + + if l.Front == nil { + return nil + } else if l.Front == l.End { + l.Front = nil + l.End = nil + l.Count-- + } else { + new_end := l.Front + for new_end.Next.Next != nil { + new_end = new_end.Next + } + + l.End = new_end + l.End.Next = nil + l.Count-- + } + + return el +} + +func (l *LinkedList) PopFront() (*Node) { + el := l.Front + + if l.Front == nil { + return nil + } else if l.Front == l.End { + l.Front = nil + l.End = nil + l.Count-- + } else { + l.Front = l.Front.Next + l.Count-- + } + + return el +} + +func (l *LinkedList) Dump() { + fmt.Println("----------------", l.Count, "nodes") + + for cur := l.Front; cur != nil; cur = cur.Next { + fmt.Println(cur.Data) + } +} diff --git a/main.go b/main.go new file mode 100644 index 0000000..de34d37 --- /dev/null +++ b/main.go @@ -0,0 +1,8 @@ +package main + +import ( + "fmt" +) +func main() { + fmt.Println("nothing here") +} diff --git a/tests/double_list_test.go b/tests/double_list_test.go new file mode 100644 index 0000000..013702b --- /dev/null +++ b/tests/double_list_test.go @@ -0,0 +1,41 @@ +package tests + +import ( + "testing" + "github.com/stretchr/testify/assert" + "MY/dsa/dlist" +) + +func TestDoubleLinkedList(t *testing.T) { + list := dlist.DLinkedList{} + assert.Nil(t, list.PopBack()) + assert.Nil(t, list.PopFront()) + + list.Add("front") + assert.Equal(t, list.End.Data, "front") + + list.Add("back") + list.Dump() + assert.Equal(t, list.End.Data, "back") + + back := list.PopBack() + assert.Equal(t, back.Data, "back") + + list.Add("middle1") + list.Add("middle2") + list.Add("back2") + + list.Dump() + back = list.PopBack() + assert.Equal(t, back.Data, "back2") + + front := list.PopFront() + assert.Equal(t, front.Data, "front") + list.Dump() + + middle := list.Find("middle2") + assert.Equal(t, middle.Data, "middle2") + + list.Delete(middle) + list.Dump() +} diff --git a/tests/linked_list_test.go b/tests/linked_list_test.go new file mode 100644 index 0000000..b9c2e9d --- /dev/null +++ b/tests/linked_list_test.go @@ -0,0 +1,37 @@ +package tests + +import ( + "testing" + "github.com/stretchr/testify/assert" + "MY/dsa/llist" +) + +func TestLinkedList(t *testing.T) { + list := llist.LinkedList{} + assert.Nil(t, list.PopBack()) + assert.Nil(t, list.PopFront()) + + list.Add("front") + list.Add("back") + list.Dump() + back := list.PopBack() + assert.Equal(t, back.Data, "back") + + list.Add("middle1") + list.Add("middle2") + list.Add("back2") + + list.Dump() + back = list.PopBack() + assert.Equal(t, back.Data, "back2") + + front := list.PopFront() + assert.Equal(t, front.Data, "front") + list.Dump() + + middle := list.Find("middle2") + assert.Equal(t, middle.Data, "middle2") + + list.Delete(middle) + list.Dump() +} diff --git a/tests/ternary_tree_test.go b/tests/ternary_tree_test.go new file mode 100644 index 0000000..7513710 --- /dev/null +++ b/tests/ternary_tree_test.go @@ -0,0 +1,30 @@ +package tests + +import ( + "testing" + "github.com/stretchr/testify/assert" + "MY/dsa/tst" +) + +func TestTernarySearchTree(t *testing.T) { + tree := tst.TST{} + + tree.Add("hello", 100) + + hello := tree.Get("hello") + assert.Equal(t, 100, hello) + + tree.Add("howdy", 200) + howdy := tree.Get("howdy") + assert.Equal(t, 200, howdy) + + nope := tree.Get("nope") + assert.Equal(t, nil, nope) + + tree.Delete("howdy") + howdy = tree.Get("howdy") + assert.Equal(t, nil, howdy) + + maybe := tree.StartsWith("ho") + assert.Equal(t, 200, maybe.Value) +} diff --git a/tst/impl.go b/tst/impl.go new file mode 100644 index 0000000..3da7db2 --- /dev/null +++ b/tst/impl.go @@ -0,0 +1,120 @@ +package tst + +import ( +) + +type TST struct { + Root *Node +} + +type Node struct { + Char rune + Value any + Less *Node + Equal *Node + Greater *Node +} + +func (t *TST) Add(key string, value any) { + if t.Root == nil { + // first run, setup with the start letter + t.Root = &Node{rune(key[0]), nil, nil, nil, nil} + } + + pos := t.Root + + for _, ch := range key { + if ch < pos.Char { + if pos.Less == nil { + pos.Less = &Node{ch, nil, nil, nil, nil} + } + + pos = pos.Less + } else if ch > pos.Char { + if pos.Greater == nil { + pos.Greater = &Node{ch, nil, nil, nil, nil} + } + + pos = pos.Greater + } else if ch == pos.Char { + if pos.Equal == nil { + pos.Equal = &Node{ch, nil, nil, nil, nil} + } + + pos = pos.Equal + } + + pos.Value = value + } +} + +func (t *TST) Find(key string) (*Node) { + if t.Root == nil { + return nil + } + + pos := t.Root + next := t.Root + + for _, ch := range key { + if ch < pos.Char { + next = pos.Less + } else if ch > pos.Char { + next = pos.Greater + } else if ch == pos.Char { + next = pos.Equal + } + + if next == nil { + return nil + } else { + pos = next + } + } + + return pos +} + +func (t *TST) Get(key string) any { + node := t.Find(key) + + if node == nil { + return nil + } else { + return node.Value + } +} + +func (t *TST) Delete(key string) { + node := t.Find(key) + + if node != nil { + node.Value = nil + } +} + +func (t *TST) StartsWith(key string) *Node { + if t.Root == nil { + return nil + } + + pos := t.Root + next := t.Root + + for _, ch := range key { + if ch < pos.Char { + next = pos.Less + } else if ch > pos.Char { + next = pos.Greater + } else if ch == pos.Char { + next = pos.Equal + pos = pos.Equal + } + + if next == nil { + return pos + } + } + + return pos +}