2015 Conc
2015 Conc
O(1)
3⇥
sum
O(log n)
O(log n)
O(1)
3⇥
Conc
List
Nil :: Conc
Empty Single
<>
Conc
level
level 0 Empty Single 1
<> size Conc
abstract class Conc[+T] { case class Single[T](x: T)
def level: Int extends Leaf[T] {
def size: Int def level = 0
def left: Conc[T] def size = 1
def right: Conc[T] }
def normalized = this }
case class <>[T](
abstract class Leaf[T] left: Conc[T], right: Conc[T]
extends Conc[T] { ) extends Conc[T] {
def left = error() val level =
def right = error() } 1 + max(left.level,
right.level)
case object Empty val size =
extends Leaf[Nothing] { left.size + right.size
def level = 0 }
def size = 0 }
size level
<>
Conc
normalized
normalized
Empty
<> Empty
<>
level 1
<>
S(level) = 2level
n = S(level) level = log2 n
<> level
|lef t.level right.level| = 1 level
p p
1 1 + 5 level 1 1 5 level
S(level) = p ( ) p ( )
5 2 5 2
p
level = log 1+p5 n + log 1+p5 5
2 2
O(log n)
O(log n)
O(log n) insert
<>
xs <> ys
new <>(xs, ys)
<>
<>
concat
level
1
level 1
concat
Single
xs ys
level level xs
ys
<>
level
xs ys xs
ys xs
def <>[T](xs: Conc[T], ys: Conc[T]) = {
if (xs == Empty) ys
else if (ys == Empty) xs
else concat(xs.normalized, ys.normalized) }
def concat[T](xs: Conc[T], ys: Conc[T]) = {
val diff = ys.level - xs.level
if (abs(diff) <= 1) new <>(xs, ys)
else if (diff < -1) {
if (xs.left.level >= xs.right.level) {
val nr = concat(xs.right, ys)
new <>(xs.left, nr)
} else {
val nrr = concat(xs.right.right, ys)
if (nrr.level == xs.level - 3) {
val nr = new <>(xs.right.left, nrr)
new <>(xs.left, nr)
} else {
val nl = new <>(xs.left, xs.right.left)
new <>(nl, nrr)
} }
} else {
if (ys.right.level >= ys.left.level) {
val nl = concat(xs, ys.left)
new <>(nl, ys.right)
} else {
val nll = concat(xs, ys.left.left)
if (nll.level == ys.level - 3) {
val nl = new <>(nll, ys.left.right)
new <>(nl, ys.right)
} else {
val nr = new <>(ys.left.right, ys.right)
new <>(nll, nr)
} } } }
h1 h2 h |h max(h1 , h2 )| 1
h1 h2 O(|h1 h2 |)
O(1)
concat
concat concat
1 2 3 concat
1
concat O(|xslevel yslevel |) t
u
insert
insert
def insert[T](xs: Conc[T], i: Int, y: T) =
xs match {
case Single(x) =>
if (i == 0) new <>(Single(y), xs)
else new <>(xs, Single(y))
case left <> right if i < left.size =>
insert(left, i, y) <> right
case left <> right =>
left <> insert(right, i - left.size, y) }
O(1)
O(log n)
O(log n) split insert
O(log n)
Single
O(log n)
O(1)
append
O(log n)
O(log n)
Append
<> Append
left right
Append
right Append Append
Append Empty Append
Append Append
Nil
<> Append
case class Append[T](left: Conc[T], right: Conc[T])
extends Conc[T] {
val level = 1 + left.level.max(right.level)
val size = left.size + right.size
override def normalized = wrap(left, right)
}
def wrap[T](xs: Conc[T], ys: Conc[T]) =
xs match {
case Append(ws, zs) => wrap(ws, zs <> ys)
case xs => xs <> ys
}
normalized
concat normalized
O(log n) normalized O(log n)
concat O(log n)
Append
⇧ )
append
normalized n
normalized O(n log n)
append append
concat
append
level
level <>
n O(n)
1 O(1)
O(log n)
n Single O(n)
level
O(1)
Append a
Append b a.right.level < b.right.level
Append
2level
Append
append O(1)
level
O(log n)
O(log n)
O(log n) y z
t⇤ xyzs⇤
x O(log n)
O(log n)
O(log n)
def append[T](xs: Conc[T], ys: Leaf[T]) =
xs match {
case Empty => ys
case xs: Leaf[T] => new <>(xs, ys)
case _ <> _ => new Append(xs, ys)
case xs: Append[T] => append(xs, ys) }
private def append[T](xs: Append[T], ys: Conc[T]) =
if (xs.right.level > ys.level) new Append(xs, ys)
else {
val zs = new <>(xs.right, ys)
xs.left match {
case ws @ Append(_, _) =>
append(ws, zs)
case ws =>
if (ws.level <= xs.level) ws <> zs
else new Append(ws, zs) } }
foreach
Leaf Chunk
+=
Chunk xs size
k Chunk insert
Chunk
Chunk size k remove
Chunk
append
O(1)
O(log n)
O(1)
class ConcBuffer[T](val k: Int) {
private var conc: Conc[T] = Empty
private var ch: Array[T] = new Array(k)
private var lastSize: Int = 0
def +=(elem: T) {
if (lastSize >= k) expand()
ch(lastSize) = elem
lastSize += 1 }
private def expand() {
conc = append(conc, new Chunk(ch, lastSize, k))
ch = new Array(k)
lastSize = 0 } }
O(1)
ConcBuffer
Chunk
O(1)
Chunk
k Conc
expand
ConcBuffer ArrayList
vector
O(n) ArrayBuffer
ArrayList vector
O(1)
2
foreach
foreach
Chunk
k = 128 2⇥
k 128
2⇥
4⇥
104
log
Vector
Chunk
Chunk
50%
Single Chunk
6 6
ms
ms
4 4
2 2
0 0
0.2 0.4 0.6 0.8 1 1.2 1.4 1.6 0.2 0.4 0.6 0.8 1 1.2 1.4 1.6
·105 ·106
30
8
ms
ms
20 6
4
10
0
0.2 0.4 0.6 0.8 1 1.2 1.4 1.6 0.2 0.4 0.6 0.8 1 1.2 1.4 1.6
·105 ·106
10
ms
ms
101
0 100
0.2 0.4 0.6 0.8 1 1.2 1.4 1.6 0.2 0.4 0.6 0.8 1 1.2 1.4 1.6
·105 ·106
101 8,000
ms
kB
100 6,000
1
10 4,000
2
10
2,000
3
10
0
0 0.2 0.4 0.6 0.8 1 1.2 1.4 1.6 0 0.2 0.4 0.6 0.8 1 1.2 1.4 1.6
·105 ·106
20
15
ms
ms
15
10
10
5
5
0 0
0 0.5 1 1.5 2 2.5 3 0 0.5 1 1.5 2 2.5 3
·106 ·106
x => x + 1
map
2 3⇥
ArrayList vector
O(1)
O(1)
O(1)
O(n)
O(n)
O(log n)
O(log n)
O(log n)
n1
O(log n2 )
O(1)
3 4⇥
20 50%
3⇥
View publication stats