-
Notifications
You must be signed in to change notification settings - Fork 105
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
3 changed files
with
156 additions
and
51 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
package quadtree | ||
|
||
import "github.com/paulmach/orb" | ||
|
||
// maxHeap is used for the knearest list. We need a way to maintain | ||
// the furthest point from the query point in the list, hence maxHeap. | ||
// When we find a point closer than the furthest away, we remove | ||
// furthest and add the new point to the heap. | ||
type maxHeap []*heapItem | ||
|
||
type heapItem struct { | ||
point orb.Pointer | ||
distance float64 | ||
} | ||
|
||
func (h *maxHeap) Push(item *heapItem) { | ||
*h = append(*h, item) | ||
|
||
i := len(*h) - 1 | ||
for i > 0 { | ||
up := ((i + 1) >> 1) - 1 | ||
parent := (*h)[up] | ||
|
||
if item.distance < parent.distance { | ||
// parent is further so we're done fixing up the heap. | ||
break | ||
} | ||
|
||
// swap nodes | ||
(*h)[i] = parent | ||
(*h)[up] = item | ||
|
||
i = up | ||
} | ||
} | ||
|
||
func (h *maxHeap) Pop() *heapItem { | ||
removed := (*h)[0] | ||
lastItem := (*h)[len(*h)-1] | ||
(*h) = (*h)[:len(*h)-1] | ||
|
||
mh := (*h) | ||
if len(mh) == 0 { | ||
return removed | ||
} | ||
|
||
// move the last item to the top and reset the heap | ||
mh[0] = lastItem | ||
|
||
i := 0 | ||
current := mh[i] | ||
for { | ||
right := (i + 1) << 1 | ||
left := right - 1 | ||
|
||
childIndex := i | ||
child := mh[childIndex] | ||
|
||
// swap with biggest child | ||
if left < len(mh) && child.distance < mh[left].distance { | ||
childIndex = left | ||
child = mh[left] | ||
} | ||
|
||
if right < len(mh) && child.distance < mh[right].distance { | ||
childIndex = right | ||
child = mh[right] | ||
} | ||
|
||
// non bigger, so quit | ||
if childIndex == i { | ||
break | ||
} | ||
|
||
// swap the nodes | ||
mh[i] = child | ||
mh[childIndex] = current | ||
|
||
i = childIndex | ||
} | ||
|
||
return removed | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
package quadtree | ||
|
||
import ( | ||
"math/rand" | ||
"testing" | ||
) | ||
|
||
func TestMaxHeap(t *testing.T) { | ||
r := rand.New(rand.NewSource(22)) | ||
|
||
for i := 1; i < 100; i++ { | ||
h := make(maxHeap, 0, i) | ||
for j := 0; j < i; j++ { | ||
h.Push(&heapItem{distance: r.Float64()}) | ||
} | ||
|
||
current := h.Pop().distance | ||
for len(h) > 0 { | ||
next := h.Pop().distance | ||
if next > current { | ||
t.Errorf("incorrect") | ||
} | ||
|
||
current = next | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters