Skip to content

Commit f561311

Browse files
authored
Merge pull request #220 from farzadshbfn/SegmentTree
Segment Tree
2 parents 8dde602 + f7ecb1a commit f561311

File tree

5 files changed

+169
-175
lines changed

5 files changed

+169
-175
lines changed

Segment Tree/README.markdown

+14-14
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ The `leftBound` and `rightBound` of each node are marked in red.
7373
Here's how we create a node of the segment tree:
7474

7575
```swift
76-
public init(array: [T], leftBound: Int, rightBound: Int, function: (T, T) -> T) {
76+
public init(array: [T], leftBound: Int, rightBound: Int, function: @escaping (T, T) -> T) {
7777
self.leftBound = leftBound
7878
self.rightBound = rightBound
7979
self.function = function
@@ -111,7 +111,7 @@ We go through all this trouble so we can efficiently query the tree.
111111
Here's the code:
112112

113113
```swift
114-
public func queryWithLeftBound(leftBound: Int, rightBound: Int) -> T {
114+
public func query(withLeftBound: leftBound: Int, rightBound: Int) -> T {
115115
// 1
116116
if self.leftBound == leftBound && self.rightBound == rightBound {
117117
return self.value
@@ -122,16 +122,16 @@ Here's the code:
122122

123123
// 2
124124
if leftChild.rightBound < leftBound {
125-
return rightChild.queryWithLeftBound(leftBound, rightBound: rightBound)
125+
return rightChild.query(withLeftBound: leftBound, rightBound: rightBound)
126126

127127
// 3
128128
} else if rightChild.leftBound > rightBound {
129-
return leftChild.queryWithLeftBound(leftBound, rightBound: rightBound)
129+
return leftChild.query(withLeftBound: leftBound, rightBound: rightBound)
130130

131131
// 4
132132
} else {
133-
let leftResult = leftChild.queryWithLeftBound(leftBound, rightBound: leftChild.rightBound)
134-
let rightResult = rightChild.queryWithLeftBound(rightChild.leftBound, rightBound: rightBound)
133+
let leftResult = leftChild.query(withLeftBound: leftBound, rightBound: leftChild.rightBound)
134+
let rightResult = rightChild.query(withLeftBound: rightChild.leftBound, rightBound: rightBound)
135135
return function(leftResult, rightResult)
136136
}
137137
}
@@ -162,10 +162,10 @@ let array = [1, 2, 3, 4]
162162

163163
let sumSegmentTree = SegmentTree(array: array, function: +)
164164

165-
sumSegmentTree.queryWithLeftBound(0, rightBound: 3) // 1 + 2 + 3 + 4 = 10
166-
sumSegmentTree.queryWithLeftBound(1, rightBound: 2) // 2 + 3 = 5
167-
sumSegmentTree.queryWithLeftBound(0, rightBound: 0) // just 1
168-
sumSegmentTree.queryWithLeftBound(3, rightBound: 3) // just 4
165+
sumSegmentTree.query(withLeftBound: 0, rightBound: 3) // 1 + 2 + 3 + 4 = 10
166+
sumSegmentTree.query(withLeftBound: 1, rightBound: 2) // 2 + 3 = 5
167+
sumSegmentTree.query(withLeftBound: 0, rightBound: 0) // just 1
168+
sumSegmentTree.query(withLeftBound: 3, rightBound: 3) // just 4
169169
```
170170

171171
Querying the tree takes **O(log n)** time.
@@ -177,21 +177,21 @@ The value of a node in the segment tree depends on the nodes below it. So if we
177177
Here is the code:
178178

179179
```swift
180-
public func replaceItemAtIndex(index: Int, withItem item: T) {
180+
public func replaceItem(at index: Int, withItem item: T) {
181181
if leftBound == rightBound {
182182
value = item
183183
} else if let leftChild = leftChild, rightChild = rightChild {
184184
if leftChild.rightBound >= index {
185-
leftChild.replaceItemAtIndex(index, withItem: item)
185+
leftChild.replaceItem(at: index, withItem: item)
186186
} else {
187-
rightChild.replaceItemAtIndex(index, withItem: item)
187+
rightChild.replaceItem(at: index, withItem: item)
188188
}
189189
value = function(leftChild.value, rightChild.value)
190190
}
191191
}
192192
```
193193

194-
As usual, this works with recursion. If the node is a leaf, we just change its value. If the node is not a leaf, then we recursively call `replaceItemAtIndex()` to update its children. After that, we recalculate the node's own value so that it is up-to-date again.
194+
As usual, this works with recursion. If the node is a leaf, we just change its value. If the node is not a leaf, then we recursively call `replaceItem(at: )` to update its children. After that, we recalculate the node's own value so that it is up-to-date again.
195195

196196
Replacing an item takes **O(log n)** time.
197197

Original file line numberDiff line numberDiff line change
@@ -1,64 +1,64 @@
11
//: Playground - noun: a place where people can play
22

33
public class SegmentTree<T> {
4-
5-
private var value: T
6-
private var function: (T, T) -> T
7-
private var leftBound: Int
8-
private var rightBound: Int
9-
private var leftChild: SegmentTree<T>?
10-
private var rightChild: SegmentTree<T>?
11-
12-
public init(array: [T], leftBound: Int, rightBound: Int, function: (T, T) -> T) {
13-
self.leftBound = leftBound
14-
self.rightBound = rightBound
15-
self.function = function
16-
17-
if leftBound == rightBound {
18-
value = array[leftBound]
19-
} else {
20-
let middle = (leftBound + rightBound) / 2
21-
leftChild = SegmentTree<T>(array: array, leftBound: leftBound, rightBound: middle, function: function)
22-
rightChild = SegmentTree<T>(array: array, leftBound: middle+1, rightBound: rightBound, function: function)
23-
value = function(leftChild!.value, rightChild!.value)
24-
}
25-
}
26-
27-
public convenience init(array: [T], function: (T, T) -> T) {
28-
self.init(array: array, leftBound: 0, rightBound: array.count-1, function: function)
29-
}
30-
31-
public func queryWithLeftBound(leftBound: Int, rightBound: Int) -> T {
32-
if self.leftBound == leftBound && self.rightBound == rightBound {
33-
return self.value
34-
}
35-
36-
guard let leftChild = leftChild else { fatalError("leftChild should not be nil") }
37-
guard let rightChild = rightChild else { fatalError("rightChild should not be nil") }
38-
39-
if leftChild.rightBound < leftBound {
40-
return rightChild.queryWithLeftBound(leftBound, rightBound: rightBound)
41-
} else if rightChild.leftBound > rightBound {
42-
return leftChild.queryWithLeftBound(leftBound, rightBound: rightBound)
43-
} else {
44-
let leftResult = leftChild.queryWithLeftBound(leftBound, rightBound: leftChild.rightBound)
45-
let rightResult = rightChild.queryWithLeftBound(rightChild.leftBound, rightBound: rightBound)
46-
return function(leftResult, rightResult)
47-
}
48-
}
49-
50-
public func replaceItemAtIndex(index: Int, withItem item: T) {
51-
if leftBound == rightBound {
52-
value = item
53-
} else if let leftChild = leftChild, rightChild = rightChild {
54-
if leftChild.rightBound >= index {
55-
leftChild.replaceItemAtIndex(index, withItem: item)
56-
} else {
57-
rightChild.replaceItemAtIndex(index, withItem: item)
58-
}
59-
value = function(leftChild.value, rightChild.value)
60-
}
61-
}
4+
5+
private var value: T
6+
private var function: (T, T) -> T
7+
private var leftBound: Int
8+
private var rightBound: Int
9+
private var leftChild: SegmentTree<T>?
10+
private var rightChild: SegmentTree<T>?
11+
12+
public init(array: [T], leftBound: Int, rightBound: Int, function: @escaping (T, T) -> T) {
13+
self.leftBound = leftBound
14+
self.rightBound = rightBound
15+
self.function = function
16+
17+
if leftBound == rightBound {
18+
value = array[leftBound]
19+
} else {
20+
let middle = (leftBound + rightBound) / 2
21+
leftChild = SegmentTree<T>(array: array, leftBound: leftBound, rightBound: middle, function: function)
22+
rightChild = SegmentTree<T>(array: array, leftBound: middle+1, rightBound: rightBound, function: function)
23+
value = function(leftChild!.value, rightChild!.value)
24+
}
25+
}
26+
27+
public convenience init(array: [T], function: @escaping (T, T) -> T) {
28+
self.init(array: array, leftBound: 0, rightBound: array.count-1, function: function)
29+
}
30+
31+
public func query(withLeftBound: Int, rightBound: Int) -> T {
32+
if self.leftBound == leftBound && self.rightBound == rightBound {
33+
return self.value
34+
}
35+
36+
guard let leftChild = leftChild else { fatalError("leftChild should not be nil") }
37+
guard let rightChild = rightChild else { fatalError("rightChild should not be nil") }
38+
39+
if leftChild.rightBound < leftBound {
40+
return rightChild.query(withLeftBound: leftBound, rightBound: rightBound)
41+
} else if rightChild.leftBound > rightBound {
42+
return leftChild.query(withLeftBound: leftBound, rightBound: rightBound)
43+
} else {
44+
let leftResult = leftChild.query(withLeftBound: leftBound, rightBound: leftChild.rightBound)
45+
let rightResult = rightChild.query(withLeftBound:rightChild.leftBound, rightBound: rightBound)
46+
return function(leftResult, rightResult)
47+
}
48+
}
49+
50+
public func replaceItem(at index: Int, withItem item: T) {
51+
if leftBound == rightBound {
52+
value = item
53+
} else if let leftChild = leftChild, let rightChild = rightChild {
54+
if leftChild.rightBound >= index {
55+
leftChild.replaceItem(at: index, withItem: item)
56+
} else {
57+
rightChild.replaceItem(at: index, withItem: item)
58+
}
59+
value = function(leftChild.value, rightChild.value)
60+
}
61+
}
6262
}
6363

6464

@@ -68,72 +68,72 @@ let array = [1, 2, 3, 4]
6868

6969
let sumSegmentTree = SegmentTree(array: array, function: +)
7070

71-
print(sumSegmentTree.queryWithLeftBound(0, rightBound: 3)) // 1 + 2 + 3 + 4 = 10
72-
print(sumSegmentTree.queryWithLeftBound(1, rightBound: 2)) // 2 + 3 = 5
73-
print(sumSegmentTree.queryWithLeftBound(0, rightBound: 0)) // 1 = 1
71+
print(sumSegmentTree.query(withLeftBound: 0, rightBound: 3)) // 1 + 2 + 3 + 4 = 10
72+
print(sumSegmentTree.query(withLeftBound: 1, rightBound: 2)) // 2 + 3 = 5
73+
print(sumSegmentTree.query(withLeftBound: 0, rightBound: 0)) // 1 = 1
7474

75-
sumSegmentTree.replaceItemAtIndex(0, withItem: 2) //our array now is [2, 2, 3, 4]
75+
sumSegmentTree.replaceItem(at: 0, withItem: 2) //our array now is [2, 2, 3, 4]
7676

77-
print(sumSegmentTree.queryWithLeftBound(0, rightBound: 0)) // 2 = 2
78-
print(sumSegmentTree.queryWithLeftBound(0, rightBound: 1)) // 2 + 2 = 4
77+
print(sumSegmentTree.query(withLeftBound: 0, rightBound: 0)) // 2 = 2
78+
print(sumSegmentTree.query(withLeftBound: 0, rightBound: 1)) // 2 + 2 = 4
7979

8080

8181
//you can use any associative function (i.e (a+b)+c == a+(b+c)) as function for segment tree
82-
func gcd(m: Int, _ n: Int) -> Int {
83-
var a = 0
84-
var b = max(m, n)
85-
var r = min(m, n)
86-
87-
while r != 0 {
88-
a = b
89-
b = r
90-
r = a % b
91-
}
92-
return b
82+
func gcd(_ m: Int, _ n: Int) -> Int {
83+
var a = 0
84+
var b = max(m, n)
85+
var r = min(m, n)
86+
87+
while r != 0 {
88+
a = b
89+
b = r
90+
r = a % b
91+
}
92+
return b
9393
}
9494

9595
let gcdArray = [2, 4, 6, 3, 5]
9696

9797
let gcdSegmentTree = SegmentTree(array: gcdArray, function: gcd)
9898

99-
print(gcdSegmentTree.queryWithLeftBound(0, rightBound: 1)) // gcd(2, 4) = 2
100-
print(gcdSegmentTree.queryWithLeftBound(2, rightBound: 3)) // gcd(6, 3) = 3
101-
print(gcdSegmentTree.queryWithLeftBound(1, rightBound: 3)) // gcd(4, 6, 3) = 1
102-
print(gcdSegmentTree.queryWithLeftBound(0, rightBound: 4)) // gcd(2, 4, 6, 3, 5) = 1
99+
print(gcdSegmentTree.query(withLeftBound: 0, rightBound: 1)) // gcd(2, 4) = 2
100+
print(gcdSegmentTree.query(withLeftBound: 2, rightBound: 3)) // gcd(6, 3) = 3
101+
print(gcdSegmentTree.query(withLeftBound: 1, rightBound: 3)) // gcd(4, 6, 3) = 1
102+
print(gcdSegmentTree.query(withLeftBound: 0, rightBound: 4)) // gcd(2, 4, 6, 3, 5) = 1
103103

104-
gcdSegmentTree.replaceItemAtIndex(3, withItem: 10) //gcdArray now is [2, 4, 6, 10, 5]
104+
gcdSegmentTree.replaceItem(at: 3, withItem: 10) //gcdArray now is [2, 4, 6, 10, 5]
105105

106-
print(gcdSegmentTree.queryWithLeftBound(3, rightBound: 4)) // gcd(10, 5) = 5
106+
print(gcdSegmentTree.query(withLeftBound: 3, rightBound: 4)) // gcd(10, 5) = 5
107107

108108

109109
//example of segment tree which finds minimum on given range
110110
let minArray = [2, 4, 1, 5, 3]
111111

112112
let minSegmentTree = SegmentTree(array: minArray, function: min)
113113

114-
print(minSegmentTree.queryWithLeftBound(0, rightBound: 4)) // min(2, 4, 1, 5, 3) = 1
115-
print(minSegmentTree.queryWithLeftBound(0, rightBound: 1)) // min(2, 4) = 2
114+
print(minSegmentTree.query(withLeftBound: 0, rightBound: 4)) // min(2, 4, 1, 5, 3) = 1
115+
print(minSegmentTree.query(withLeftBound: 0, rightBound: 1)) // min(2, 4) = 2
116116

117-
minSegmentTree.replaceItemAtIndex(2, withItem: 10) // minArray now is [2, 4, 10, 5, 3]
117+
minSegmentTree.replaceItem(at: 2, withItem: 10) // minArray now is [2, 4, 10, 5, 3]
118118

119-
print(minSegmentTree.queryWithLeftBound(0, rightBound: 4)) // min(2, 4, 10, 5, 3) = 2
119+
print(minSegmentTree.query(withLeftBound: 0, rightBound: 4)) // min(2, 4, 10, 5, 3) = 2
120120

121121

122122
//type of elements in array can be any type which has some associative function
123123
let stringArray = ["a", "b", "c", "A", "B", "C"]
124124

125125
let stringSegmentTree = SegmentTree(array: stringArray, function: +)
126126

127-
print(stringSegmentTree.queryWithLeftBound(0, rightBound: 1)) // "a"+"b" = "ab"
128-
print(stringSegmentTree.queryWithLeftBound(2, rightBound: 3)) // "c"+"A" = "cA"
129-
print(stringSegmentTree.queryWithLeftBound(1, rightBound: 3)) // "b"+"c"+"A" = "bcA"
130-
print(stringSegmentTree.queryWithLeftBound(0, rightBound: 5)) // "a"+"b"+"c"+"A"+"B"+"C" = "abcABC"
127+
print(stringSegmentTree.query(withLeftBound: 0, rightBound: 1)) // "a"+"b" = "ab"
128+
print(stringSegmentTree.query(withLeftBound: 2, rightBound: 3)) // "c"+"A" = "cA"
129+
print(stringSegmentTree.query(withLeftBound: 1, rightBound: 3)) // "b"+"c"+"A" = "bcA"
130+
print(stringSegmentTree.query(withLeftBound: 0, rightBound: 5)) // "a"+"b"+"c"+"A"+"B"+"C" = "abcABC"
131131

132-
stringSegmentTree.replaceItemAtIndex(0, withItem: "I")
133-
stringSegmentTree.replaceItemAtIndex(1, withItem: " like")
134-
stringSegmentTree.replaceItemAtIndex(2, withItem: " algorithms")
135-
stringSegmentTree.replaceItemAtIndex(3, withItem: " and")
136-
stringSegmentTree.replaceItemAtIndex(4, withItem: " swift")
137-
stringSegmentTree.replaceItemAtIndex(5, withItem: "!")
132+
stringSegmentTree.replaceItem(at: 0, withItem: "I")
133+
stringSegmentTree.replaceItem(at: 1, withItem: " like")
134+
stringSegmentTree.replaceItem(at: 2, withItem: " algorithms")
135+
stringSegmentTree.replaceItem(at: 3, withItem: " and")
136+
stringSegmentTree.replaceItem(at: 4, withItem: " swift")
137+
stringSegmentTree.replaceItem(at: 5, withItem: "!")
138138

139-
print(stringSegmentTree.queryWithLeftBound(0, rightBound: 5))
139+
print(stringSegmentTree.query(withLeftBound: 0, rightBound: 5))
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
2-
<playground version='5.0' target-platform='osx'>
2+
<playground version='5.0' target-platform='osx' last-migration='0800'>
33
<timeline fileName='timeline.xctimeline'/>
44
</playground>

Segment Tree/SegmentTree.playground/timeline.xctimeline

-6
This file was deleted.

0 commit comments

Comments
 (0)