From 7a0cce72c741db918fa927d13a666a5c75ab0cf7 Mon Sep 17 00:00:00 2001 From: Alokzh Date: Fri, 27 Jun 2025 08:09:33 +0530 Subject: [PATCH 01/11] Implemented `addAll:` & `do:` methods with tests --- .../CTBinarySearchTreeTest.class.st | 34 +++++++++++-------- .../CTBSTNode.class.st | 5 +-- .../CTBinarySearchTree.class.st | 16 ++++++++- 3 files changed, 37 insertions(+), 18 deletions(-) diff --git a/src/Containers-BinarySearchTree-Tests/CTBinarySearchTreeTest.class.st b/src/Containers-BinarySearchTree-Tests/CTBinarySearchTreeTest.class.st index 9f9112b..14d3eeb 100644 --- a/src/Containers-BinarySearchTree-Tests/CTBinarySearchTreeTest.class.st +++ b/src/Containers-BinarySearchTree-Tests/CTBinarySearchTreeTest.class.st @@ -20,9 +20,8 @@ CTBinarySearchTreeTest >> setUp [ { #category : 'tests' } CTBinarySearchTreeTest >> testAddMultipleElements [ - tree add: 50. - tree add: 30. - tree add: 70. + tree addAll: #(50 30 70). + self assert: tree size equals: 3 ] @@ -34,6 +33,17 @@ CTBinarySearchTreeTest >> testAddSingleElement [ self assert: tree size equals: 1 ] +{ #category : 'tests' } +CTBinarySearchTreeTest >> testDuplicateHandling [ + + tree addAll: #( 42 42 50 ). + + self assert: tree size equals: 2. + + self assert: (tree includes: 42). + self assert: (tree includes: 50) +] + { #category : 'tests' } CTBinarySearchTreeTest >> testEmpty [ @@ -49,26 +59,20 @@ CTBinarySearchTreeTest >> testHeight [ tree add: 50. self assert: tree height equals: 1. - tree add: 30. - self assert: tree height equals: 2. - - tree add: 70. + tree addAll: #(30 70). self assert: tree height equals: 2 ] { #category : 'tests' } CTBinarySearchTreeTest >> testInOrderTraversal [ - | result | - tree add: 50. - tree add: 30. - tree add: 70. - tree add: 20. - tree add: 40. - + | result | + tree addAll: #(50 30 70 20 40). + result := OrderedCollection new. tree inOrderDo: [ :each | result add: each ]. - self assert: result asArray equals: #( 20 30 40 50 70 ) + + self assert: result asArray equals: #(20 30 40 50 70) ] { #category : 'tests' } diff --git a/src/Containers-BinarySearchTree/CTBSTNode.class.st b/src/Containers-BinarySearchTree/CTBSTNode.class.st index 00a26c7..770a5c9 100644 --- a/src/Containers-BinarySearchTree/CTBSTNode.class.st +++ b/src/Containers-BinarySearchTree/CTBSTNode.class.st @@ -18,8 +18,9 @@ CTBSTNode >> addChild: anObject [ anObject < contents ifTrue: [ left := left addChild: anObject ] - ifFalse: [ anObject > contents - ifTrue: [ right := right addChild: anObject ] ]. + ifFalse: [ + anObject > contents + ifTrue: [ right := right addChild: anObject ] ]. ^ self ] diff --git a/src/Containers-BinarySearchTree/CTBinarySearchTree.class.st b/src/Containers-BinarySearchTree/CTBinarySearchTree.class.st index 19df61e..4fa5bd1 100644 --- a/src/Containers-BinarySearchTree/CTBinarySearchTree.class.st +++ b/src/Containers-BinarySearchTree/CTBinarySearchTree.class.st @@ -18,10 +18,24 @@ CTBinarySearchTree >> add: anObject [ ^ anObject ] +{ #category : 'adding' } +CTBinarySearchTree >> addAll: aCollection [ + + aCollection do: [ :each | self add: each ]. + ^ aCollection +] + +{ #category : 'enumerating' } +CTBinarySearchTree >> do: aBlock [ + + "Alias for inOrderDo: - visits elements in sorted order" + self inOrderDo: aBlock +] + { #category : 'accessing' } CTBinarySearchTree >> height [ - ^ root height + ^ root isEmpty ifTrue: [ 0 ] ifFalse: [ root height ] ] { #category : 'enumerating' } From e5025477788eee1591f21cd92288d9b6e83bc65f Mon Sep 17 00:00:00 2001 From: Alokzh Date: Fri, 27 Jun 2025 14:39:54 +0530 Subject: [PATCH 02/11] Implemented findMin and findMax operations --- .../CTBinarySearchTreeTest.class.st | 17 ++++++++++++----- .../CTBSTAbstractNode.class.st | 12 ++++++++++++ .../CTBSTNillNode.class.st | 12 ++++++++++++ .../CTBSTNode.class.st | 16 ++++++++++++++++ .../CTBinarySearchTree.class.st | 16 ++++++++++++++++ 5 files changed, 68 insertions(+), 5 deletions(-) diff --git a/src/Containers-BinarySearchTree-Tests/CTBinarySearchTreeTest.class.st b/src/Containers-BinarySearchTree-Tests/CTBinarySearchTreeTest.class.st index 14d3eeb..4faea12 100644 --- a/src/Containers-BinarySearchTree-Tests/CTBinarySearchTreeTest.class.st +++ b/src/Containers-BinarySearchTree-Tests/CTBinarySearchTreeTest.class.st @@ -51,6 +51,15 @@ CTBinarySearchTreeTest >> testEmpty [ self assert: tree size equals: 0 ] +{ #category : 'tests' } +CTBinarySearchTreeTest >> testFindMinMax [ + + tree addAll: #(50 30 70 20 80). + + self assert: tree findMin equals: 20. + self assert: tree findMax equals: 80 +] + { #category : 'tests' } CTBinarySearchTreeTest >> testHeight [ @@ -78,14 +87,12 @@ CTBinarySearchTreeTest >> testInOrderTraversal [ { #category : 'tests' } CTBinarySearchTreeTest >> testIncludes [ - tree add: 50. - tree add: 30. - tree add: 70. + tree addAll: #(50 30 70 20 40). self assert: (tree includes: 50). self assert: (tree includes: 30). - self assert: (tree includes: 70). - self deny: (tree includes: 99) + self deny: (tree includes: 99). + self deny: (tree includes: 25) ] { #category : 'tests' } diff --git a/src/Containers-BinarySearchTree/CTBSTAbstractNode.class.st b/src/Containers-BinarySearchTree/CTBSTAbstractNode.class.st index 8487891..3cb4681 100644 --- a/src/Containers-BinarySearchTree/CTBSTAbstractNode.class.st +++ b/src/Containers-BinarySearchTree/CTBSTAbstractNode.class.st @@ -29,6 +29,18 @@ CTBSTAbstractNode >> contents: anObject [ self subclassResponsibility ] +{ #category : 'searching' } +CTBSTAbstractNode >> findMax [ + + ^ self subclassResponsibility +] + +{ #category : 'searching' } +CTBSTAbstractNode >> findMin [ + + ^ self subclassResponsibility +] + { #category : 'accessing' } CTBSTAbstractNode >> height [ diff --git a/src/Containers-BinarySearchTree/CTBSTNillNode.class.st b/src/Containers-BinarySearchTree/CTBSTNillNode.class.st index 808139a..8b00e17 100644 --- a/src/Containers-BinarySearchTree/CTBSTNillNode.class.st +++ b/src/Containers-BinarySearchTree/CTBSTNillNode.class.st @@ -29,6 +29,18 @@ CTBSTNillNode >> contents: anObject [ "Do nothing for nil node" ] +{ #category : 'searching' } +CTBSTNillNode >> findMax [ + + ^ nil +] + +{ #category : 'searching' } +CTBSTNillNode >> findMin [ + + ^ nil +] + { #category : 'accessing' } CTBSTNillNode >> height [ diff --git a/src/Containers-BinarySearchTree/CTBSTNode.class.st b/src/Containers-BinarySearchTree/CTBSTNode.class.st index 770a5c9..1d887fb 100644 --- a/src/Containers-BinarySearchTree/CTBSTNode.class.st +++ b/src/Containers-BinarySearchTree/CTBSTNode.class.st @@ -36,6 +36,22 @@ CTBSTNode >> contents: anObject [ contents := anObject ] +{ #category : 'searching' } +CTBSTNode >> findMax [ + + ^ right isEmpty + ifTrue: [ contents ] + ifFalse: [ right findMax ] +] + +{ #category : 'searching' } +CTBSTNode >> findMin [ + + ^ left isEmpty + ifTrue: [ contents ] + ifFalse: [ left findMin ] +] + { #category : 'accessing' } CTBSTNode >> height [ diff --git a/src/Containers-BinarySearchTree/CTBinarySearchTree.class.st b/src/Containers-BinarySearchTree/CTBinarySearchTree.class.st index 4fa5bd1..8b0df5c 100644 --- a/src/Containers-BinarySearchTree/CTBinarySearchTree.class.st +++ b/src/Containers-BinarySearchTree/CTBinarySearchTree.class.st @@ -32,6 +32,22 @@ CTBinarySearchTree >> do: aBlock [ self inOrderDo: aBlock ] +{ #category : 'searching' } +CTBinarySearchTree >> findMax [ + + ^ self isEmpty + ifTrue: [ nil ] + ifFalse: [ root findMax ] +] + +{ #category : 'searching' } +CTBinarySearchTree >> findMin [ + + ^ self isEmpty + ifTrue: [ nil ] + ifFalse: [ root findMin ] +] + { #category : 'accessing' } CTBinarySearchTree >> height [ From 0b73cb1d6b43940acd69c1e974900c2251ad36df Mon Sep 17 00:00:00 2001 From: Alokzh Date: Sat, 28 Jun 2025 08:53:31 +0530 Subject: [PATCH 03/11] Implemented collection protocol methods (`collect:`, `select:`, `detect:`) --- .../CTBinarySearchTreeTest.class.st | 37 ++++++++++++++++ .../CTBinarySearchTree.class.st | 43 +++++++++++++++++++ 2 files changed, 80 insertions(+) diff --git a/src/Containers-BinarySearchTree-Tests/CTBinarySearchTreeTest.class.st b/src/Containers-BinarySearchTree-Tests/CTBinarySearchTreeTest.class.st index 4faea12..b44b537 100644 --- a/src/Containers-BinarySearchTree-Tests/CTBinarySearchTreeTest.class.st +++ b/src/Containers-BinarySearchTree-Tests/CTBinarySearchTreeTest.class.st @@ -33,6 +33,43 @@ CTBinarySearchTreeTest >> testAddSingleElement [ self assert: tree size equals: 1 ] +{ #category : 'tests' } +CTBinarySearchTreeTest >> testAsArray [ + + + | result | + tree addAll: #(50 30 70 20 40). + + result := tree asArray. + self assert: result equals: #(20 30 40 50 70) +] + +{ #category : 'tests' } +CTBinarySearchTreeTest >> testClear [ + + tree addAll: #(1 2 3 4 5). + tree clear. + + self assert: tree isEmpty. + self assert: tree size equals: 0 +] + +{ #category : 'tests' } +CTBinarySearchTreeTest >> testCollectionMethods [ + + | doubled evens found | + tree addAll: #(50 30 70 20 40). + + doubled := tree collect: [ :each | each * 2 ]. + self assert: doubled asArray equals: #(40 60 80 100 140). + + evens := tree select: [ :each | each even ]. + self assert: evens asArray equals: #(20 30 40 50 70). + + found := tree detect: [ :each | each > 45 ] ifNone: [ nil ]. + self assert: found equals: 50 +] + { #category : 'tests' } CTBinarySearchTreeTest >> testDuplicateHandling [ diff --git a/src/Containers-BinarySearchTree/CTBinarySearchTree.class.st b/src/Containers-BinarySearchTree/CTBinarySearchTree.class.st index 8b0df5c..cb7d591 100644 --- a/src/Containers-BinarySearchTree/CTBinarySearchTree.class.st +++ b/src/Containers-BinarySearchTree/CTBinarySearchTree.class.st @@ -25,6 +25,40 @@ CTBinarySearchTree >> addAll: aCollection [ ^ aCollection ] +{ #category : 'converting' } +CTBinarySearchTree >> asArray [ + + | result | + result := OrderedCollection new. + self inOrderDo: [ :each | result add: each ]. + ^ result asArray +] + +{ #category : 'removing' } +CTBinarySearchTree >> clear [ + + root := CTBSTNillNode new +] + +{ #category : 'enumerating' } +CTBinarySearchTree >> collect: aBlock [ + + | result | + result := OrderedCollection new. + self inOrderDo: [ :each | result add: (aBlock value: each) ]. + ^ result + +] + +{ #category : 'enumerating' } +CTBinarySearchTree >> detect: aBlock ifNone: absentBlock [ + + self inOrderDo: [ :each | + (aBlock value: each) ifTrue: [ ^ each ] + ]. + ^ absentBlock value +] + { #category : 'enumerating' } CTBinarySearchTree >> do: aBlock [ @@ -85,6 +119,15 @@ CTBinarySearchTree >> root [ ^ root isEmpty ifTrue: [ nil ] ifFalse: [ root ] ] +{ #category : 'enumerating' } +CTBinarySearchTree >> select: aBlock [ + + | result | + result := OrderedCollection new. + self inOrderDo: [ :each | (aBlock value: each) ifTrue: [ result add: each ] ]. + ^ result +] + { #category : 'accessing' } CTBinarySearchTree >> size [ From a17b4f069b6719011fff98023809f7511699fd2c Mon Sep 17 00:00:00 2001 From: Alokzh Date: Mon, 30 Jun 2025 08:37:16 +0530 Subject: [PATCH 04/11] Implemented complete removal operations --- .../CTBinarySearchTreeTest.class.st | 59 +++++++++++++++++++ .../CTBSTAbstractNode.class.st | 6 ++ .../CTBSTNillNode.class.st | 7 +++ .../CTBSTNode.class.st | 37 ++++++++++++ .../CTBinarySearchTree.class.st | 27 +++++++++ 5 files changed, 136 insertions(+) diff --git a/src/Containers-BinarySearchTree-Tests/CTBinarySearchTreeTest.class.st b/src/Containers-BinarySearchTree-Tests/CTBinarySearchTreeTest.class.st index b44b537..c52f720 100644 --- a/src/Containers-BinarySearchTree-Tests/CTBinarySearchTreeTest.class.st +++ b/src/Containers-BinarySearchTree-Tests/CTBinarySearchTreeTest.class.st @@ -142,3 +142,62 @@ CTBinarySearchTreeTest >> testIsLeaf [ self deny: tree root isLeaf. self assert: tree root left isLeaf ] + +{ #category : 'tests' } +CTBinarySearchTreeTest >> testRemoveLeafNode [ + + tree addAll: #(50 30 70 20). + + tree remove: 20. + self assert: tree size equals: 3. + self deny: (tree includes: 20) +] + +{ #category : 'tests' } +CTBinarySearchTreeTest >> testRemoveNodeWithOneChild [ + + tree addAll: #( 50 30 20 ). + + tree remove: 30. + self assert: tree size equals: 2. + self deny: (tree includes: 30). + self assert: (tree includes: 20) +] + +{ #category : 'tests' } +CTBinarySearchTreeTest >> testRemoveNodeWithTwoChildren [ + + tree addAll: #(50 30 70 20 40). + + tree remove: 30. + self assert: tree size equals: 4. + self deny: (tree includes: 30) +] + +{ #category : 'tests' } +CTBinarySearchTreeTest >> testRemoveNonExistentElement [ + + | result | + + tree addAll: #(50 30 70). + result := tree remove: 99 ifAbsent: [ #notFound ]. + self assert: result equals: #notFound. + self assert: tree size equals: 3. + + self should: [ tree remove: 99 ] raise: Error +] + +{ #category : 'tests' } +CTBinarySearchTreeTest >> testRemoveRoot [ + "Root with no children" + tree add: 50. + tree remove: 50. + self assert: tree isEmpty. + + "Root with two children" + tree clear. + tree addAll: #(50 30 70 20 40 60 80). + tree remove: 50. + self assert: tree size equals: 6. + self deny: (tree includes: 50). +] diff --git a/src/Containers-BinarySearchTree/CTBSTAbstractNode.class.st b/src/Containers-BinarySearchTree/CTBSTAbstractNode.class.st index 3cb4681..56b1619 100644 --- a/src/Containers-BinarySearchTree/CTBSTAbstractNode.class.st +++ b/src/Containers-BinarySearchTree/CTBSTAbstractNode.class.st @@ -77,6 +77,12 @@ CTBSTAbstractNode >> parent: aNode [ parent := aNode ] +{ #category : 'removing' } +CTBSTAbstractNode >> removeValue: anObject [ + + ^ self subclassResponsibility +] + { #category : 'accessing' } CTBSTAbstractNode >> search: anObject [ diff --git a/src/Containers-BinarySearchTree/CTBSTNillNode.class.st b/src/Containers-BinarySearchTree/CTBSTNillNode.class.st index 8b00e17..0f3e0af 100644 --- a/src/Containers-BinarySearchTree/CTBSTNillNode.class.st +++ b/src/Containers-BinarySearchTree/CTBSTNillNode.class.st @@ -65,6 +65,13 @@ CTBSTNillNode >> isLeaf [ ^ false ] +{ #category : 'removing' } +CTBSTNillNode >> removeValue: anObject [ + + "Element not found - return self unchanged" + ^ self +] + { #category : 'accessing' } CTBSTNillNode >> search: anObject [ diff --git a/src/Containers-BinarySearchTree/CTBSTNode.class.st b/src/Containers-BinarySearchTree/CTBSTNode.class.st index 1d887fb..33e6e78 100644 --- a/src/Containers-BinarySearchTree/CTBSTNode.class.st +++ b/src/Containers-BinarySearchTree/CTBSTNode.class.st @@ -99,6 +99,43 @@ CTBSTNode >> left: aNode [ aNode parent: self ] +{ #category : 'removing' } +CTBSTNode >> removeThisNode [ + + "Remove this node and return replacement using standard BST algorithm" + | successorValue | + "Case 1: Leaf node (no children)" + (left isEmpty and: [ right isEmpty ]) + ifTrue: [ ^ CTBSTNillNode new ]. + + "Case 2: Only one child" + left isEmpty ifTrue: [ ^ right ]. + right isEmpty ifTrue: [ ^ left ]. + + "Case 3: Two children - replace with inorder successor" + successorValue := right findMin. + contents := successorValue. + right := right removeValue: successorValue. + ^ self +] + +{ #category : 'removing' } +CTBSTNode >> removeValue: anObject [ + + "Remove node with anObject value and return the new subtree root" + + anObject < contents ifTrue: [ + left := left removeValue: anObject. + ^ self ]. + + anObject > contents ifTrue: [ + right := right removeValue: anObject. + ^ self ]. + + "Found the node to remove" + ^ self removeThisNode +] + { #category : 'accessing' } CTBSTNode >> right [ diff --git a/src/Containers-BinarySearchTree/CTBinarySearchTree.class.st b/src/Containers-BinarySearchTree/CTBinarySearchTree.class.st index cb7d591..c13dd42 100644 --- a/src/Containers-BinarySearchTree/CTBinarySearchTree.class.st +++ b/src/Containers-BinarySearchTree/CTBinarySearchTree.class.st @@ -113,6 +113,33 @@ CTBinarySearchTree >> isEmpty [ ^ root isEmpty ] +{ #category : 'removing' } +CTBinarySearchTree >> remove: anObject [ + + ^ self + remove: anObject + ifAbsent: [ + self error: 'Element not found: ' , anObject printString ] +] + +{ #category : 'removing' } +CTBinarySearchTree >> remove: anObject ifAbsent: aBlock [ + + | originalSize | + originalSize := self size. + root := root removeValue: anObject. + ^ originalSize = self size + ifTrue: [ aBlock value ] + ifFalse: [ anObject ] +] + +{ #category : 'removing' } +CTBinarySearchTree >> removeAll: aCollection [ + + aCollection do: [ :each | self remove: each ifAbsent: [ ] ]. + ^ aCollection +] + { #category : 'accessing' } CTBinarySearchTree >> root [ From ad86aec1ba71cea8579ee4fba190ceba6da7612a Mon Sep 17 00:00:00 2001 From: Alokzh Date: Tue, 1 Jul 2025 07:47:47 +0530 Subject: [PATCH 05/11] Implemented `preOrderDo:` & `postOrderDo:` traversal methods --- .../CTBinarySearchTreeTest.class.st | 25 +++++++++++++++++++ .../CTBSTAbstractNode.class.st | 12 +++++++++ .../CTBSTNillNode.class.st | 12 +++++++++ .../CTBSTNode.class.st | 16 ++++++++++++ .../CTBinarySearchTree.class.st | 14 +++++++++++ 5 files changed, 79 insertions(+) diff --git a/src/Containers-BinarySearchTree-Tests/CTBinarySearchTreeTest.class.st b/src/Containers-BinarySearchTree-Tests/CTBinarySearchTreeTest.class.st index c52f720..3c546e8 100644 --- a/src/Containers-BinarySearchTree-Tests/CTBinarySearchTreeTest.class.st +++ b/src/Containers-BinarySearchTree-Tests/CTBinarySearchTreeTest.class.st @@ -143,6 +143,31 @@ CTBinarySearchTreeTest >> testIsLeaf [ self assert: tree root left isLeaf ] +{ #category : 'tests' } +CTBinarySearchTreeTest >> testPostOrderTraversal [ + + | result | + tree addAll: #( 50 30 70 20 ). + + result := OrderedCollection new. + tree postOrderDo: [ :each | result add: each ]. + + self assert: result last equals: 50. + self assert: result asArray equals: #( 20 30 70 50 ) +] + +{ #category : 'tests' } +CTBinarySearchTreeTest >> testPreOrderTraversal [ + + | result | + tree addAll: #( 50 30 70 20 ). + + result := OrderedCollection new. + tree preOrderDo: [ :each | result add: each ]. + self assert: result first equals: 50. + self assert: result asArray equals: #(50 30 20 70) +] + { #category : 'tests' } CTBinarySearchTreeTest >> testRemoveLeafNode [ diff --git a/src/Containers-BinarySearchTree/CTBSTAbstractNode.class.st b/src/Containers-BinarySearchTree/CTBSTAbstractNode.class.st index 56b1619..39a5720 100644 --- a/src/Containers-BinarySearchTree/CTBSTAbstractNode.class.st +++ b/src/Containers-BinarySearchTree/CTBSTAbstractNode.class.st @@ -77,6 +77,18 @@ CTBSTAbstractNode >> parent: aNode [ parent := aNode ] +{ #category : 'enumerating' } +CTBSTAbstractNode >> postOrderDo: aBlock [ + + ^ self subclassResponsibility +] + +{ #category : 'enumerating' } +CTBSTAbstractNode >> preOrderDo: aBlock [ + + ^ self subclassResponsibility +] + { #category : 'removing' } CTBSTAbstractNode >> removeValue: anObject [ diff --git a/src/Containers-BinarySearchTree/CTBSTNillNode.class.st b/src/Containers-BinarySearchTree/CTBSTNillNode.class.st index 0f3e0af..5ec6300 100644 --- a/src/Containers-BinarySearchTree/CTBSTNillNode.class.st +++ b/src/Containers-BinarySearchTree/CTBSTNillNode.class.st @@ -65,6 +65,18 @@ CTBSTNillNode >> isLeaf [ ^ false ] +{ #category : 'enumerating' } +CTBSTNillNode >> postOrderDo: aBlock [ + + "Do nothing for nill node" +] + +{ #category : 'enumerating' } +CTBSTNillNode >> preOrderDo: aBlock [ + + "Do nothing for nill node" +] + { #category : 'removing' } CTBSTNillNode >> removeValue: anObject [ diff --git a/src/Containers-BinarySearchTree/CTBSTNode.class.st b/src/Containers-BinarySearchTree/CTBSTNode.class.st index 33e6e78..fbf7b64 100644 --- a/src/Containers-BinarySearchTree/CTBSTNode.class.st +++ b/src/Containers-BinarySearchTree/CTBSTNode.class.st @@ -99,6 +99,22 @@ CTBSTNode >> left: aNode [ aNode parent: self ] +{ #category : 'enumerating' } +CTBSTNode >> postOrderDo: aBlock [ + + left postOrderDo: aBlock. + right postOrderDo: aBlock. + aBlock value: contents +] + +{ #category : 'enumerating' } +CTBSTNode >> preOrderDo: aBlock [ + + aBlock value: contents. + left preOrderDo: aBlock. + right preOrderDo: aBlock +] + { #category : 'removing' } CTBSTNode >> removeThisNode [ diff --git a/src/Containers-BinarySearchTree/CTBinarySearchTree.class.st b/src/Containers-BinarySearchTree/CTBinarySearchTree.class.st index c13dd42..ee4f359 100644 --- a/src/Containers-BinarySearchTree/CTBinarySearchTree.class.st +++ b/src/Containers-BinarySearchTree/CTBinarySearchTree.class.st @@ -113,6 +113,20 @@ CTBinarySearchTree >> isEmpty [ ^ root isEmpty ] +{ #category : 'enumerating' } +CTBinarySearchTree >> postOrderDo: aBlock [ + + root postOrderDo: aBlock + + +] + +{ #category : 'enumerating' } +CTBinarySearchTree >> preOrderDo: aBlock [ + + root preOrderDo: aBlock. +] + { #category : 'removing' } CTBinarySearchTree >> remove: anObject [ From b12e78e9bf4a356b165c6faf0ded085d70ad0f46 Mon Sep 17 00:00:00 2001 From: Alokzh Date: Tue, 1 Jul 2025 08:03:43 +0530 Subject: [PATCH 06/11] Added Range Query Method implementation --- .../CTBinarySearchTreeTest.class.st | 17 +++++++++++++++++ .../CTBSTAbstractNode.class.st | 6 ++++++ .../CTBSTNillNode.class.st | 6 ++++++ .../CTBSTNode.class.st | 18 ++++++++++++++++++ .../CTBinarySearchTree.class.st | 10 ++++++++++ 5 files changed, 57 insertions(+) diff --git a/src/Containers-BinarySearchTree-Tests/CTBinarySearchTreeTest.class.st b/src/Containers-BinarySearchTree-Tests/CTBinarySearchTreeTest.class.st index 3c546e8..481579e 100644 --- a/src/Containers-BinarySearchTree-Tests/CTBinarySearchTreeTest.class.st +++ b/src/Containers-BinarySearchTree-Tests/CTBinarySearchTreeTest.class.st @@ -168,6 +168,23 @@ CTBinarySearchTreeTest >> testPreOrderTraversal [ self assert: result asArray equals: #(50 30 20 70) ] +{ #category : 'tests' } +CTBinarySearchTreeTest >> testRangeQuery [ + + | result | + tree addAll: #( 50 30 70 20 40 60 80 ). + + result := tree elementsFrom: 35 to: 65. + self assert: result size equals: 3. + + "Test edge cases" + result := tree elementsFrom: 10 to: 15. + self assert: result isEmpty. + + result := tree elementsFrom: 15 to: 5. "Invalid range" + self assert: result isEmpty +] + { #category : 'tests' } CTBinarySearchTreeTest >> testRemoveLeafNode [ diff --git a/src/Containers-BinarySearchTree/CTBSTAbstractNode.class.st b/src/Containers-BinarySearchTree/CTBSTAbstractNode.class.st index 39a5720..155dc58 100644 --- a/src/Containers-BinarySearchTree/CTBSTAbstractNode.class.st +++ b/src/Containers-BinarySearchTree/CTBSTAbstractNode.class.st @@ -29,6 +29,12 @@ CTBSTAbstractNode >> contents: anObject [ self subclassResponsibility ] +{ #category : 'enumerating' } +CTBSTAbstractNode >> elementsFrom: min to: max into: aCollection [ + + ^ self subclassResponsibility +] + { #category : 'searching' } CTBSTAbstractNode >> findMax [ diff --git a/src/Containers-BinarySearchTree/CTBSTNillNode.class.st b/src/Containers-BinarySearchTree/CTBSTNillNode.class.st index 5ec6300..88ee2ce 100644 --- a/src/Containers-BinarySearchTree/CTBSTNillNode.class.st +++ b/src/Containers-BinarySearchTree/CTBSTNillNode.class.st @@ -29,6 +29,12 @@ CTBSTNillNode >> contents: anObject [ "Do nothing for nil node" ] +{ #category : 'enumerating' } +CTBSTNillNode >> elementsFrom: min to: max into: aCollection [ + + "Do nothing for nill node" +] + { #category : 'searching' } CTBSTNillNode >> findMax [ diff --git a/src/Containers-BinarySearchTree/CTBSTNode.class.st b/src/Containers-BinarySearchTree/CTBSTNode.class.st index fbf7b64..909846f 100644 --- a/src/Containers-BinarySearchTree/CTBSTNode.class.st +++ b/src/Containers-BinarySearchTree/CTBSTNode.class.st @@ -36,6 +36,24 @@ CTBSTNode >> contents: anObject [ contents := anObject ] +{ #category : 'enumerating' } +CTBSTNode >> elementsFrom: min to: max into: aCollection [ + "If current node is greater than max, only check left subtree" + contents > max ifTrue: [ + left elementsFrom: min to: max into: aCollection. + ^ self ]. + + "If current node is less than min, only check right subtree" + contents < min ifTrue: [ + right elementsFrom: min to: max into: aCollection. + ^ self ]. + + "Current node is in range, check both subtrees and include current" + left elementsFrom: min to: max into: aCollection. + aCollection add: contents. + right elementsFrom: min to: max into: aCollection +] + { #category : 'searching' } CTBSTNode >> findMax [ diff --git a/src/Containers-BinarySearchTree/CTBinarySearchTree.class.st b/src/Containers-BinarySearchTree/CTBinarySearchTree.class.st index ee4f359..40a9ed4 100644 --- a/src/Containers-BinarySearchTree/CTBinarySearchTree.class.st +++ b/src/Containers-BinarySearchTree/CTBinarySearchTree.class.st @@ -66,6 +66,16 @@ CTBinarySearchTree >> do: aBlock [ self inOrderDo: aBlock ] +{ #category : 'enumerating' } +CTBinarySearchTree >> elementsFrom: min to: max [ + + | result | + min > max ifTrue: [ ^ #() ]. + result := OrderedCollection new. + root elementsFrom: min to: max into: result. + ^ result +] + { #category : 'searching' } CTBinarySearchTree >> findMax [ From 072b057b42747a0ce9feaa282fd3086d87355af3 Mon Sep 17 00:00:00 2001 From: Alokzh Date: Tue, 1 Jul 2025 08:23:27 +0530 Subject: [PATCH 07/11] Implemented `anySatisfy:` method with its test --- .../CTBinarySearchTreeTest.class.st | 8 ++++++-- .../CTBinarySearchTree.class.st | 9 +++++++++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/Containers-BinarySearchTree-Tests/CTBinarySearchTreeTest.class.st b/src/Containers-BinarySearchTree-Tests/CTBinarySearchTreeTest.class.st index 481579e..8bd6620 100644 --- a/src/Containers-BinarySearchTree-Tests/CTBinarySearchTreeTest.class.st +++ b/src/Containers-BinarySearchTree-Tests/CTBinarySearchTreeTest.class.st @@ -56,9 +56,10 @@ CTBinarySearchTreeTest >> testClear [ { #category : 'tests' } CTBinarySearchTreeTest >> testCollectionMethods [ - + | doubled evens found | tree addAll: #(50 30 70 20 40). + doubled := tree collect: [ :each | each * 2 ]. self assert: doubled asArray equals: #(40 60 80 100 140). @@ -67,7 +68,10 @@ CTBinarySearchTreeTest >> testCollectionMethods [ self assert: evens asArray equals: #(20 30 40 50 70). found := tree detect: [ :each | each > 45 ] ifNone: [ nil ]. - self assert: found equals: 50 + self assert: found equals: 50. + + self assert: (tree anySatisfy: [ :each | each > 60 ]). + self deny: (tree anySatisfy: [ :each | each > 100 ]) ] { #category : 'tests' } diff --git a/src/Containers-BinarySearchTree/CTBinarySearchTree.class.st b/src/Containers-BinarySearchTree/CTBinarySearchTree.class.st index 40a9ed4..5cac7fd 100644 --- a/src/Containers-BinarySearchTree/CTBinarySearchTree.class.st +++ b/src/Containers-BinarySearchTree/CTBinarySearchTree.class.st @@ -25,6 +25,15 @@ CTBinarySearchTree >> addAll: aCollection [ ^ aCollection ] +{ #category : 'enumerating' } +CTBinarySearchTree >> anySatisfy: aBlock [ + + self inOrderDo: [ :each | + (aBlock value: each) ifTrue: [ ^ true ] + ]. + ^ false +] + { #category : 'converting' } CTBinarySearchTree >> asArray [ From 421cea35b499d72f00a02cc73e89171a8d75b7b6 Mon Sep 17 00:00:00 2001 From: Alokzh Date: Wed, 2 Jul 2025 07:24:33 +0530 Subject: [PATCH 08/11] Implemented `predecessorOf:` & `successorOf:` methods --- .../CTBinarySearchTreeTest.class.st | 35 +++++++++++++++++-- .../CTBSTAbstractNode.class.st | 12 +++++++ .../CTBSTNillNode.class.st | 12 +++++++ .../CTBSTNode.class.st | 28 +++++++++++++++ .../CTBinarySearchTree.class.st | 14 ++++++++ 5 files changed, 99 insertions(+), 2 deletions(-) diff --git a/src/Containers-BinarySearchTree-Tests/CTBinarySearchTreeTest.class.st b/src/Containers-BinarySearchTree-Tests/CTBinarySearchTreeTest.class.st index 8bd6620..cddc557 100644 --- a/src/Containers-BinarySearchTree-Tests/CTBinarySearchTreeTest.class.st +++ b/src/Containers-BinarySearchTree-Tests/CTBinarySearchTreeTest.class.st @@ -172,14 +172,35 @@ CTBinarySearchTreeTest >> testPreOrderTraversal [ self assert: result asArray equals: #(50 30 20 70) ] +{ #category : 'tests' } +CTBinarySearchTreeTest >> testPredecessorSuccessorWithNonExistentElement [ + + tree addAll: #( 50 30 70 20 40 60 80 ). + + self assert: (tree predecessorOf: 35) equals: 30. + self assert: (tree successorOf: 35) equals: 40 +] + +{ #category : 'tests' } +CTBinarySearchTreeTest >> testPredecessors [ + + tree addAll: #( 50 30 70 20 40 60 80 ). + + self assert: (tree predecessorOf: 50) equals: 40. + self assert: (tree predecessorOf: 30) equals: 20. + self assert: (tree predecessorOf: 20) isNil +] + { #category : 'tests' } CTBinarySearchTreeTest >> testRangeQuery [ - | result | + | result temp | tree addAll: #( 50 30 70 20 40 60 80 ). result := tree elementsFrom: 35 to: 65. - self assert: result size equals: 3. + temp := result asArray. + self assert: result size equals: 3. + self assert: temp equals: #(40 50 60). "Test edge cases" result := tree elementsFrom: 10 to: 15. @@ -247,3 +268,13 @@ CTBinarySearchTreeTest >> testRemoveRoot [ self assert: tree size equals: 6. self deny: (tree includes: 50). ] + +{ #category : 'tests' } +CTBinarySearchTreeTest >> testSuccessors [ + + tree addAll: #(50 30 70 20 40 60 80). + + self assert: (tree successorOf: 50) equals: 60. + self assert: (tree successorOf: 70) equals: 80. + self assert: (tree successorOf: 80) isNil. +] diff --git a/src/Containers-BinarySearchTree/CTBSTAbstractNode.class.st b/src/Containers-BinarySearchTree/CTBSTAbstractNode.class.st index 155dc58..14e3484 100644 --- a/src/Containers-BinarySearchTree/CTBSTAbstractNode.class.st +++ b/src/Containers-BinarySearchTree/CTBSTAbstractNode.class.st @@ -95,6 +95,12 @@ CTBSTAbstractNode >> preOrderDo: aBlock [ ^ self subclassResponsibility ] +{ #category : 'searching' } +CTBSTAbstractNode >> predecessorOf: anObject [ + + ^ self subclassResponsibility +] + { #category : 'removing' } CTBSTAbstractNode >> removeValue: anObject [ @@ -112,3 +118,9 @@ CTBSTAbstractNode >> size [ ^ self subclassResponsibility ] + +{ #category : 'searching' } +CTBSTAbstractNode >> successorOf: anObject [ + + ^ self subclassResponsibility +] diff --git a/src/Containers-BinarySearchTree/CTBSTNillNode.class.st b/src/Containers-BinarySearchTree/CTBSTNillNode.class.st index 88ee2ce..f5e6663 100644 --- a/src/Containers-BinarySearchTree/CTBSTNillNode.class.st +++ b/src/Containers-BinarySearchTree/CTBSTNillNode.class.st @@ -83,6 +83,12 @@ CTBSTNillNode >> preOrderDo: aBlock [ "Do nothing for nill node" ] +{ #category : 'searching' } +CTBSTNillNode >> predecessorOf: anObject [ + + ^ nil +] + { #category : 'removing' } CTBSTNillNode >> removeValue: anObject [ @@ -101,3 +107,9 @@ CTBSTNillNode >> size [ ^ 0 ] + +{ #category : 'searching' } +CTBSTNillNode >> successorOf: anObject [ + + ^ nil +] diff --git a/src/Containers-BinarySearchTree/CTBSTNode.class.st b/src/Containers-BinarySearchTree/CTBSTNode.class.st index 909846f..53f9f26 100644 --- a/src/Containers-BinarySearchTree/CTBSTNode.class.st +++ b/src/Containers-BinarySearchTree/CTBSTNode.class.st @@ -133,6 +133,20 @@ CTBSTNode >> preOrderDo: aBlock [ right preOrderDo: aBlock ] +{ #category : 'searching' } +CTBSTNode >> predecessorOf: anObject [ + + | rightResult | + "Find the largest element smaller than anObject" + + anObject <= contents ifTrue: [ + ^ left predecessorOf: anObject ]. + + "Current node is potential predecessor, check right subtree for better one" + rightResult := right predecessorOf: anObject. + ^ rightResult ifNil: [ contents ] ifNotNil: [ rightResult ] +] + { #category : 'removing' } CTBSTNode >> removeThisNode [ @@ -197,3 +211,17 @@ CTBSTNode >> size [ ^ 1 + left size + right size ] + +{ #category : 'searching' } +CTBSTNode >> successorOf: anObject [ + + | leftResult | + "Find the smallest element larger than anObject" + + anObject >= contents ifTrue: [ + ^ right successorOf: anObject ]. + + "Current node is potential successor, check left subtree for better one" + leftResult := left successorOf: anObject. + ^ leftResult ifNil: [ contents ] ifNotNil: [ leftResult ] +] diff --git a/src/Containers-BinarySearchTree/CTBinarySearchTree.class.st b/src/Containers-BinarySearchTree/CTBinarySearchTree.class.st index 5cac7fd..de76b4f 100644 --- a/src/Containers-BinarySearchTree/CTBinarySearchTree.class.st +++ b/src/Containers-BinarySearchTree/CTBinarySearchTree.class.st @@ -146,6 +146,13 @@ CTBinarySearchTree >> preOrderDo: aBlock [ root preOrderDo: aBlock. ] +{ #category : 'searching' } +CTBinarySearchTree >> predecessorOf: anObject [ + + "Find the predecessor (largest element smaller than anObject)" + ^ root predecessorOf: anObject +] + { #category : 'removing' } CTBinarySearchTree >> remove: anObject [ @@ -193,3 +200,10 @@ CTBinarySearchTree >> size [ ^ root size ] + +{ #category : 'searching' } +CTBinarySearchTree >> successorOf: anObject [ + + "Find the successor (smallest element larger than anObject)" + ^ root successorOf: anObject +] From 3a8b872f440476ab40062b7b4c5cc9522e44ab9f Mon Sep 17 00:00:00 2001 From: Alokzh Date: Wed, 2 Jul 2025 07:57:37 +0530 Subject: [PATCH 09/11] Implemented `validateBSTProperty` & `copy:` methods --- .../CTBinarySearchTreeTest.class.st | 57 +++++++++++++++++++ .../CTBSTAbstractNode.class.st | 12 ++++ .../CTBSTNillNode.class.st | 12 ++++ .../CTBSTNode.class.st | 17 ++++++ .../CTBinarySearchTree.class.st | 16 ++++++ 5 files changed, 114 insertions(+) diff --git a/src/Containers-BinarySearchTree-Tests/CTBinarySearchTreeTest.class.st b/src/Containers-BinarySearchTree-Tests/CTBinarySearchTreeTest.class.st index cddc557..0458a35 100644 --- a/src/Containers-BinarySearchTree-Tests/CTBinarySearchTreeTest.class.st +++ b/src/Containers-BinarySearchTree-Tests/CTBinarySearchTreeTest.class.st @@ -44,6 +44,21 @@ CTBinarySearchTreeTest >> testAsArray [ self assert: result equals: #(20 30 40 50 70) ] +{ #category : 'tests' } +CTBinarySearchTreeTest >> testBSTValidation [ + + | emptyTree | + emptyTree := CTBinarySearchTree new. + self assert: emptyTree validateBSTProperty. + + tree addAll: #(50 30 70 20 40). + self assert: tree validateBSTProperty. + + "Test after removal" + tree remove: 30. + self assert: tree validateBSTProperty +] + { #category : 'tests' } CTBinarySearchTreeTest >> testClear [ @@ -74,6 +89,21 @@ CTBinarySearchTreeTest >> testCollectionMethods [ self deny: (tree anySatisfy: [ :each | each > 100 ]) ] +{ #category : 'tests' } +CTBinarySearchTreeTest >> testCopy [ + + | copiedTree | + tree addAll: #(50 30 70). + copiedTree := tree copy. + + self assert: copiedTree size equals: tree size. + self assert: copiedTree asArray equals: tree asArray. + + copiedTree add: 99. + self deny: (tree includes: 99). + self assert: (copiedTree includes: 99) +] + { #category : 'tests' } CTBinarySearchTreeTest >> testDuplicateHandling [ @@ -92,6 +122,21 @@ CTBinarySearchTreeTest >> testEmpty [ self assert: tree size equals: 0 ] +{ #category : 'tests' } +CTBinarySearchTreeTest >> testEmptyTreeOperations [ + + | result | + self assert: tree isEmpty. + self assert: tree findMin isNil. + self assert: tree findMax isNil. + self deny: (tree includes: 42). + + result := tree collect: [ :each | each * 2 ]. + self assert: result isEmpty. + + self deny: (tree anySatisfy: [ :each | true ]) +] + { #category : 'tests' } CTBinarySearchTreeTest >> testFindMinMax [ @@ -147,6 +192,18 @@ CTBinarySearchTreeTest >> testIsLeaf [ self assert: tree root left isLeaf ] +{ #category : 'tests' } +CTBinarySearchTreeTest >> testNegativeNumbersTree [ + + | result | + tree addAll: #(-10 -5 0 5 10). + + self assert: tree findMin equals: -10. + self assert: tree findMax equals: 10. + result := tree asArray. + self assert: result equals: #(-10 -5 0 5 10) +] + { #category : 'tests' } CTBinarySearchTreeTest >> testPostOrderTraversal [ diff --git a/src/Containers-BinarySearchTree/CTBSTAbstractNode.class.st b/src/Containers-BinarySearchTree/CTBSTAbstractNode.class.st index 14e3484..235e6eb 100644 --- a/src/Containers-BinarySearchTree/CTBSTAbstractNode.class.st +++ b/src/Containers-BinarySearchTree/CTBSTAbstractNode.class.st @@ -124,3 +124,15 @@ CTBSTAbstractNode >> successorOf: anObject [ ^ self subclassResponsibility ] + +{ #category : 'testing' } +CTBSTAbstractNode >> validateBSTProperty [ + + ^ self subclassResponsibility +] + +{ #category : 'private' } +CTBSTAbstractNode >> validateBSTPropertyWithMin: min max: max [ + + ^ self subclassResponsibility +] diff --git a/src/Containers-BinarySearchTree/CTBSTNillNode.class.st b/src/Containers-BinarySearchTree/CTBSTNillNode.class.st index f5e6663..4f72972 100644 --- a/src/Containers-BinarySearchTree/CTBSTNillNode.class.st +++ b/src/Containers-BinarySearchTree/CTBSTNillNode.class.st @@ -113,3 +113,15 @@ CTBSTNillNode >> successorOf: anObject [ ^ nil ] + +{ #category : 'testing' } +CTBSTNillNode >> validateBSTProperty [ + + ^ true +] + +{ #category : 'private' } +CTBSTNillNode >> validateBSTPropertyWithMin: min max: max [ + + ^ true +] diff --git a/src/Containers-BinarySearchTree/CTBSTNode.class.st b/src/Containers-BinarySearchTree/CTBSTNode.class.st index 53f9f26..3df7742 100644 --- a/src/Containers-BinarySearchTree/CTBSTNode.class.st +++ b/src/Containers-BinarySearchTree/CTBSTNode.class.st @@ -225,3 +225,20 @@ CTBSTNode >> successorOf: anObject [ leftResult := left successorOf: anObject. ^ leftResult ifNil: [ contents ] ifNotNil: [ leftResult ] ] + +{ #category : 'testing' } +CTBSTNode >> validateBSTProperty [ + + "Check if BST property holds: left < node < right" + ^ self validateBSTPropertyWithMin: nil max: nil +] + +{ #category : 'private' } +CTBSTNode >> validateBSTPropertyWithMin: min max: max [ + + (min notNil and: [ contents < min ]) ifTrue: [ ^ false ]. + (max notNil and: [ contents > max ]) ifTrue: [ ^ false ]. + + ^ (left isEmpty or: [ left validateBSTPropertyWithMin: min max: contents ]) + and: [ right isEmpty or: [ right validateBSTPropertyWithMin: contents max: max ] ] +] diff --git a/src/Containers-BinarySearchTree/CTBinarySearchTree.class.st b/src/Containers-BinarySearchTree/CTBinarySearchTree.class.st index de76b4f..ce984e1 100644 --- a/src/Containers-BinarySearchTree/CTBinarySearchTree.class.st +++ b/src/Containers-BinarySearchTree/CTBinarySearchTree.class.st @@ -59,6 +59,15 @@ CTBinarySearchTree >> collect: aBlock [ ] +{ #category : 'copying' } +CTBinarySearchTree >> copy [ + + | newTree | + newTree := self class new. + self inOrderDo: [ :each | newTree add: each ]. + ^ newTree +] + { #category : 'enumerating' } CTBinarySearchTree >> detect: aBlock ifNone: absentBlock [ @@ -207,3 +216,10 @@ CTBinarySearchTree >> successorOf: anObject [ "Find the successor (smallest element larger than anObject)" ^ root successorOf: anObject ] + +{ #category : 'testing' } +CTBinarySearchTree >> validateBSTProperty [ + + "Validate that the tree maintains BST property" + ^ root validateBSTProperty +] From c6012352f3cbc3da4579f5ed8907c6b5bab0ca09 Mon Sep 17 00:00:00 2001 From: Alokzh Date: Wed, 2 Jul 2025 08:37:40 +0530 Subject: [PATCH 10/11] Added `elementsLessThan:` & `elementsGreaterThan:` methods with tests --- .../CTBinarySearchTreeTest.class.st | 44 +++++++++++++++++++ .../CTBSTAbstractNode.class.st | 12 +++++ .../CTBSTNillNode.class.st | 12 +++++ .../CTBSTNode.class.st | 20 +++++++++ .../CTBinarySearchTree.class.st | 18 ++++++++ 5 files changed, 106 insertions(+) diff --git a/src/Containers-BinarySearchTree-Tests/CTBinarySearchTreeTest.class.st b/src/Containers-BinarySearchTree-Tests/CTBinarySearchTreeTest.class.st index 0458a35..d259d08 100644 --- a/src/Containers-BinarySearchTree-Tests/CTBinarySearchTreeTest.class.st +++ b/src/Containers-BinarySearchTree-Tests/CTBinarySearchTreeTest.class.st @@ -104,6 +104,18 @@ CTBinarySearchTreeTest >> testCopy [ self assert: (copiedTree includes: 99) ] +{ #category : 'tests' } +CTBinarySearchTreeTest >> testDoMethod [ + + | result | + tree addAll: #(50 30 70 20 40). + + result := OrderedCollection new. + tree do: [ :each | result add: each ]. + + self assert: result asArray equals: #(20 30 40 50 70) +] + { #category : 'tests' } CTBinarySearchTreeTest >> testDuplicateHandling [ @@ -115,6 +127,38 @@ CTBinarySearchTreeTest >> testDuplicateHandling [ self assert: (tree includes: 50) ] +{ #category : 'tests' } +CTBinarySearchTreeTest >> testElementsGreaterThan [ + + | result | + tree addAll: #(50 30 70 20 40 60 80). + + result := tree elementsGreaterThan: 45. + self assert: result asArray equals: #(50 60 70 80). + + result := tree elementsGreaterThan: 80. + self assert: result isEmpty. + + result := tree elementsGreaterThan: 10. + self assert: result asArray equals: #(20 30 40 50 60 70 80) +] + +{ #category : 'tests' } +CTBinarySearchTreeTest >> testElementsLessThan [ + + | result | + tree addAll: #(50 30 70 20 40 60 80). + + result := tree elementsLessThan: 45. + self assert: result asArray equals: #(20 30 40). + + result := tree elementsLessThan: 20. + self assert: result isEmpty. + + result := tree elementsLessThan: 90. + self assert: result asArray equals: #(20 30 40 50 60 70 80) +] + { #category : 'tests' } CTBinarySearchTreeTest >> testEmpty [ diff --git a/src/Containers-BinarySearchTree/CTBSTAbstractNode.class.st b/src/Containers-BinarySearchTree/CTBSTAbstractNode.class.st index 235e6eb..ec82ac5 100644 --- a/src/Containers-BinarySearchTree/CTBSTAbstractNode.class.st +++ b/src/Containers-BinarySearchTree/CTBSTAbstractNode.class.st @@ -35,6 +35,18 @@ CTBSTAbstractNode >> elementsFrom: min to: max into: aCollection [ ^ self subclassResponsibility ] +{ #category : 'enumerating' } +CTBSTAbstractNode >> elementsGreaterThan: anObject into: aCollection [ + + ^ self subclassResponsibility +] + +{ #category : 'enumerating' } +CTBSTAbstractNode >> elementsLessThan: anObject into: aCollection [ + + ^ self subclassResponsibility +] + { #category : 'searching' } CTBSTAbstractNode >> findMax [ diff --git a/src/Containers-BinarySearchTree/CTBSTNillNode.class.st b/src/Containers-BinarySearchTree/CTBSTNillNode.class.st index 4f72972..6e6611d 100644 --- a/src/Containers-BinarySearchTree/CTBSTNillNode.class.st +++ b/src/Containers-BinarySearchTree/CTBSTNillNode.class.st @@ -35,6 +35,18 @@ CTBSTNillNode >> elementsFrom: min to: max into: aCollection [ "Do nothing for nill node" ] +{ #category : 'enumerating' } +CTBSTNillNode >> elementsGreaterThan: anObject into: aCollection [ + + "Do nothing for nill node" +] + +{ #category : 'enumerating' } +CTBSTNillNode >> elementsLessThan: anObject into: aCollection [ + + "Do nothing for nill node" +] + { #category : 'searching' } CTBSTNillNode >> findMax [ diff --git a/src/Containers-BinarySearchTree/CTBSTNode.class.st b/src/Containers-BinarySearchTree/CTBSTNode.class.st index 3df7742..c55c3bd 100644 --- a/src/Containers-BinarySearchTree/CTBSTNode.class.st +++ b/src/Containers-BinarySearchTree/CTBSTNode.class.st @@ -54,6 +54,26 @@ CTBSTNode >> elementsFrom: min to: max into: aCollection [ right elementsFrom: min to: max into: aCollection ] +{ #category : 'enumerating' } +CTBSTNode >> elementsGreaterThan: anObject into: aCollection [ + + "If current node is greater than target, check left subtree and include current" + contents > anObject ifTrue: [ + left elementsGreaterThan: anObject into: aCollection. + aCollection add: contents ]. + "Always check right subtree" + right elementsGreaterThan: anObject into: aCollection +] + +{ #category : 'enumerating' } +CTBSTNode >> elementsLessThan: anObject into: aCollection [ + + left elementsLessThan: anObject into: aCollection. + contents < anObject ifFalse: [ ^ self ]. + aCollection add: contents. + right elementsLessThan: anObject into: aCollection +] + { #category : 'searching' } CTBSTNode >> findMax [ diff --git a/src/Containers-BinarySearchTree/CTBinarySearchTree.class.st b/src/Containers-BinarySearchTree/CTBinarySearchTree.class.st index ce984e1..bdba471 100644 --- a/src/Containers-BinarySearchTree/CTBinarySearchTree.class.st +++ b/src/Containers-BinarySearchTree/CTBinarySearchTree.class.st @@ -94,6 +94,24 @@ CTBinarySearchTree >> elementsFrom: min to: max [ ^ result ] +{ #category : 'enumerating' } +CTBinarySearchTree >> elementsGreaterThan: anObject [ + + | result | + result := OrderedCollection new. + root elementsGreaterThan: anObject into: result. + ^ result +] + +{ #category : 'enumerating' } +CTBinarySearchTree >> elementsLessThan: anObject [ + + | result | + result := OrderedCollection new. + root elementsLessThan: anObject into: result. + ^ result +] + { #category : 'searching' } CTBinarySearchTree >> findMax [ From 9f04ff9d78b5aba22143ba3fd167f51e1c482896 Mon Sep 17 00:00:00 2001 From: Alokzh Date: Wed, 2 Jul 2025 08:48:40 +0530 Subject: [PATCH 11/11] Added proper description for each class --- .../CTBinarySearchTreeTest.class.st | 6 +++++- .../CTBSTAbstractNode.class.st | 6 +++++- .../CTBSTNillNode.class.st | 6 +++++- src/Containers-BinarySearchTree/CTBSTNode.class.st | 7 ++++++- .../CTBinarySearchTree.class.st | 14 +++++++++++++- 5 files changed, 34 insertions(+), 5 deletions(-) diff --git a/src/Containers-BinarySearchTree-Tests/CTBinarySearchTreeTest.class.st b/src/Containers-BinarySearchTree-Tests/CTBinarySearchTreeTest.class.st index d259d08..df28544 100644 --- a/src/Containers-BinarySearchTree-Tests/CTBinarySearchTreeTest.class.st +++ b/src/Containers-BinarySearchTree-Tests/CTBinarySearchTreeTest.class.st @@ -1,5 +1,9 @@ " -A CTBinarySearchTreeTest is a test class for testing the behavior of CTBinarySearchTree +I test the Binary Search Tree implementation (CTBinarySearchTree). + +I verify correctness of all tree operations including insertion, deletion, search, traversals, and collection protocol methods. I test edge cases like empty trees, single nodes, and complex removal scenarios. + +I ensure the BST maintains its ordering property and handles duplicates correctly. " Class { #name : 'CTBinarySearchTreeTest', diff --git a/src/Containers-BinarySearchTree/CTBSTAbstractNode.class.st b/src/Containers-BinarySearchTree/CTBSTAbstractNode.class.st index ec82ac5..3e8a576 100644 --- a/src/Containers-BinarySearchTree/CTBSTAbstractNode.class.st +++ b/src/Containers-BinarySearchTree/CTBSTAbstractNode.class.st @@ -1,5 +1,9 @@ " -I represent an abstract node for Binary Search Tree. +I am an abstract base class for Binary Search Tree nodes. + +I define the common interface that both regular nodes (CTBSTNode) and nil nodes (CTBSTNillNode) must implement, enabling polymorphic behavior throughout the tree structure. + +I use the Null Object pattern to eliminate special case handling for empty subtrees, making tree algorithms cleaner and more reliable. " Class { #name : 'CTBSTAbstractNode', diff --git a/src/Containers-BinarySearchTree/CTBSTNillNode.class.st b/src/Containers-BinarySearchTree/CTBSTNillNode.class.st index 6e6611d..0fcff28 100644 --- a/src/Containers-BinarySearchTree/CTBSTNillNode.class.st +++ b/src/Containers-BinarySearchTree/CTBSTNillNode.class.st @@ -1,5 +1,9 @@ " -I represent a nil node for Binary Search Tree. +I represent an empty node in a Binary Search Tree using the Null Object pattern. + +I provide default 'do nothing' behavior for all tree operations, eliminating the need for nil checks throughout the tree algorithms. This makes the code cleaner and prevents null pointer errors. + +When elements are added to me, I create and return a new CTBSTNode containing the element, effectively growing the tree. " Class { #name : 'CTBSTNillNode', diff --git a/src/Containers-BinarySearchTree/CTBSTNode.class.st b/src/Containers-BinarySearchTree/CTBSTNode.class.st index c55c3bd..03f4964 100644 --- a/src/Containers-BinarySearchTree/CTBSTNode.class.st +++ b/src/Containers-BinarySearchTree/CTBSTNode.class.st @@ -1,5 +1,10 @@ " -I represent a node for Binary Search Tree. +I represent a node in a Binary Search Tree containing actual data. + +I hold a value and references to left and right child nodes, maintaining the BST invariant where left child < my contents < right child. + +I implement all tree operations recursively, delegating to my children when appropriate. My children are never nil - they are either other CTBSTNode instances or CTBSTNillNode instances. + " Class { #name : 'CTBSTNode', diff --git a/src/Containers-BinarySearchTree/CTBinarySearchTree.class.st b/src/Containers-BinarySearchTree/CTBinarySearchTree.class.st index bdba471..e2a2eff 100644 --- a/src/Containers-BinarySearchTree/CTBinarySearchTree.class.st +++ b/src/Containers-BinarySearchTree/CTBinarySearchTree.class.st @@ -1,5 +1,17 @@ " -I represent a Binary Search Tree data structure. +I represent a Binary Search Tree data structure that maintains elements in sorted order. + +I provide O(log n) average-case performance for insertion, deletion, and search operations. +Elements are stored according to the BST property: left subtree < node < right subtree. + +Usage: + tree := CTBinarySearchTree new. + tree addAll: #(50 30 70 20 40). + tree asArray. => #(20 30 40 50 70) + tree findMin. => 20 + tree includes: 30. => true + +I support standard collection protocol (do:, collect:, select:) and provide specialized tree operations like range queries and predecessor/successor finding. " Class { #name : 'CTBinarySearchTree',