From c411c9fd1775849df308ef333888fc344a248021 Mon Sep 17 00:00:00 2001 From: Hayden McAlister Date: Fri, 13 Dec 2024 16:16:38 +1300 Subject: [PATCH 01/25] Add ForwardIterator and ReverseIterator methods to linked list --- list/LinkedList/linkedlist.go | 40 ++++++++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/list/LinkedList/linkedlist.go b/list/LinkedList/linkedlist.go index f38b97e..35d584f 100644 --- a/list/LinkedList/linkedlist.go +++ b/list/LinkedList/linkedlist.go @@ -1,6 +1,10 @@ package linkedlist -import dsa_error "github.com/hmcalister/Go-DSA/utils/DSA_Error" +import ( + "iter" + + dsa_error "github.com/hmcalister/Go-DSA/utils/DSA_Error" +) // An implementation of a doubly linked list. type LinkedList[T any] struct { @@ -232,6 +236,40 @@ func ReverseFold[T any, G any](list *LinkedList[T], initialAccumulator G, f func return acc } +// Iterate over the items of the list in the forward direction. +// Returns both the index (as counted from the head) and item. +// This method is not concurrency safe. For concurrent applications, consider using a mutex, or pull the data out using Items(). +func (list *LinkedList[T]) ForwardIterator() iter.Seq2[int, T] { + return func(yield func(int, T) bool) { + index := 0 + currentNode := list.head + for currentNode != nil { + if !yield(index, currentNode.item) { + return + } + currentNode = currentNode.next + index += 1 + } + } +} + +// Iterate over the items of the list in the reverse direction. +// Returns both the index (as counted from the tail) and item. +// This method is not concurrency safe. For concurrent applications, consider using a mutex, or pull the data out using Items(). +func (list *LinkedList[T]) ReverseIterator() iter.Seq2[int, T] { + return func(yield func(int, T) bool) { + index := 0 + currentNode := list.tail + for currentNode != nil { + if !yield(index, currentNode.item) { + return + } + currentNode = currentNode.prev + index += 1 + } + } +} + // ---------------------------------------------------------------------------- // Add methods From f0f2ad39feb724f80944a11ee8d811b84602a3b3 Mon Sep 17 00:00:00 2001 From: Hayden McAlister Date: Fri, 13 Dec 2024 16:16:45 +1300 Subject: [PATCH 02/25] Add ForwardIterator and ReverseIterator method tests to linked list --- list/LinkedList/linkedlist_apply_test.go | 45 ++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/list/LinkedList/linkedlist_apply_test.go b/list/LinkedList/linkedlist_apply_test.go index f69c5fd..4b22902 100644 --- a/list/LinkedList/linkedlist_apply_test.go +++ b/list/LinkedList/linkedlist_apply_test.go @@ -135,3 +135,48 @@ func TestReverseFold(t *testing.T) { t.Errorf("result (%v) does not match expected result (%v)", concatString, expectedConcatString) } } + +func TestForwardIterator(t *testing.T) { + list := linkedlist.New[int]() + items := []int{1, 2, 3, 4, 5, 6, 7, 8, 9} + for _, item := range items { + list.Add(item) + } + + sum := 0 + for index, item := range list.ForwardIterator() { + sum += index * item + } + + expectedSum := 0 + for index, item := range items { + expectedSum += index * item + } + + if sum != expectedSum { + t.Errorf("result (%v) does not match expected result (%v)", sum, expectedSum) + } +} + +func TestReverseIterator(t *testing.T) { + list := linkedlist.New[int]() + items := []int{1, 2, 3, 4, 5, 6, 7, 8, 9} + for _, item := range items { + list.Add(item) + } + + sum := 0 + for index, item := range list.ReverseIterator() { + sum += index * item + } + + slices.Reverse(items) + expectedSum := 0 + for index, item := range items { + expectedSum += index * item + } + + if sum != expectedSum { + t.Errorf("result (%v) does not match expected result (%v)", sum, expectedSum) + } +} From 3cc1fa917d6cced486a6ed118fb0f647419679ce Mon Sep 17 00:00:00 2001 From: Hayden McAlister Date: Fri, 13 Dec 2024 16:16:48 +1300 Subject: [PATCH 03/25] Add ForwardIterator and ReverseIterator methods to linked list queue --- queue/LinkedListQueue/linkedlistqueue.go | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/queue/LinkedListQueue/linkedlistqueue.go b/queue/LinkedListQueue/linkedlistqueue.go index 62668a6..d43e077 100644 --- a/queue/LinkedListQueue/linkedlistqueue.go +++ b/queue/LinkedListQueue/linkedlistqueue.go @@ -1,6 +1,8 @@ package linkedlistqueue import ( + "iter" + linkedlist "github.com/hmcalister/Go-DSA/list/LinkedList" dsa_error "github.com/hmcalister/Go-DSA/utils/DSA_Error" ) @@ -158,3 +160,17 @@ func ReverseMap[T any](queue *LinkedListQueue[T], f func(item T) T) { func ReverseFold[T any, G any](queue *LinkedListQueue[T], initialAccumulator G, f func(item T, accumulator G) G) G { return linkedlist.ReverseFold(queue.queueData, initialAccumulator, f) } + +// Iterate over the items of the queue in the forward direction (front to back). +// Returns both the index (from the front of the queue) and item. +// This method is not concurrency safe. For concurrent applications, consider using a mutex, or pull the data out using Items(). +func (queue *LinkedListQueue[T]) ForwardIterator() iter.Seq2[int, T] { + return queue.queueData.ForwardIterator() +} + +// Iterate over the items of the queue in the reverse direction (top to bottom). +// Returns both the index from the back of the queue) and item. +// This method is not concurrency safe. For concurrent applications, consider using a mutex, or pull the data out using Items(). +func (queue *LinkedListQueue[T]) ReverseIterator() iter.Seq2[int, T] { + return queue.queueData.ReverseIterator() +} From c944b68f0e4ff567e07d0359735e49ce7863c1de Mon Sep 17 00:00:00 2001 From: Hayden McAlister Date: Fri, 13 Dec 2024 16:16:54 +1300 Subject: [PATCH 04/25] Add ForwardIterator and ReverseIterator method tests to linked list queue --- .../linkedlistqueue_apply_test.go | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/queue/LinkedListQueue/linkedlistqueue_apply_test.go b/queue/LinkedListQueue/linkedlistqueue_apply_test.go index 4f54c1f..440c4b0 100644 --- a/queue/LinkedListQueue/linkedlistqueue_apply_test.go +++ b/queue/LinkedListQueue/linkedlistqueue_apply_test.go @@ -120,3 +120,48 @@ func TestReverseFold(t *testing.T) { t.Errorf("result (%v) does not match expected result (%v)", concatString, expectedConcatString) } } + +func TestForwardIterator(t *testing.T) { + queue := linkedlistqueue.New[int]() + items := []int{1, 2, 3, 4, 5, 6, 7, 8, 9} + for _, item := range items { + queue.Add(item) + } + + sum := 0 + for index, item := range queue.ForwardIterator() { + sum += index * item + } + + expectedSum := 0 + for index, item := range items { + expectedSum += index * item + } + + if sum != expectedSum { + t.Errorf("result (%v) does not match expected result (%v)", sum, expectedSum) + } +} + +func TestReverseIterator(t *testing.T) { + queue := linkedlistqueue.New[int]() + items := []int{1, 2, 3, 4, 5, 6, 7, 8, 9} + for _, item := range items { + queue.Add(item) + } + + sum := 0 + for index, item := range queue.ReverseIterator() { + sum += index * item + } + + slices.Reverse(items) + expectedSum := 0 + for index, item := range items { + expectedSum += index * item + } + + if sum != expectedSum { + t.Errorf("result (%v) does not match expected result (%v)", sum, expectedSum) + } +} From 09d1a3a3d0f841b729072e09305c3c3f76c3f8da Mon Sep 17 00:00:00 2001 From: Hayden McAlister Date: Fri, 13 Dec 2024 16:17:02 +1300 Subject: [PATCH 05/25] Add ForwardIterator and ReverseIterator methods to linked list stack --- stack/LinkedListStack/linkedliststack.go | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/stack/LinkedListStack/linkedliststack.go b/stack/LinkedListStack/linkedliststack.go index 0fa354d..141c0e3 100644 --- a/stack/LinkedListStack/linkedliststack.go +++ b/stack/LinkedListStack/linkedliststack.go @@ -1,6 +1,8 @@ package linkedliststack import ( + "iter" + linkedlist "github.com/hmcalister/Go-DSA/list/LinkedList" dsa_error "github.com/hmcalister/Go-DSA/utils/DSA_Error" ) @@ -159,3 +161,17 @@ func ReverseMap[T any](stack *LinkedListStack[T], f func(item T) T) { func ReverseFold[T any, G any](stack *LinkedListStack[T], initialAccumulator G, f func(item T, accumulator G) G) G { return linkedlist.ReverseFold(stack.stackData, initialAccumulator, f) } + +// Iterate over the items of the stack in the forward direction (bottom to top). +// Returns both the index (as counted from the bottom of the stack) and item. +// This method is not concurrency safe. For concurrent applications, consider using a mutex, or pull the data out using Items(). +func (stack *LinkedListStack[T]) ForwardIterator() iter.Seq2[int, T] { + return stack.stackData.ForwardIterator() +} + +// Iterate over the items of the stack in the reverse direction (top to bottom). +// Returns both the index (as counted from the top of the stack) and item. +// This method is not concurrency safe. For concurrent applications, consider using a mutex, or pull the data out using Items(). +func (stack *LinkedListStack[T]) ReverseIterator() iter.Seq2[int, T] { + return stack.stackData.ReverseIterator() +} From 96963971ec672cd505640c5ec2c7009bb99c0ced Mon Sep 17 00:00:00 2001 From: Hayden McAlister Date: Fri, 13 Dec 2024 16:17:08 +1300 Subject: [PATCH 06/25] Add ForwardIterator and ReverseIterator method tests to linked list stack --- .../linkedliststack_apply_test.go | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/stack/LinkedListStack/linkedliststack_apply_test.go b/stack/LinkedListStack/linkedliststack_apply_test.go index 91152e8..5cabe35 100644 --- a/stack/LinkedListStack/linkedliststack_apply_test.go +++ b/stack/LinkedListStack/linkedliststack_apply_test.go @@ -120,3 +120,48 @@ func TestReverseFold(t *testing.T) { t.Errorf("result (%v) does not match expected result (%v)", concatString, expectedConcatString) } } + +func TestForwardIterator(t *testing.T) { + stack := linkedliststack.New[int]() + items := []int{1, 2, 3, 4, 5, 6, 7, 8, 9} + for _, item := range items { + stack.Add(item) + } + + sum := 0 + for index, item := range stack.ForwardIterator() { + sum += index * item + } + + expectedSum := 0 + for index, item := range items { + expectedSum += index * item + } + + if sum != expectedSum { + t.Errorf("result (%v) does not match expected result (%v)", sum, expectedSum) + } +} + +func TestReverseIterator(t *testing.T) { + stack := linkedliststack.New[int]() + items := []int{1, 2, 3, 4, 5, 6, 7, 8, 9} + for _, item := range items { + stack.Add(item) + } + + sum := 0 + for index, item := range stack.ReverseIterator() { + sum += index * item + } + + slices.Reverse(items) + expectedSum := 0 + for index, item := range items { + expectedSum += index * item + } + + if sum != expectedSum { + t.Errorf("result (%v) does not match expected result (%v)", sum, expectedSum) + } +} From 0fced04e59e81d1fb87c1772b57cf0cdb6109cb6 Mon Sep 17 00:00:00 2001 From: Hayden McAlister Date: Fri, 13 Dec 2024 16:17:23 +1300 Subject: [PATCH 07/25] Add Iterator method to hashset --- set/HashSet/hashset.go | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/set/HashSet/hashset.go b/set/HashSet/hashset.go index 61b44a9..0e3ce97 100644 --- a/set/HashSet/hashset.go +++ b/set/HashSet/hashset.go @@ -1,5 +1,7 @@ package hashset +import "iter" + // An implementation of a set using maps as the underlying data structure. type HashSet[T comparable] struct { setData map[T]interface{} @@ -85,3 +87,15 @@ func Fold[T comparable, G any](set *HashSet[T], initialAccumulator G, f func(ite return accumulator } + +// Iterate over the items of the hashset. Note the iteration order may not be the insertion order. +// This method is not concurrency safe. For concurrent applications, consider using a mutex, or pull the data out using Items(). +func (set *HashSet[T]) Iterator() iter.Seq[T] { + return func(yield func(T) bool) { + for item := range set.setData { + if !yield(item) { + return + } + } + } +} From ebb180c070ae8d855f72433ee9d47724293b3c2b Mon Sep 17 00:00:00 2001 From: Hayden McAlister Date: Fri, 13 Dec 2024 16:17:28 +1300 Subject: [PATCH 08/25] Add Iterator method tests to hashset --- set/HashSet/hashset_apply_test.go | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/set/HashSet/hashset_apply_test.go b/set/HashSet/hashset_apply_test.go index d0391e6..63d6523 100644 --- a/set/HashSet/hashset_apply_test.go +++ b/set/HashSet/hashset_apply_test.go @@ -45,3 +45,25 @@ func TestFold(t *testing.T) { t.Errorf("result (%v) does not match expected result (%v)", sum, expectedSum) } } + +func TestIterator(t *testing.T) { + set := hashset.New[int]() + items := []int{1, 2, 3, 4, 5, 6, 7, 8, 9} + for _, item := range items { + set.Add(item) + } + + sum := 0 + for item := range set.Iterator() { + sum += item + } + + expectedSum := 0 + for _, item := range items { + expectedSum += item + } + + if sum != expectedSum { + t.Errorf("result (%v) does not match expected result (%v)", sum, expectedSum) + } +} From 9b2ec182310d784956477e1070c6ee581b270390 Mon Sep 17 00:00:00 2001 From: Hayden McAlister Date: Sat, 14 Dec 2024 02:13:37 +1300 Subject: [PATCH 09/25] Add forward and reverse iterators to array stack --- stack/ArrayStack/arraystack.go | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/stack/ArrayStack/arraystack.go b/stack/ArrayStack/arraystack.go index 07c5207..d5ad468 100644 --- a/stack/ArrayStack/arraystack.go +++ b/stack/ArrayStack/arraystack.go @@ -1,6 +1,10 @@ package arraystack -import dsa_error "github.com/hmcalister/Go-DSA/utils/DSA_Error" +import ( + "iter" + + dsa_error "github.com/hmcalister/Go-DSA/utils/DSA_Error" +) // Implement a stack using a array (slice) as the backing data structure. // @@ -181,3 +185,31 @@ func ReverseFold[T any, G any](stack *ArrayStack[T], initialAccumulator G, f fun return accumulator } + +// Iterate over the items of the stack in the forward direction (bottom to top). +// Returns both the index (as counted from the bottom of the stack) and item. +// This method is not concurrency safe. For concurrent applications, consider using a mutex, or pull the data out using Items(). +func (stack *ArrayStack[T]) ForwardIterator() iter.Seq2[int, T] { + return func(yield func(int, T) bool) { + for index := 0; index < len(stack.stackData); index += 1 { + item := stack.stackData[index] + if !yield(index, item) { + break + } + } + } +} + +// Iterate over the items of the stack in the reverse direction (top to bottom). +// Returns both the index (as counted from the top of the stack) and item. +// This method is not concurrency safe. For concurrent applications, consider using a mutex, or pull the data out using Items(). +func (stack *ArrayStack[T]) ReverseIterator() iter.Seq2[int, T] { + return func(yield func(int, T) bool) { + for index := 0; index < len(stack.stackData); index += 1 { + item := stack.stackData[len(stack.stackData)-index-1] + if !yield(index, item) { + break + } + } + } +} From 94fd1b8992a8676a3a383e4620d7070209d938bc Mon Sep 17 00:00:00 2001 From: Hayden McAlister Date: Sat, 14 Dec 2024 02:13:44 +1300 Subject: [PATCH 10/25] Add forward and reverse iterator tests to array stack --- stack/ArrayStack/arraystack_apply_test.go | 45 +++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/stack/ArrayStack/arraystack_apply_test.go b/stack/ArrayStack/arraystack_apply_test.go index 0fb36df..7a37e19 100644 --- a/stack/ArrayStack/arraystack_apply_test.go +++ b/stack/ArrayStack/arraystack_apply_test.go @@ -120,3 +120,48 @@ func TestReverseFold(t *testing.T) { t.Errorf("result (%v) does not match expected result (%v)", concatString, expectedConcatString) } } + +func TestForwardIterator(t *testing.T) { + stack := arraystack.New[int]() + items := []int{1, 2, 3, 4, 5, 6, 7, 8, 9} + for _, item := range items { + stack.Add(item) + } + + sum := 0 + for index, item := range stack.ForwardIterator() { + sum += index * item + } + + expectedSum := 0 + for index, item := range items { + expectedSum += index * item + } + + if sum != expectedSum { + t.Errorf("result (%v) does not match expected result (%v)", sum, expectedSum) + } +} + +func TestReverseIterator(t *testing.T) { + stack := arraystack.New[int]() + items := []int{1, 2, 3, 4, 5, 6, 7, 8, 9} + for _, item := range items { + stack.Add(item) + } + + sum := 0 + for index, item := range stack.ReverseIterator() { + sum += index * item + } + + slices.Reverse(items) + expectedSum := 0 + for index, item := range items { + expectedSum += index * item + } + + if sum != expectedSum { + t.Errorf("result (%v) does not match expected result (%v)", sum, expectedSum) + } +} From 804e4776459f6eaa1c7124b20be2e1fa900c0308 Mon Sep 17 00:00:00 2001 From: Hayden McAlister Date: Sat, 14 Dec 2024 02:14:56 +1300 Subject: [PATCH 11/25] Add forward and reverse iterators to array queue --- queue/ArrayQueue/arrayqueue.go | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/queue/ArrayQueue/arrayqueue.go b/queue/ArrayQueue/arrayqueue.go index 81f3895..f45fdef 100644 --- a/queue/ArrayQueue/arrayqueue.go +++ b/queue/ArrayQueue/arrayqueue.go @@ -1,6 +1,8 @@ package arrayqueue import ( + "iter" + dsa_error "github.com/hmcalister/Go-DSA/utils/DSA_Error" ) @@ -181,3 +183,31 @@ func ReverseFold[T any, G any](queue *ArrayQueue[T], initialAccumulator G, f fun return accumulator } + +// Iterate over the items of the queue in the forward direction (front to back). +// Returns both the index (as counted from the front of the queue) and item. +// This method is not concurrency safe. For concurrent applications, consider using a mutex, or pull the data out using Items(). +func (queue *ArrayQueue[T]) ForwardIterator() iter.Seq2[int, T] { + return func(yield func(int, T) bool) { + for index := 0; index < len(queue.queueData); index += 1 { + item := queue.queueData[index] + if !yield(index, item) { + break + } + } + } +} + +// Iterate over the items of the queue in the reverse direction (back to front). +// Returns both the index (as counted from the back of the queue) and item. +// This method is not concurrency safe. For concurrent applications, consider using a mutex, or pull the data out using Items(). +func (queue *ArrayQueue[T]) ReverseIterator() iter.Seq2[int, T] { + return func(yield func(int, T) bool) { + for index := 0; index < len(queue.queueData); index += 1 { + item := queue.queueData[len(queue.queueData)-index-1] + if !yield(index, item) { + break + } + } + } +} From 4219cdc964cc6322c194ff1d357c3862043aaed3 Mon Sep 17 00:00:00 2001 From: Hayden McAlister Date: Sat, 14 Dec 2024 02:15:01 +1300 Subject: [PATCH 12/25] Add forward and reverse iterator tests to array queue --- queue/ArrayQueue/arrayqueue_apply_test.go | 45 +++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/queue/ArrayQueue/arrayqueue_apply_test.go b/queue/ArrayQueue/arrayqueue_apply_test.go index aea8a07..add8369 100644 --- a/queue/ArrayQueue/arrayqueue_apply_test.go +++ b/queue/ArrayQueue/arrayqueue_apply_test.go @@ -120,3 +120,48 @@ func TestReverseFold(t *testing.T) { t.Errorf("result (%v) does not match expected result (%v)", concatString, expectedConcatString) } } + +func TestForwardIterator(t *testing.T) { + queue := arrayqueue.New[int]() + items := []int{1, 2, 3, 4, 5, 6, 7, 8, 9} + for _, item := range items { + queue.Add(item) + } + + sum := 0 + for index, item := range queue.ForwardIterator() { + sum += index * item + } + + expectedSum := 0 + for index, item := range items { + expectedSum += index * item + } + + if sum != expectedSum { + t.Errorf("result (%v) does not match expected result (%v)", sum, expectedSum) + } +} + +func TestReverseIterator(t *testing.T) { + queue := arrayqueue.New[int]() + items := []int{1, 2, 3, 4, 5, 6, 7, 8, 9} + for _, item := range items { + queue.Add(item) + } + + sum := 0 + for index, item := range queue.ReverseIterator() { + sum += index * item + } + + slices.Reverse(items) + expectedSum := 0 + for index, item := range items { + expectedSum += index * item + } + + if sum != expectedSum { + t.Errorf("result (%v) does not match expected result (%v)", sum, expectedSum) + } +} From de219e739a76d1e73139b611e87e464e98ffae4f Mon Sep 17 00:00:00 2001 From: Hayden McAlister Date: Sat, 14 Dec 2024 02:20:11 +1300 Subject: [PATCH 13/25] Add iterator method to min binary heap --- heap/MinBinaryHeap/minBinaryHeap.go | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/heap/MinBinaryHeap/minBinaryHeap.go b/heap/MinBinaryHeap/minBinaryHeap.go index cc3cc72..0cd62d3 100644 --- a/heap/MinBinaryHeap/minBinaryHeap.go +++ b/heap/MinBinaryHeap/minBinaryHeap.go @@ -1,6 +1,8 @@ package minbinaryheap import ( + "iter" + comparator "github.com/hmcalister/Go-DSA/utils/Comparator" dsa_error "github.com/hmcalister/Go-DSA/utils/DSA_Error" ) @@ -249,3 +251,22 @@ func Fold[T any, G any](heap *MinBinaryHeap[T], initialAccumulator G, f func(ite return accumulator } + +// Iterate over the items of the heap. +// In case it matters, the iteration is effectively in "reading order" along the heap. +// This is *not* a sorted order. To iterate in sorted order you may either extract the heap items with Items() and sort, +// or continually pop items from the heap (which will naturally update the heap). +// +// If you are updating items in the heap, please note this method does *not* reheapify. +// +// This method is not concurrency safe. For concurrent applications, consider using a mutex, or pull the data out using Items(). +func (heap *MinBinaryHeap[T]) Iterator() iter.Seq[T] { + return func(yield func(T) bool) { + for index := 0; index < len(heap.heapData); index += 1 { + item := heap.heapData[index] + if !yield(item) { + break + } + } + } +} From 8494549b6481e19136c738968d9eb7a8ba4e0b24 Mon Sep 17 00:00:00 2001 From: Hayden McAlister Date: Sat, 14 Dec 2024 02:20:15 +1300 Subject: [PATCH 14/25] Add iterator method test to min binary heap --- .../MinBinaryHeap/minBinaryHeap_apply_test.go | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/heap/MinBinaryHeap/minBinaryHeap_apply_test.go b/heap/MinBinaryHeap/minBinaryHeap_apply_test.go index 1233404..c04941f 100644 --- a/heap/MinBinaryHeap/minBinaryHeap_apply_test.go +++ b/heap/MinBinaryHeap/minBinaryHeap_apply_test.go @@ -27,6 +27,7 @@ func TestMinBinaryHeapApply(t *testing.T) { t.Errorf("result (%v) does not match expected result (%v)", concatString, expectedConcatString) } } + func TestMinBinaryHeapMap(t *testing.T) { heap := minbinaryheap.New[string](comparator.DefaultStringComparator) items := []string{"a", "b", "c", "d", "e", "f", "g", "h"} @@ -78,3 +79,25 @@ func TestMinBinaryHeapFold(t *testing.T) { t.Errorf("expected all items to be contained in ground truth array") } } + +func TestMinBinaryIterator(t *testing.T) { + heap := minbinaryheap.New[string](comparator.DefaultStringComparator) + items := []string{"a", "b", "c", "d", "e", "f", "g", "h"} + for _, item := range items { + heap.Add(item) + } + + concatString := "" + for item := range heap.Iterator() { + concatString += item + } + + expectedConcatString := "" + for _, item := range items { + expectedConcatString += item + } + + if concatString != expectedConcatString { + t.Errorf("result (%v) does not match expected result (%v)", concatString, expectedConcatString) + } +} From 74d9696a4c1bebc4ea7f6f5867a9d59aace5d50c Mon Sep 17 00:00:00 2001 From: Hayden McAlister Date: Sat, 14 Dec 2024 02:21:24 +1300 Subject: [PATCH 15/25] Add iterator method to max binary heap --- heap/MaxBinaryHeap/maxBinaryHeap.go | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/heap/MaxBinaryHeap/maxBinaryHeap.go b/heap/MaxBinaryHeap/maxBinaryHeap.go index 7ca72bc..3015ddf 100644 --- a/heap/MaxBinaryHeap/maxBinaryHeap.go +++ b/heap/MaxBinaryHeap/maxBinaryHeap.go @@ -1,6 +1,8 @@ package maxbinaryheap import ( + "iter" + comparator "github.com/hmcalister/Go-DSA/utils/Comparator" dsa_error "github.com/hmcalister/Go-DSA/utils/DSA_Error" ) @@ -249,3 +251,22 @@ func Fold[T any, G any](heap *MaxBinaryHeap[T], initialAccumulator G, f func(ite return accumulator } + +// Iterate over the items of the heap. +// In case it matters, the iteration is effectively in "reading order" along the heap. +// This is *not* a sorted order. To iterate in sorted order you may either extract the heap items with Items() and sort, +// or continually pop items from the heap (which will naturally update the heap). +// +// If you are updating items in the heap, please note this method does *not* reheapify. +// +// This method is not concurrency safe. For concurrent applications, consider using a mutex, or pull the data out using Items(). +func (heap *MaxBinaryHeap[T]) Iterator() iter.Seq[T] { + return func(yield func(T) bool) { + for index := 0; index < len(heap.heapData); index += 1 { + item := heap.heapData[index] + if !yield(item) { + break + } + } + } +} From be8fbf0ff0b651dd4541628d9a2d5b6a22d4f4d8 Mon Sep 17 00:00:00 2001 From: Hayden McAlister Date: Sat, 14 Dec 2024 02:21:28 +1300 Subject: [PATCH 16/25] Add iterator method test to max binary heap --- heap/MaxBinaryHeap/maxBinaryHeap_apply_test.go | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/heap/MaxBinaryHeap/maxBinaryHeap_apply_test.go b/heap/MaxBinaryHeap/maxBinaryHeap_apply_test.go index 34bac83..dc8606e 100644 --- a/heap/MaxBinaryHeap/maxBinaryHeap_apply_test.go +++ b/heap/MaxBinaryHeap/maxBinaryHeap_apply_test.go @@ -70,3 +70,16 @@ func TestMaxBinaryHeapFold(t *testing.T) { t.Errorf("expected all items to be contained in ground truth array") } } + +func TestMaxBinaryIterator(t *testing.T) { + heap := maxbinaryheap.New[string](comparator.DefaultStringComparator) + items := []string{"a", "b", "c", "d", "e", "f", "g", "h"} + for _, item := range items { + heap.Add(item) + } + + concatString := "" + for item := range heap.Iterator() { + concatString += item + } +} From ee7295fdfed0c5a89b5d36bb3ae15969aed8c212 Mon Sep 17 00:00:00 2001 From: Hayden McAlister Date: Sat, 14 Dec 2024 02:25:24 +1300 Subject: [PATCH 17/25] Add iterator method to priority queue --- queue/PriorityQueue/priorityqueue.go | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/queue/PriorityQueue/priorityqueue.go b/queue/PriorityQueue/priorityqueue.go index 5649d58..b461a6c 100644 --- a/queue/PriorityQueue/priorityqueue.go +++ b/queue/PriorityQueue/priorityqueue.go @@ -1,6 +1,8 @@ package priorityqueue import ( + "iter" + minbinaryheap "github.com/hmcalister/Go-DSA/heap/MinBinaryHeap" comparator "github.com/hmcalister/Go-DSA/utils/Comparator" dsa_error "github.com/hmcalister/Go-DSA/utils/DSA_Error" @@ -161,3 +163,15 @@ func Map[T any](queue *PriorityQueue[T], f func(item T) T) { func Fold[T any, G any](queue *PriorityQueue[T], initialAccumulator G, f func(item T, accumulator G) G) G { return minbinaryheap.Fold(queue.queueData, initialAccumulator, f) } + +// Iterate over the items of the queue. +// +// BEWARE: Iteration order is not the same as priority order! +// To iterate in priority order, use Items() and sort by priority. +// +// If you are updating items in the queue, please note this method does *not* reheapify. +// +// This method is not concurrency safe. For concurrent applications, consider using a mutex, or pull the data out using Items(). +func (queue *PriorityQueue[T]) Iterator() iter.Seq[T] { + return queue.queueData.Iterator() +} From 1fb24650605591c9aa30c71196f1484f4b5b7149 Mon Sep 17 00:00:00 2001 From: Hayden McAlister Date: Sat, 14 Dec 2024 02:25:28 +1300 Subject: [PATCH 18/25] Add iterator method test to priority queue --- .../priority_queue_apply_test.go | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/queue/PriorityQueue/priority_queue_apply_test.go b/queue/PriorityQueue/priority_queue_apply_test.go index c35573d..7909360 100644 --- a/queue/PriorityQueue/priority_queue_apply_test.go +++ b/queue/PriorityQueue/priority_queue_apply_test.go @@ -27,6 +27,7 @@ func TestPriorityQueueApply(t *testing.T) { t.Errorf("result (%v) does not match expected result (%v)", concatString, expectedConcatString) } } + func TestPriorityQueueMap(t *testing.T) { queue := priorityqueue.New[string](comparator.DefaultStringComparator) items := []string{"a", "b", "c", "d", "e", "f", "g", "h"} @@ -78,3 +79,25 @@ func TestPriorityQueueFold(t *testing.T) { t.Errorf("expected all items to be contained in ground truth array") } } + +func TestPriorityQueueIterator(t *testing.T) { + queue := priorityqueue.New[string](comparator.DefaultStringComparator) + items := []string{"a", "b", "c", "d", "e", "f", "g", "h"} + for _, item := range items { + queue.Add(item) + } + + concatString := "" + for item := range queue.Iterator() { + concatString += item + } + + expectedConcatString := "" + for _, item := range items { + expectedConcatString += item + } + + if concatString != expectedConcatString { + t.Errorf("result (%v) does not match expected result (%v)", concatString, expectedConcatString) + } +} From 4f57aa1f36915a6c8140ba100f89fc4e721c81f5 Mon Sep 17 00:00:00 2001 From: Hayden McAlister Date: Sat, 14 Dec 2024 03:22:30 +1300 Subject: [PATCH 19/25] Add preorder, inorder, and postorder iterator to binary search tree --- tree/BinarySearchTree/binaryserachtree.go | 36 ++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/tree/BinarySearchTree/binaryserachtree.go b/tree/BinarySearchTree/binaryserachtree.go index a634c21..b0bcaf6 100644 --- a/tree/BinarySearchTree/binaryserachtree.go +++ b/tree/BinarySearchTree/binaryserachtree.go @@ -1,6 +1,8 @@ package binarysearchtree import ( + "iter" + comparator "github.com/hmcalister/Go-DSA/utils/Comparator" dsa_error "github.com/hmcalister/Go-DSA/utils/DSA_Error" ) @@ -32,7 +34,6 @@ func (tree *BinarySearchTree[T]) Root() *BinarySearchTreeNode[T] { return tree.root } -// ---------------------------------------------------------------------------- // Find Methods // Determines if a given item is present in the tree. @@ -145,6 +146,39 @@ func FoldTreePostorder[T, G any](tree *BinarySearchTree[T], initialAccumulator G return FoldNodePostorder(tree.root, initialAccumulator, f) } +// ---------------------------------------------------------------------------- +// Iterator Methods + +// Iterate over the tree Preorder. +// +// This method is a wrapper for IteratorNodePreorder(tree.root) +func IteratorTreePreorder[T any](tree *BinarySearchTree[T]) iter.Seq[T] { + if tree.root == nil { + return func(yield func(T) bool) {} + } + return IteratorNodePreorder(tree.root) +} + +// Iterate over the tree Inorder. +// +// This method is a wrapper for IteratorNodeInorder(tree.root) +func IteratorTreeInorder[T any](tree *BinarySearchTree[T]) iter.Seq[T] { + if tree.root == nil { + return func(yield func(T) bool) {} + } + return IteratorNodeInorder(tree.root) +} + +// Iterate over the tree Postorder. +// +// This method is a wrapper for IteratorNodePostorder(tree.root) +func IteratorTreePostorder[T any](tree *BinarySearchTree[T]) iter.Seq[T] { + if tree.root == nil { + return func(yield func(T) bool) {} + } + return IteratorNodePostorder(tree.root) +} + // ---------------------------------------------------------------------------- // Add Methods From 8a377bc28a5ac10fb96f5b77723c6c8f1f4895a0 Mon Sep 17 00:00:00 2001 From: Hayden McAlister Date: Sat, 14 Dec 2024 03:22:32 +1300 Subject: [PATCH 20/25] Add preorder, inorder, and postorder iterator to binary search tree node --- tree/BinarySearchTree/node.go | 82 +++++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) diff --git a/tree/BinarySearchTree/node.go b/tree/BinarySearchTree/node.go index 0e61fd7..737c158 100644 --- a/tree/BinarySearchTree/node.go +++ b/tree/BinarySearchTree/node.go @@ -1,5 +1,9 @@ package binarysearchtree +import ( + "iter" +) + type BinarySearchTreeNode[T any] struct { // The item of this node item T @@ -237,3 +241,81 @@ func FoldNodePostorder[T, G any](node *BinarySearchTreeNode[T], initialAccumulat return currentAccumulator } + +// ---------------------------------------------------------------------------- +// Iterator Methods + +// Iterate over each node in a tree Preorder. +// +// Apply should not change the item in a Node, as this could affect the binary tree structure. +func IteratorNodePreorder[T any](node *BinarySearchTreeNode[T]) iter.Seq[T] { + return func(yield func(T) bool) { + if node == nil { + return + } + + if !yield(node.item) { + return + } + for item := range IteratorNodePreorder(node.left) { + if !yield(item) { + return + } + } + for item := range IteratorNodePreorder(node.right) { + if !yield(item) { + return + } + } + } +} + +// Iterate over each node in a tree Inorder. +// +// Apply should not change the item in a Node, as this could affect the binary tree structure. +func IteratorNodeInorder[T any](node *BinarySearchTreeNode[T]) iter.Seq[T] { + return func(yield func(T) bool) { + if node == nil { + return + } + + for item := range IteratorNodeInorder(node.left) { + if !yield(item) { + return + } + } + if !yield(node.item) { + return + } + for item := range IteratorNodeInorder(node.right) { + if !yield(item) { + return + } + } + } +} + +// Iterate over each node in a tree Postorder. +// +// Apply should not change the item in a Node, as this could affect the binary tree structure. +func IteratorNodePostorder[T any](node *BinarySearchTreeNode[T]) iter.Seq[T] { + return func(yield func(T) bool) { + if node == nil { + return + } + + for item := range IteratorNodePostorder(node.left) { + if !yield(item) { + return + } + } + for item := range IteratorNodePostorder(node.right) { + if !yield(item) { + return + } + } + if !yield(node.item) { + return + } + } +} From bba3cde3a3843bb36c2e4d121fa7a20c37d7c91e Mon Sep 17 00:00:00 2001 From: Hayden McAlister Date: Sat, 14 Dec 2024 03:22:43 +1300 Subject: [PATCH 21/25] Add preorder, inorder, and postorder iterator tests to binary search tree --- .../binarysearchtree_misc_test.go | 72 +++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/tree/BinarySearchTree/binarysearchtree_misc_test.go b/tree/BinarySearchTree/binarysearchtree_misc_test.go index 70ead8e..3b4c699 100644 --- a/tree/BinarySearchTree/binarysearchtree_misc_test.go +++ b/tree/BinarySearchTree/binarysearchtree_misc_test.go @@ -1,6 +1,7 @@ package binarysearchtree_test import ( + "iter" "slices" "testing" @@ -53,3 +54,74 @@ func TestBinarySearchTreeItems(t *testing.T) { } } } + +func TestBinarySearchTreeIterators(t *testing.T) { + // We will construct this tree + // 5 + // / \ + // 3 7 + // / \ / \ + // 1 4 6 9 + + items := []int{5, 3, 7, 1, 4, 6, 9} + tree := binarysearchtree.New[int](comparator.DefaultIntegerComparator) + for _, item := range items { + tree.Add(item) + } + + testNodeIteratorMethod := func(t *testing.T, iteratorMethod func(*binarysearchtree.BinarySearchTreeNode[int]) iter.Seq[int], iteratorDescriptor string, expectedOrder []int) { + foundOrder := make([]int, 0) + for item := range iteratorMethod(tree.Root()) { + foundOrder = append(foundOrder, item) + } + + if !slices.Equal(expectedOrder, foundOrder) { + t.Errorf("%v iterator: expected order %v does not match found order %v", iteratorDescriptor, expectedOrder, foundOrder) + } + } + + testTreeIteratorMethod := func(t *testing.T, iteratorMethod func(*binarysearchtree.BinarySearchTree[int]) iter.Seq[int], iteratorDescriptor string, expectedOrder []int) { + foundOrder := make([]int, 0) + for item := range iteratorMethod(tree) { + foundOrder = append(foundOrder, item) + } + + if !slices.Equal(expectedOrder, foundOrder) { + t.Errorf("%v iterator: expected order %v does not match found order %v", iteratorDescriptor, expectedOrder, foundOrder) + } + } + + var expectedOrder []int + + // Pre-Order + expectedOrder = []int{5, 3, 1, 4, 7, 6, 9} + testNodeIteratorMethod(t, binarysearchtree.IteratorNodePreorder, "node preorder", expectedOrder) + testTreeIteratorMethod(t, binarysearchtree.IteratorTreePreorder, "tree preorder", expectedOrder) + + // In-Order + expectedOrder = []int{1, 3, 4, 5, 6, 7, 9} + testNodeIteratorMethod(t, binarysearchtree.IteratorNodeInorder, "node inorder", expectedOrder) + testTreeIteratorMethod(t, binarysearchtree.IteratorTreeInorder, "tree inorder", expectedOrder) + + // Post-Order + expectedOrder = []int{1, 4, 3, 6, 9, 7, 5} + testNodeIteratorMethod(t, binarysearchtree.IteratorNodePostorder, "node postorder", expectedOrder) + testTreeIteratorMethod(t, binarysearchtree.IteratorTreePostorder, "tree postorder", expectedOrder) +} + +func TestBinarySearchTreeLargeIterator(t *testing.T) { + const MAX_ITEM = 4096 + tree := binarysearchtree.New[int](comparator.DefaultIntegerComparator) + for i := 0; i < MAX_ITEM; i += 1 { + tree.Add(i) + } + + expectedItem := 0 + for item := range binarysearchtree.IteratorNodeInorder(tree.Root()) { + if expectedItem != item { + t.Errorf("expected item %v does not match found item %v", expectedItem, item) + return + } + expectedItem += 1 + } +} From 6d9270b7e353f400baaa400447dcaad6bd7b16dc Mon Sep 17 00:00:00 2001 From: Hayden McAlister Date: Sat, 14 Dec 2024 03:23:47 +1300 Subject: [PATCH 22/25] Update documentation of iterator methods for BST node --- tree/BinarySearchTree/node.go | 6 ------ 1 file changed, 6 deletions(-) diff --git a/tree/BinarySearchTree/node.go b/tree/BinarySearchTree/node.go index 737c158..bf64c1b 100644 --- a/tree/BinarySearchTree/node.go +++ b/tree/BinarySearchTree/node.go @@ -246,8 +246,6 @@ func FoldNodePostorder[T, G any](node *BinarySearchTreeNode[T], initialAccumulat // Iterator Methods // Iterate over each node in a tree Preorder. -// -// Apply should not change the item in a Node, as this could affect the binary tree structure. func IteratorNodePreorder[T any](node *BinarySearchTreeNode[T]) iter.Seq[T] { return func(yield func(T) bool) { if node == nil { @@ -271,8 +269,6 @@ func IteratorNodePreorder[T any](node *BinarySearchTreeNode[T]) iter.Seq[T] { } // Iterate over each node in a tree Inorder. -// -// Apply should not change the item in a Node, as this could affect the binary tree structure. func IteratorNodeInorder[T any](node *BinarySearchTreeNode[T]) iter.Seq[T] { return func(yield func(T) bool) { if node == nil { @@ -296,8 +292,6 @@ func IteratorNodeInorder[T any](node *BinarySearchTreeNode[T]) iter.Seq[T] { } // Iterate over each node in a tree Postorder. -// -// Apply should not change the item in a Node, as this could affect the binary tree structure. func IteratorNodePostorder[T any](node *BinarySearchTreeNode[T]) iter.Seq[T] { return func(yield func(T) bool) { if node == nil { From 8199240d87e5d95a5924edaa1caf936fded0bc7e Mon Sep 17 00:00:00 2001 From: Hayden McAlister Date: Sat, 14 Dec 2024 03:26:01 +1300 Subject: [PATCH 23/25] Add preorder, inorder, and postorder iterator to red black tree --- tree/RedBlackTree/redblacktree.go | 35 +++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/tree/RedBlackTree/redblacktree.go b/tree/RedBlackTree/redblacktree.go index dd48b01..859f501 100644 --- a/tree/RedBlackTree/redblacktree.go +++ b/tree/RedBlackTree/redblacktree.go @@ -1,6 +1,8 @@ package redblacktree import ( + "iter" + comparator "github.com/hmcalister/Go-DSA/utils/Comparator" dsa_error "github.com/hmcalister/Go-DSA/utils/DSA_Error" ) @@ -278,6 +280,39 @@ func FoldTreePostorder[T, G any](tree *RedBlackTree[T], initialAccumulator G, f return FoldNodePostorder(tree.root, initialAccumulator, f) } +// ---------------------------------------------------------------------------- +// Iterator Methods + +// Iterate over the tree Preorder. +// +// This method is a wrapper for IteratorNodePreorder(tree.root) +func IteratorTreePreorder[T any](tree *RedBlackTree[T]) iter.Seq[T] { + if tree.root == nil { + return func(yield func(T) bool) {} + } + return IteratorNodePreorder(tree.root) +} + +// Iterate over the tree Inorder. +// +// This method is a wrapper for IteratorNodeInorder(tree.root) +func IteratorTreeInorder[T any](tree *RedBlackTree[T]) iter.Seq[T] { + if tree.root == nil { + return func(yield func(T) bool) {} + } + return IteratorNodeInorder(tree.root) +} + +// Iterate over the tree Postorder. +// +// This method is a wrapper for IteratorNodePostorder(tree.root) +func IteratorTreePostorder[T any](tree *RedBlackTree[T]) iter.Seq[T] { + if tree.root == nil { + return func(yield func(T) bool) {} + } + return IteratorNodePostorder(tree.root) +} + // ---------------------------------------------------------------------------- // Add Methods From d8b6a398a5db7b555487af51fd6887bd36628085 Mon Sep 17 00:00:00 2001 From: Hayden McAlister Date: Sat, 14 Dec 2024 03:26:03 +1300 Subject: [PATCH 24/25] Add preorder, inorder, and postorder iterator to red black tree node --- tree/RedBlackTree/node.go | 74 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/tree/RedBlackTree/node.go b/tree/RedBlackTree/node.go index fd27ffc..eea7406 100644 --- a/tree/RedBlackTree/node.go +++ b/tree/RedBlackTree/node.go @@ -1,5 +1,7 @@ package redblacktree +import "iter" + type colorEnum int const ( @@ -298,3 +300,75 @@ func FoldNodePostorder[T, G any](node *RedBlackTreeNode[T], initialAccumulator G return currentAccumulator } + +// ---------------------------------------------------------------------------- +// Iterator Methods + +// Iterate over each node in a tree Preorder. +func IteratorNodePreorder[T any](node *RedBlackTreeNode[T]) iter.Seq[T] { + return func(yield func(T) bool) { + if node == nil { + return + } + + if !yield(node.item) { + return + } + for item := range IteratorNodePreorder(node.left) { + if !yield(item) { + return + } + } + for item := range IteratorNodePreorder(node.right) { + if !yield(item) { + return + } + } + } +} + +// Iterate over each node in a tree Inorder. +func IteratorNodeInorder[T any](node *RedBlackTreeNode[T]) iter.Seq[T] { + return func(yield func(T) bool) { + if node == nil { + return + } + + for item := range IteratorNodeInorder(node.left) { + if !yield(item) { + return + } + } + if !yield(node.item) { + return + } + for item := range IteratorNodeInorder(node.right) { + if !yield(item) { + return + } + } + } +} + +// Iterate over each node in a tree Postorder. +func IteratorNodePostorder[T any](node *RedBlackTreeNode[T]) iter.Seq[T] { + return func(yield func(T) bool) { + if node == nil { + return + } + + for item := range IteratorNodePostorder(node.left) { + if !yield(item) { + return + } + } + for item := range IteratorNodePostorder(node.right) { + if !yield(item) { + return + } + } + if !yield(node.item) { + return + } + } +} From 3e127d655e72abd2896091cef66bfbf780d42c05 Mon Sep 17 00:00:00 2001 From: Hayden McAlister Date: Sat, 14 Dec 2024 03:26:10 +1300 Subject: [PATCH 25/25] Add preorder, inorder, and postorder iterator tests to red black tree --- tree/RedBlackTree/redblacktree_misc_test.go | 72 +++++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/tree/RedBlackTree/redblacktree_misc_test.go b/tree/RedBlackTree/redblacktree_misc_test.go index 6aa2b26..d010749 100644 --- a/tree/RedBlackTree/redblacktree_misc_test.go +++ b/tree/RedBlackTree/redblacktree_misc_test.go @@ -1,6 +1,7 @@ package redblacktree_test import ( + "iter" "slices" "testing" @@ -53,3 +54,74 @@ func TestRedBlackTreeItems(t *testing.T) { } } } + +func TestRedBlackTreeIterators(t *testing.T) { + // We will construct this tree + // 5 + // / \ + // 3 7 + // / \ / \ + // 1 4 6 9 + + items := []int{5, 3, 7, 1, 4, 6, 9} + tree := redblacktree.New[int](comparator.DefaultIntegerComparator) + for _, item := range items { + tree.Add(item) + } + + testNodeIteratorMethod := func(t *testing.T, iteratorMethod func(*redblacktree.RedBlackTreeNode[int]) iter.Seq[int], iteratorDescriptor string, expectedOrder []int) { + foundOrder := make([]int, 0) + for item := range iteratorMethod(tree.Root()) { + foundOrder = append(foundOrder, item) + } + + if !slices.Equal(expectedOrder, foundOrder) { + t.Errorf("%v iterator: expected order %v does not match found order %v", iteratorDescriptor, expectedOrder, foundOrder) + } + } + + testTreeIteratorMethod := func(t *testing.T, iteratorMethod func(*redblacktree.RedBlackTree[int]) iter.Seq[int], iteratorDescriptor string, expectedOrder []int) { + foundOrder := make([]int, 0) + for item := range iteratorMethod(tree) { + foundOrder = append(foundOrder, item) + } + + if !slices.Equal(expectedOrder, foundOrder) { + t.Errorf("%v iterator: expected order %v does not match found order %v", iteratorDescriptor, expectedOrder, foundOrder) + } + } + + var expectedOrder []int + + // Pre-Order + expectedOrder = []int{5, 3, 1, 4, 7, 6, 9} + testNodeIteratorMethod(t, redblacktree.IteratorNodePreorder, "node preorder", expectedOrder) + testTreeIteratorMethod(t, redblacktree.IteratorTreePreorder, "tree preorder", expectedOrder) + + // In-Order + expectedOrder = []int{1, 3, 4, 5, 6, 7, 9} + testNodeIteratorMethod(t, redblacktree.IteratorNodeInorder, "node inorder", expectedOrder) + testTreeIteratorMethod(t, redblacktree.IteratorTreeInorder, "tree inorder", expectedOrder) + + // Post-Order + expectedOrder = []int{1, 4, 3, 6, 9, 7, 5} + testNodeIteratorMethod(t, redblacktree.IteratorNodePostorder, "node postorder", expectedOrder) + testTreeIteratorMethod(t, redblacktree.IteratorTreePostorder, "tree postorder", expectedOrder) +} + +func TestRedBlackTreeLargeIterator(t *testing.T) { + const MAX_ITEM = 4096 + tree := redblacktree.New[int](comparator.DefaultIntegerComparator) + for i := 0; i < MAX_ITEM; i += 1 { + tree.Add(i) + } + + expectedItem := 0 + for item := range redblacktree.IteratorNodeInorder(tree.Root()) { + if expectedItem != item { + t.Errorf("expected item %v does not match found item %v", expectedItem, item) + return + } + expectedItem += 1 + } +}