Skip to content

Commit a263d58

Browse files
committed
Fix segment tree
1 parent f4be92e commit a263d58

File tree

8 files changed

+47
-14
lines changed

8 files changed

+47
-14
lines changed

README.markdown

+1-1
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ Most of the time using just the built-in `Array`, `Dictionary`, and `Set` types
132132
- Red-Black Tree
133133
- Splay Tree
134134
- Threaded Binary Tree
135-
- [Segment Tree](Segment Tree/). Stores intervals and can answer which intervals (or segments) contain a given point.
135+
- [Segment Tree](Segment Tree/). Can compute f(a[l], a[l+1], ..., a[r]) for l ≤ r (f is some associative function) and update a[x] = v both on **O(log n)** time
136136
- kd-Tree
137137
- [Heap](Heap/). A binary tree stored in an array, so it doesn't use pointers. Makes a great priority queue.
138138
- Fibonacci Heap

Segment Tree/Images/EqualSegments.png

10.3 KB
Loading

Segment Tree/Images/LeftSegment.png

10.3 KB
Loading

Segment Tree/Images/MixedSegment.png

10.1 KB
Loading

Segment Tree/Images/RightSegment.png

10.3 KB
Loading

Segment Tree/README.markdown

+37-5
Original file line numberDiff line numberDiff line change
@@ -54,13 +54,13 @@ init(array: [T], leftBound: Int, rightBound: Int, function: (T, T) -> T) {
5454
}
5555
```
5656

57-
If out current leftBound and rightBound are equal it means that we are in leaf so we don't have any child nodes and we just fill in `value` property with `array[leftBound]` else we have two child nodes. In that case we divide our current segment into two equal (if length is even) segments: `middle = (leftBound + rightBound) / 2` **[leftBound, middle]** and **[middle+1, rightBound]** and then we build our child nodes for that segments. After we build our child nodes we can easily calculate our value as `value = function(leftChild!.value, rightChild!.value)` because **f(leftBound, rightBound) = f(f(leftBound, middle), f(middle+1, rightBound))**
57+
If out current leftBound and rightBound are equal it means that we are in leaf so we don't have any child nodes and we just fill in `value` property with `array[leftBound]` else we have two child nodes. In that case we divide our current segment into two equal (if length is even) segments: `middle = (leftBound + rightBound) / 2` **[leftBound, middle]** and **[middle+1, rightBound]** and then we build our child nodes for that segments. After we build our child nodes so we can easily calculate our value as `value = function(leftChild!.value, rightChild!.value)` because **f(leftBound, rightBound) = f(f(leftBound, middle), f(middle+1, rightBound))**
5858

5959
## Getting answer to query
6060

6161
```swift
6262
public func queryWithLeftBound(leftBound: Int, rightBound: Int) -> T {
63-
if self.leftBound == self.rightBound {
63+
if self.leftBound == leftBound && self.rightBound == rightBound { {
6464
return self.value
6565
} else if leftChild!.rightBound < leftBound {
6666
return rightChild!.queryWithLeftBound(leftBound, rightBound: rightBound)
@@ -73,8 +73,36 @@ public func queryWithLeftBound(leftBound: Int, rightBound: Int) -> T {
7373
}
7474
}
7575
```
76-
Firstly, we check if our current node is leaf, if it is we just return its value else
77-
we check that our query segment fully lies in rightChild, if so we return result of query on rightChild else if segment lies in leftChild we return result of query on leftChild. If our query lies in both child then we combine results of query on both child.
76+
Firstly, we check if current query segment is equal to segment for which our current node responsible, if it is we just return its value.
77+
```swift
78+
return self.value
79+
```
80+
81+
![equalSegments](Images/EqualSegments.png)
82+
83+
Else we check that our query segment fully lies in rightChild, if so we return result of query on rightChild
84+
```swift
85+
return rightChild!.queryWithLeftBound(leftBound, rightBound: rightBound)
86+
```
87+
88+
![rightSegment](Images/RightSegment.png)
89+
90+
else if segment lies in leftChild we return result of query on leftChild.
91+
```swift
92+
return leftChild!.queryWithLeftBound(leftBound, rightBound: rightBound)
93+
```
94+
95+
![leftSegment](Images/LeftSegment.png)
96+
97+
If none of above-descripted runs it means our query lies in both child so we combine results of query on both child.
98+
99+
```swift
100+
let leftResult = leftChild!.queryWithLeftBound(leftBound, rightBound: leftChild!.rightBound)
101+
let rightResult = rightChild!.queryWithLeftBound(rightChild!.leftBound, rightBound: rightBound)
102+
return function(leftResult, rightResult)
103+
```
104+
105+
![mixedSegment](Images/MixedSegment.png)
78106

79107
## Replacing items
80108

@@ -92,10 +120,14 @@ public func replaceItemAtIndex(index: Int, withItem item: T) {
92120
}
93121
}
94122
```
95-
As always we check if current node is leaf and if so we just change its value otherwise we need to find out to which child index belongs. After that we call same function on that child and after that we recalculate our value because it needs to be in actual state.
123+
Foremost, we check if current node is leaf and if so we just change its value otherwise we need to find out to which child index belongs and call same function on that child. After that we recalculate our value because it needs to be in actual state.
96124

97125
## Examples
98126

99127
Examples of using segment trees can be found in playground
100128

129+
## See also
130+
131+
[Segment tree](http://wcipeg.com/wiki/Segment_tree)
132+
101133
*Written for Swift Algorithm Club by [Artur Antonov](https://github.com/goingreen)*

Segment Tree/SegmentTree.playground/Contents.swift

+3-3
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ public class SegmentTree<T> {
2929
}
3030

3131
public func queryWithLeftBound(leftBound: Int, rightBound: Int) -> T {
32-
if self.leftBound == self.rightBound {
32+
if self.leftBound == leftBound && self.rightBound == rightBound {
3333
return self.value
3434
} else if leftChild!.rightBound < leftBound {
3535
return rightChild!.queryWithLeftBound(leftBound, rightBound: rightBound)
@@ -59,11 +59,11 @@ public class SegmentTree<T> {
5959

6060

6161

62-
let array = [1, 2, 3]
62+
let array = [1, 2, 3, 4]
6363

6464
let sumSegmentTree = SegmentTree(array: array, function: +)
6565

66-
print(sumSegmentTree.queryWithLeftBound(0, rightBound: 2)) // 1 + 2 + 3 + 4 = 10
66+
print(sumSegmentTree.queryWithLeftBound(0, rightBound: 3)) // 1 + 2 + 3 + 4 = 10
6767
print(sumSegmentTree.queryWithLeftBound(1, rightBound: 2)) // 2 + 3 = 5
6868
print(sumSegmentTree.queryWithLeftBound(0, rightBound: 0)) // 1 = 1
6969

Segment Tree/SegmentTree.swift

+6-5
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
/*
2-
Segment tree
3-
build is O(n)
4-
query is O(log n)
5-
replace item is O(log n)
2+
Segment tree
3+
build is O(n)
4+
query is O(log n)
5+
replace item is O(log n)
66
*/
77

8+
89
public class SegmentTree<T> {
910

1011
private var value: T
@@ -34,7 +35,7 @@ public class SegmentTree<T> {
3435
}
3536

3637
public func queryWithLeftBound(leftBound: Int, rightBound: Int) -> T {
37-
if self.leftBound == self.rightBound {
38+
if self.leftBound == leftBound && self.rightBound == rightBound {
3839
return self.value
3940
} else if leftChild!.rightBound < leftBound {
4041
return rightChild!.queryWithLeftBound(leftBound, rightBound: rightBound)

0 commit comments

Comments
 (0)