From 35592e1bb8b954815c08c3fb67ce69af33d4c893 Mon Sep 17 00:00:00 2001 From: Acid Date: Fri, 24 Jul 2026 03:57:15 -0400 Subject: [PATCH] moved heapSort to its own file --- tests/treeTests/heapSort_test.go | 137 ++++++++++++++++++ trees/heap/heapSort.go | 30 ++++ .../{priorityQeue.go => priorityQueue.go} | 25 ---- 3 files changed, 167 insertions(+), 25 deletions(-) create mode 100644 tests/treeTests/heapSort_test.go create mode 100644 trees/heap/heapSort.go rename trees/heap/{priorityQeue.go => priorityQueue.go} (72%) diff --git a/tests/treeTests/heapSort_test.go b/tests/treeTests/heapSort_test.go new file mode 100644 index 0000000..41d6c39 --- /dev/null +++ b/tests/treeTests/heapSort_test.go @@ -0,0 +1,137 @@ +package tests + +import ( + "math/rand" + "slices" + "testing" + + "datastructures/trees/heap" +) + +func TestHeapSortRandomInts(t *testing.T) { + input := []int{5, 3, 9, 1, 7, 2, 8, 6, 4} + + sorted := heap.HeapSort(input) + + if !slices.IsSorted(sorted) { + t.Errorf("HeapSort = %v, want ascending order", sorted) + } + if len(sorted) != len(input) { + t.Errorf("len = %d, want %d", len(sorted), len(input)) + } +} + +func TestHeapSortAlreadySorted(t *testing.T) { + sorted := heap.HeapSort([]int{1, 2, 3, 4, 5}) + + want := []int{1, 2, 3, 4, 5} + if !slices.Equal(sorted, want) { + t.Errorf("HeapSort = %v, want %v", sorted, want) + } +} + +func TestHeapSortReversed(t *testing.T) { + sorted := heap.HeapSort([]int{5, 4, 3, 2, 1}) + + want := []int{1, 2, 3, 4, 5} + if !slices.Equal(sorted, want) { + t.Errorf("HeapSort = %v, want %v", sorted, want) + } +} + +func TestHeapSortSingleElement(t *testing.T) { + sorted := heap.HeapSort([]int{42}) + + want := []int{42} + if !slices.Equal(sorted, want) { + t.Errorf("HeapSort = %v, want %v", sorted, want) + } +} + +// Empty input returns nil rather than an empty slice. +func TestHeapSortEmpty(t *testing.T) { + sorted := heap.HeapSort([]int{}) + + if len(sorted) != 0 { + t.Errorf("HeapSort on empty input = %v, want no elements", sorted) + } +} + +func TestHeapSortKeepsDuplicates(t *testing.T) { + input := []int{3, 1, 3, 2, 1, 3} + + sorted := heap.HeapSort(input) + + want := []int{1, 1, 2, 3, 3, 3} + if !slices.Equal(sorted, want) { + t.Errorf("HeapSort = %v, want %v", sorted, want) + } +} + +func TestHeapSortNegativeValues(t *testing.T) { + sorted := heap.HeapSort([]int{3, -5, 0, -1, 8, -5}) + + want := []int{-5, -5, -1, 0, 3, 8} + if !slices.Equal(sorted, want) { + t.Errorf("HeapSort = %v, want %v", sorted, want) + } +} + +// Heapify clones the slice, so the caller's input must come back untouched. +func TestHeapSortDoesNotMutateInput(t *testing.T) { + input := []int{5, 3, 9, 1, 7} + original := slices.Clone(input) + + heap.HeapSort(input) + + if !slices.Equal(input, original) { + t.Errorf("input was mutated: got %v, want %v", input, original) + } +} + +// HeapSort is generic over cmp.Ordered, not just numbers. +func TestHeapSortStrings(t *testing.T) { + sorted := heap.HeapSort([]string{"pear", "apple", "fig", "banana"}) + + want := []string{"apple", "banana", "fig", "pear"} + if !slices.Equal(sorted, want) { + t.Errorf("HeapSort = %v, want %v", sorted, want) + } +} + +func TestHeapSortFloats(t *testing.T) { + sorted := heap.HeapSort([]float64{2.5, -1.5, 0.0, 10.25, 2.4}) + + want := []float64{-1.5, 0.0, 2.4, 2.5, 10.25} + if !slices.Equal(sorted, want) { + t.Errorf("HeapSort = %v, want %v", sorted, want) + } +} + +// Fuzz-ish check against the standard library over many random inputs. +func TestHeapSortMatchesSlicesSort(t *testing.T) { + random := rand.New(rand.NewSource(1)) + + for round := range 200 { + size := random.Intn(50) + input := make([]int, size) + for i := range input { + input[i] = random.Intn(100) - 50 + } + + want := slices.Clone(input) + slices.Sort(want) + + got := heap.HeapSort(input) + + if size == 0 { + if len(got) != 0 { + t.Fatalf("round %d: HeapSort on empty input = %v", round, got) + } + continue + } + if !slices.Equal(got, want) { + t.Fatalf("round %d: HeapSort(%v) = %v, want %v", round, input, got, want) + } + } +} diff --git a/trees/heap/heapSort.go b/trees/heap/heapSort.go new file mode 100644 index 0000000..7f0eccd --- /dev/null +++ b/trees/heap/heapSort.go @@ -0,0 +1,30 @@ +package heap + +import ( + "cmp" +) + +// HeapSort() -> takes in an array and returns it sorted. O(n log n) +func HeapSort[T cmp.Ordered](arg []T) []T { + if len(arg) <= 0 { + return nil + } + + heap := NewMinHeap[T]() + heap.Heapify(arg) + + sorted := make([]T, 0, len(arg)) + + for range heap.Array { + + val, ok := heap.PopMin() + + if !ok { + break + } + + sorted = append(sorted, val) + } + + return sorted +} diff --git a/trees/heap/priorityQeue.go b/trees/heap/priorityQueue.go similarity index 72% rename from trees/heap/priorityQeue.go rename to trees/heap/priorityQueue.go index 3962c28..6c73f3c 100644 --- a/trees/heap/priorityQeue.go +++ b/trees/heap/priorityQueue.go @@ -4,31 +4,6 @@ import ( "cmp" ) -// HeapSrort() -> takes in an array and returns it sorted. O(n log n) -func HeapSrort[T cmp.Ordered](arg []T) []T { - if len(arg) <= 0 { - return nil - } - - heap := NewMinHeap[T]() - heap.Heapify(arg) - - sorted := make([]T, 0, len(arg)) - - for range heap.Array { - - val, ok := heap.PopMin() - - if !ok { - break - } - - sorted = append(sorted, val) - } - - return sorted -} - // PriorityQueue type PriorityQueue[T cmp.Ordered] struct { heap MinHeap[T]