diff --git a/README.md b/README.md index bf4151d..5bd540a 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# DS +# Data Structures & Algorithms in Go ## Linear @@ -8,13 +8,35 @@ - [ ] Circular Buffer - [ ] Deque -## Graph +## Tree — hierarchical, parent/child relationships -## Tree +- [ ] Binary Tree +- [ ] Binary Search Tree +- [ ] AVL Tree +- [ ] Heap (min/max) +- [ ] Trie + +## Graph — nodes connected by edges, no strict hierarchy + +- [ ] Directed +- [ ] Undirected +- [ ] Weighted + +## Hash Based — key/value + +- [ ] Hash Map +- [ ] Hash Set + +# Each category solves different problems: + +- Linear — ordered data, undo/redo, scheduling +- Tree — searching, sorting, hierarchical data like file systems +- Graph — networks, maps, social connections, dependencies +- Hash — fast lookups, caching, counting +- Set — membership testing, deduplication # Documentation ```bash go doc -all ./linear | bat -l go - ``` diff --git a/tests/linkedList_test.go b/tests/linkedList_test.go new file mode 100644 index 0000000..3307cb6 --- /dev/null +++ b/tests/linkedList_test.go @@ -0,0 +1,260 @@ +package tests + +import ( + "testing" + + "datastructures/linear" +) + +// --- InsertAtHead --- + +func TestLinkedListInsertAtHeadSingle(t *testing.T) { + ll := &linear.LinkedList[int]{} + ll.InsertAtHead(42) + + got := ll.Data() + if got == nil { + t.Fatal("expected non-nil Data after InsertAtHead, got nil") + } + if *got != 42 { + t.Errorf("expected 42, got %d", *got) + } +} + +func TestLinkedListInsertAtHeadOrderIsLIFO(t *testing.T) { + ll := &linear.LinkedList[int]{} + ll.InsertAtHead(1) + ll.InsertAtHead(2) + ll.InsertAtHead(3) + + got := ll.Data() + if got == nil || *got != 3 { + t.Errorf("expected 3 (last inserted) at head, got %v", got) + } +} + +// --- InsertAtTail --- + +func TestLinkedListInsertAtTailSingle(t *testing.T) { + ll := &linear.LinkedList[string]{} + ll.InsertAtTail("hello") + + got := ll.Data() + if got == nil || *got != "hello" { + t.Errorf("expected 'hello' at head, got %v", got) + } +} + +func TestLinkedListInsertAtTailDoesNotMoveHead(t *testing.T) { + ll := &linear.LinkedList[int]{} + ll.InsertAtHead(1) + ll.InsertAtTail(2) + ll.InsertAtTail(3) + + got := ll.Data() + if got == nil || *got != 1 { + t.Errorf("expected head to remain 1 after tail inserts, got %v", got) + } +} + +// --- Data --- + +func TestLinkedListDataOnEmpty(t *testing.T) { + ll := &linear.LinkedList[int]{} + if ll.Data() != nil { + t.Error("expected nil Data on empty list") + } +} + +// --- DeleteHead --- + +func TestLinkedListDeleteHeadOnEmpty(t *testing.T) { + ll := &linear.LinkedList[int]{} + ll.DeleteHead() // must not panic + if ll.Data() != nil { + t.Error("expected nil Data after DeleteHead on empty list") + } +} + +func TestLinkedListDeleteHeadSingleElement(t *testing.T) { + ll := &linear.LinkedList[int]{} + ll.InsertAtHead(5) + ll.DeleteHead() + + if ll.Data() != nil { + t.Error("expected nil after deleting the only element via DeleteHead") + } +} + +func TestLinkedListDeleteHeadAdvancesHead(t *testing.T) { + ll := &linear.LinkedList[int]{} + ll.InsertAtHead(1) + ll.InsertAtHead(2) + ll.InsertAtHead(3) + + ll.DeleteHead() + + got := ll.Data() + if got == nil || *got != 2 { + t.Errorf("expected 2 after deleting head (3), got %v", got) + } +} + +// --- DeleteTail --- + +func TestLinkedListDeleteTailOnEmpty(t *testing.T) { + ll := &linear.LinkedList[int]{} + ll.DeleteTail() // must not panic + if ll.Data() != nil { + t.Error("expected nil Data after DeleteTail on empty list") + } +} + +func TestLinkedListDeleteTailSingleElement(t *testing.T) { + ll := &linear.LinkedList[int]{} + ll.InsertAtTail(10) + ll.DeleteTail() + + if ll.Data() != nil { + t.Error("expected nil after deleting the only element via DeleteTail") + } +} + +func TestLinkedListDeleteTailRemovesLastElement(t *testing.T) { + ll := &linear.LinkedList[int]{} + ll.InsertAtTail(1) + ll.InsertAtTail(2) + ll.InsertAtTail(3) + + ll.DeleteTail() + + // walk head → next to verify 3 is gone + got := ll.Data() + if got == nil || *got != 1 { + t.Errorf("expected head to remain 1, got %v", got) + } + ll.DeleteHead() + got = ll.Data() + if got == nil || *got != 2 { + t.Errorf("expected second element to be 2 (3 was deleted), got %v", got) + } + ll.DeleteHead() + if ll.Data() != nil { + t.Error("expected empty list after removing all elements") + } +} + +// --- string type --- + +func TestLinkedListWithStrings(t *testing.T) { + ll := &linear.LinkedList[string]{} + ll.InsertAtHead("bob") + ll.InsertAtHead("alice") + + got := ll.Data() + if got == nil || *got != "alice" { + t.Errorf("expected alice at head, got %v", got) + } + + ll.DeleteHead() + got = ll.Data() + if got == nil || *got != "bob" { + t.Errorf("expected bob after deleting alice, got %v", got) + } +} + +func TestLinkedListZeroValue(t *testing.T) { + ll := &linear.LinkedList[int]{} + ll.InsertAtHead(0) + + got := ll.Data() + if got == nil || *got != 0 { + t.Errorf("expected zero-value int at head, got %v", got) + } +} + +// --- pointer type --- + +func TestLinkedListWithPointers(t *testing.T) { + ll := &linear.LinkedList[*int]{} + v1, v2 := 10, 20 + p1, p2 := &v1, &v2 + + ll.InsertAtTail(p1) + ll.InsertAtTail(p2) + + got := ll.Data() + if got == nil || *got != p1 { + t.Errorf("expected p1 at head, got %v", got) + } +} + +func TestLinkedListPointerMutation(t *testing.T) { + ll := &linear.LinkedList[*int]{} + v := 42 + p := &v + ll.InsertAtHead(p) + + v = 99 + + got := ll.Data() + if got == nil || **got != 99 { + t.Errorf("expected mutation reflected via pointer, got %v", got) + } +} + +func TestLinkedListNilPointer(t *testing.T) { + ll := &linear.LinkedList[*int]{} + ll.InsertAtHead(nil) + + got := ll.Data() + if got == nil { + t.Fatal("expected non-nil Data pointer (pointing to a nil *int), got nil") + } + if *got != nil { + t.Errorf("expected stored nil *int, got %v", *got) + } +} + +// --- mixed operations --- + +func TestLinkedListAlternatingInsertDelete(t *testing.T) { + ll := &linear.LinkedList[int]{} + ll.InsertAtHead(1) + ll.InsertAtTail(2) + ll.InsertAtHead(0) + // list: 0 <--> 1 <--> 2 + + ll.DeleteTail() + // list: 0 <--> 1 + + got := ll.Data() + if got == nil || *got != 0 { + t.Errorf("expected 0 at head, got %v", got) + } + + ll.DeleteHead() + // list: 1 + got = ll.Data() + if got == nil || *got != 1 { + t.Errorf("expected 1 as sole remaining element, got %v", got) + } + + ll.DeleteHead() + if ll.Data() != nil { + t.Error("expected empty list after deleting all elements") + } +} + +func TestLinkedListDeleteBothEndsToEmpty(t *testing.T) { + ll := &linear.LinkedList[string]{} + ll.InsertAtTail("a") + ll.InsertAtTail("b") + + ll.DeleteHead() + ll.DeleteTail() + + if ll.Data() != nil { + t.Error("expected empty list after removing both elements") + } +}