8 template<class T
, typename Less
= std::less
<T
> >
10 static const int MAX_DEPTH
= 64;
18 inline int cmp_func(const T
&x
, const T
&y
) {
19 return Less()(y
, x
) - Less()(x
, y
);
21 inline unsigned child_size(Node
*p
, int dir
) {
22 return p
->p
[dir
]? p
->p
[dir
]->size
: 0;
24 // one rotation: (a,(b,c)q)p => ((a,b)p,c)q
25 inline Node
*rotate1(Node
*p
, int dir
) { // dir=0 to left; dir=1 to right
26 int opp
= 1 - dir
; // opposite direction
28 unsigned size_p
= p
->size
;
29 p
->size
-= q
->size
- child_size(q
, dir
);
31 p
->p
[opp
] = q
->p
[dir
];
35 // two consecutive rotations: (a,((b,c)r,d)q)p => ((a,b)p,(c,d)q)r
36 inline Node
*rotate2(Node
*p
, int dir
) {
37 int b1
, opp
= 1 - dir
;
38 Node
*q
= p
->p
[opp
], *r
= q
->p
[dir
];
39 unsigned size_x_dir
= child_size(r
, dir
);
41 p
->size
-= q
->size
- size_x_dir
;
42 q
->size
-= size_x_dir
+ 1;
43 p
->p
[opp
] = r
->p
[dir
];
45 q
->p
[dir
] = r
->p
[opp
];
47 b1
= dir
== 0? +1 : -1;
48 if (r
->balance
== b1
) q
->balance
= 0, p
->balance
= -b1
;
49 else if (r
->balance
== 0) q
->balance
= p
->balance
= 0;
50 else q
->balance
= b1
, p
->balance
= 0;
54 void destroy(Node
*r
) {
56 for (p
= r
; p
; p
= q
) {
68 Avl() : root(NULL
) {};
69 ~Avl() { destroy(root
); };
70 unsigned size() const { return root
? root
->size
: 0; }
71 T
*find(const T
&data
, unsigned *cnt_
= NULL
) {
75 int cmp
= cmp_func(data
, p
->data
);
76 if (cmp
>= 0) cnt
+= child_size(p
, 0) + 1;
77 if (cmp
< 0) p
= p
->p
[0];
78 else if (cmp
> 0) p
= p
->p
[1];
81 if (cnt_
) *cnt_
= cnt
;
82 return p
? &p
->data
: NULL
;
84 T
*insert(const T
&data
, bool *is_new
= NULL
, unsigned *cnt_
= NULL
) {
85 unsigned char stack
[MAX_DEPTH
];
86 Node
*path
[MAX_DEPTH
];
88 Node
*x
, *p
, *q
, *r
= 0; // _r_ is potentially the new root
89 int i
, which
= 0, top
, b1
, path_len
;
92 if (is_new
) *is_new
= false;
93 // find the insertion location
94 for (p
= bp
, q
= bq
, top
= path_len
= 0; p
; q
= p
, p
= p
->p
[which
]) {
95 int cmp
= cmp_func(data
, p
->data
);
96 if (cmp
>= 0) cnt
+= child_size(p
, 0) + 1;
98 if (cnt_
) *cnt_
= cnt
;
102 bq
= q
, bp
= p
, top
= 0;
103 stack
[top
++] = which
= (cmp
> 0);
104 path
[path_len
++] = p
;
106 if (cnt_
) *cnt_
= cnt
;
108 x
->data
= data
, x
->balance
= 0, x
->size
= 1, x
->p
[0] = x
->p
[1] = 0;
109 if (is_new
) *is_new
= true;
110 if (q
== 0) root
= x
;
111 else q
->p
[which
] = x
;
112 if (bp
== 0) return &x
->data
;
113 for (i
= 0; i
< path_len
; ++i
) ++path
[i
]->size
;
114 for (p
= bp
, top
= 0; p
!= x
; p
= p
->p
[stack
[top
]], ++top
) /* update balance factors */
115 if (stack
[top
] == 0) --p
->balance
;
117 if (bp
->balance
> -2 && bp
->balance
< 2) return &x
->data
; /* no re-balance needed */
119 which
= (bp
->balance
< 0);
120 b1
= which
== 0? +1 : -1;
121 q
= bp
->p
[1 - which
];
122 if (q
->balance
== b1
) {
123 r
= rotate1(bp
, which
);
124 q
->balance
= bp
->balance
= 0;
125 } else r
= rotate2(bp
, which
);
126 if (bq
== 0) root
= r
;
127 else bq
->p
[bp
!= bq
->p
[0]] = r
;
130 bool erase(const T
&data
) {
131 Node
*p
, *path
[MAX_DEPTH
], fake
;
132 unsigned char dir
[MAX_DEPTH
];
134 fake
.p
[0] = root
, fake
.p
[1] = 0;
135 for (cmp
= -1, p
= &fake
; cmp
; cmp
= cmp_func(data
, p
->data
)) {
136 int which
= (cmp
> 0);
140 if (p
== 0) return false;
142 for (i
= 1; i
< d
; ++i
) --path
[i
]->size
;
143 if (p
->p
[1] == 0) { // ((1,.)2,3)4 => (1,3)4; p=2
144 path
[d
-1]->p
[dir
[d
-1]] = p
->p
[0];
147 if (q
->p
[0] == 0) { // ((1,2)3,4)5 => ((1)2,4)5; p=3
149 q
->balance
= p
->balance
;
150 path
[d
-1]->p
[dir
[d
-1]] = q
;
151 path
[d
] = q
, dir
[d
++] = 1;
152 q
->size
= p
->size
- 1;
153 } else { // ((1,((.,2)3,4)5)6,7)8 => ((1,(2,4)5)3,7)8; p=6
155 int e
= d
++; // backup _d_
160 if (r
->p
[0] == 0) break;
166 r
->balance
= p
->balance
;
167 path
[e
-1]->p
[dir
[e
-1]] = r
;
168 path
[e
] = r
, dir
[e
] = 1;
169 for (i
= e
+ 1; i
< d
; ++i
) --path
[i
]->size
;
170 r
->size
= p
->size
- 1;
175 int which
, other
, b1
= 1, b2
= 2;
176 which
= dir
[d
], other
= 1 - which
;
177 if (which
) b1
= -b1
, b2
= -b2
;
179 if (q
->balance
== b1
) break;
180 else if (q
->balance
== b2
) {
181 Node
*r
= q
->p
[other
];
182 if (r
->balance
== -b1
) {
183 path
[d
-1]->p
[dir
[d
-1]] = rotate2(q
, which
);
185 path
[d
-1]->p
[dir
[d
-1]] = rotate1(q
, which
);
186 if (r
->balance
== 0) {
190 } else r
->balance
= q
->balance
= 0;
200 } // end of namespace klib