Implement first working version with auto-balancing Search Binary Trees
This commit is contained in:
commit
9a7048ffd7
6 changed files with 215 additions and 0 deletions
24
.gitignore
vendored
Normal file
24
.gitignore
vendored
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
# ---> Haskell
|
||||||
|
dist
|
||||||
|
dist-*
|
||||||
|
cabal-dev
|
||||||
|
*.o
|
||||||
|
*.hi
|
||||||
|
*.chi
|
||||||
|
*.chs.h
|
||||||
|
*.dyn_o
|
||||||
|
*.dyn_hi
|
||||||
|
.hpc
|
||||||
|
.hsenv
|
||||||
|
.cabal-sandbox/
|
||||||
|
cabal.sandbox.config
|
||||||
|
*.prof
|
||||||
|
*.aux
|
||||||
|
*.hp
|
||||||
|
*.eventlog
|
||||||
|
.stack-work/
|
||||||
|
cabal.project.local
|
||||||
|
cabal.project.local~
|
||||||
|
.HTF/
|
||||||
|
.ghc.environment.*
|
||||||
|
|
5
CHANGELOG.md
Normal file
5
CHANGELOG.md
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
# Revision history for RangeMap
|
||||||
|
|
||||||
|
## 0.1.0.0 -- 2019-09-15
|
||||||
|
|
||||||
|
* First draft, supports insertion and retrieval
|
30
LICENSE
Normal file
30
LICENSE
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
Copyright (c) 2019, Tissevert
|
||||||
|
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
* Redistributions in binary form must reproduce the above
|
||||||
|
copyright notice, this list of conditions and the following
|
||||||
|
disclaimer in the documentation and/or other materials provided
|
||||||
|
with the distribution.
|
||||||
|
|
||||||
|
* Neither the name of Tissevert nor the names of other
|
||||||
|
contributors may be used to endorse or promote products derived
|
||||||
|
from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
26
RangeMap.cabal
Normal file
26
RangeMap.cabal
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
cabal-version: >=1.10
|
||||||
|
-- Initial package description 'RangeMap.cabal' generated by 'cabal init'.
|
||||||
|
-- For further documentation, see http://haskell.org/cabal/users-guide/
|
||||||
|
|
||||||
|
name: RangeMap
|
||||||
|
version: 0.1.0.0
|
||||||
|
synopsis: A library to implement a container similar to Data.Map except it associates values to intervals instead of pure keys
|
||||||
|
-- description:
|
||||||
|
homepage: https://git.marvid.fr/tissevert/RangeMap
|
||||||
|
-- bug-reports:
|
||||||
|
license: BSD3
|
||||||
|
license-file: LICENSE
|
||||||
|
author: Tissevert
|
||||||
|
maintainer: tissevert+devel@marvid.fr
|
||||||
|
-- copyright:
|
||||||
|
category: Data
|
||||||
|
build-type: Simple
|
||||||
|
extra-source-files: CHANGELOG.md
|
||||||
|
|
||||||
|
library
|
||||||
|
exposed-modules: Data.RangeMap
|
||||||
|
-- other-modules:
|
||||||
|
-- other-extensions:
|
||||||
|
build-depends: base >=4.12 && <4.13
|
||||||
|
hs-source-dirs: src
|
||||||
|
default-language: Haskell2010
|
2
Setup.hs
Normal file
2
Setup.hs
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
import Distribution.Simple
|
||||||
|
main = defaultMain
|
128
src/Data/RangeMap.hs
Normal file
128
src/Data/RangeMap.hs
Normal file
|
@ -0,0 +1,128 @@
|
||||||
|
{-# LANGUAGE NamedFieldPuns #-}
|
||||||
|
module Data.RangeMap (
|
||||||
|
HalfLine(..)
|
||||||
|
, RangeMap
|
||||||
|
, empty
|
||||||
|
, get
|
||||||
|
, line
|
||||||
|
, segment
|
||||||
|
, set
|
||||||
|
) where
|
||||||
|
|
||||||
|
type Color b = Maybe b
|
||||||
|
data Branch a b = Branch {
|
||||||
|
lower :: RangeMap a b
|
||||||
|
, bound :: a
|
||||||
|
, weight :: Int
|
||||||
|
, higher :: RangeMap a b
|
||||||
|
} deriving (Show, Read)
|
||||||
|
|
||||||
|
data RangeMap a b =
|
||||||
|
Color (Color b)
|
||||||
|
| Tree (Branch a b)
|
||||||
|
deriving (Show, Read)
|
||||||
|
|
||||||
|
empty :: RangeMap a b
|
||||||
|
empty = Color Nothing
|
||||||
|
|
||||||
|
line :: b -> RangeMap a b
|
||||||
|
line = Color . Just
|
||||||
|
|
||||||
|
get :: Ord a => RangeMap a b -> a -> Maybe b
|
||||||
|
get (Color color) _ = color
|
||||||
|
get (Tree (Branch {lower, bound, higher})) key =
|
||||||
|
get (if key < bound then lower else higher) key
|
||||||
|
|
||||||
|
data HalfLine a = Above a | Below a
|
||||||
|
|
||||||
|
origin :: HalfLine a -> a
|
||||||
|
origin (Above a) = a
|
||||||
|
origin (Below a) = a
|
||||||
|
|
||||||
|
set :: Ord a => HalfLine a -> Color b -> RangeMap a b -> RangeMap a b
|
||||||
|
set halfLine color (Tree branch@(Branch {lower, bound, higher})) =
|
||||||
|
if origin halfLine < bound
|
||||||
|
then
|
||||||
|
let newLower = set halfLine color lower in
|
||||||
|
Tree $ balance (branch {
|
||||||
|
lower = newLower
|
||||||
|
, weight = weight branch + 1
|
||||||
|
})
|
||||||
|
else
|
||||||
|
let newHigher = set halfLine color higher in
|
||||||
|
Tree $ balance (branch {
|
||||||
|
higher = newHigher
|
||||||
|
, weight = weight branch + 1
|
||||||
|
})
|
||||||
|
|
||||||
|
set (Above bound) color rangeMap = Tree (Branch {
|
||||||
|
lower = rangeMap
|
||||||
|
, bound
|
||||||
|
, weight = 0
|
||||||
|
, higher = Color color
|
||||||
|
})
|
||||||
|
|
||||||
|
set (Below bound) color rangeMap = Tree (Branch {
|
||||||
|
lower = Color color
|
||||||
|
, bound
|
||||||
|
, weight = 0
|
||||||
|
, higher = rangeMap
|
||||||
|
})
|
||||||
|
|
||||||
|
segment :: (a, a) -> b -> RangeMap a b
|
||||||
|
segment (from, to) b = Tree (Branch {
|
||||||
|
lower = empty
|
||||||
|
, bound = from
|
||||||
|
, weight = 1
|
||||||
|
, higher = Tree (Branch {
|
||||||
|
lower = line b
|
||||||
|
, bound = to
|
||||||
|
, weight = 0
|
||||||
|
, higher = empty
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
popMax :: Branch a b -> ((a, Color b), RangeMap a b)
|
||||||
|
popMax (Branch {lower, bound, higher = Color color}) = ((bound, color), lower)
|
||||||
|
popMax branch@(Branch {higher = Tree higherBranch, weight}) =
|
||||||
|
let (pair, subTree) = popMax higherBranch in
|
||||||
|
(pair, Tree (branch {higher = subTree, weight = weight - 1}))
|
||||||
|
|
||||||
|
popMin :: Branch a b -> ((a, Color b), RangeMap a b)
|
||||||
|
popMin (Branch {lower = Color color, bound, higher}) = ((bound, color), higher)
|
||||||
|
popMin branch@(Branch {lower = Tree lowerBranch, weight}) =
|
||||||
|
let (pair, subTree) = popMin lowerBranch in
|
||||||
|
(pair, Tree (branch {lower = subTree, weight = weight - 1}))
|
||||||
|
|
||||||
|
rotateLeft :: Ord a => Branch a b -> Branch a b
|
||||||
|
rotateLeft branch@(Branch {higher = Color _}) = branch
|
||||||
|
rotateLeft branch@(Branch {lower, bound, higher = Tree higherBranch}) =
|
||||||
|
let ((minBound, color), newHigher) = popMin higherBranch in
|
||||||
|
branch {
|
||||||
|
lower = set (Above bound) color lower
|
||||||
|
, bound = minBound
|
||||||
|
, higher = newHigher
|
||||||
|
}
|
||||||
|
|
||||||
|
rotateRight :: Ord a => Branch a b -> Branch a b
|
||||||
|
rotateRight branch@(Branch {lower = Color _}) = branch
|
||||||
|
rotateRight branch@(Branch {lower = Tree lowerBranch, bound, higher}) =
|
||||||
|
let ((maxBound, color), newLower) = popMax lowerBranch in
|
||||||
|
branch {
|
||||||
|
lower = newLower
|
||||||
|
, bound = maxBound
|
||||||
|
, higher = set (Below bound) color higher
|
||||||
|
}
|
||||||
|
|
||||||
|
getWeight :: RangeMap a b -> Int
|
||||||
|
getWeight (Tree (Branch {weight})) = weight
|
||||||
|
getWeight _ = 0
|
||||||
|
|
||||||
|
balance :: Ord a => Branch a b -> Branch a b
|
||||||
|
balance branch@(Branch {lower, bound, higher})
|
||||||
|
| lowerWeight - higherWeight > 1 = rotateRight branch
|
||||||
|
| higherWeight - lowerWeight > 1 = rotateLeft branch
|
||||||
|
| otherwise = branch
|
||||||
|
where
|
||||||
|
lowerWeight = getWeight lower
|
||||||
|
higherWeight = getWeight higher
|
Loading…
Reference in a new issue