1 avl树
2 <?php
3 class Node
4 {
5 public $val;
6 public $left;
7 public $right;
8 public $height;
9
10 public function __construct( $val )
11 {
12 $this->val = $val;
13 $this->height = 0;
14 }
15 }
16
17
18 class AvlTree
19 {
20 private $_root;
21
22 public function __construct()
23 {
24 $this->_root = null;
25 }
26
27 public function find( $x )
28 {
29 return $this->_find( $x, $this->_root );
30 }
31
32 private function _find( $x, $tree )
33 {
34 if( $tree == null )
35 return null;
36
37 if( $tree->val == $x )
38 return $tree;
39 else if( $tree->val > $x ) {
40 return $this->_find( $x, $tree->left );
41 }else {
42 return $this->_find( $x, $tree->right );
43 }
44 }
45
46 public function findMax()
47 {
48 $tmp = $this->_root;
49 while( $tmp && $tmp->right ) {
50 $tmp = $tmp->right;
51 }
52
53 return $tmp;
54 }
55
56 public function findMin( $tree = null )
57 {
58 $tmp = $tree ? $tree : $this->_root;
59 while( $tmp && $tmp->left ) {
60 $tmp = $tmp->left;
61 }
62
63 return $tmp;
64 }
65
66 public function getHeight( $tree ) {
67 if( $tree == null )
68 return -1;
69 else
70 return $tree->height;
71 }
72
73 public function insert( $x )
74 {
75 $this->_root = $this->_insert( $x, $this->_root );
76 return $this->_root;
77 }
78
79 private function _insert( $val, $tree )
80 {
81 if( $tree == null ) {
82 $node = new Node( $val );
83 return $node;
84 }
85
86 if( $val > $tree->val ) {
87 $tree->right = $this->_insert( $val, $tree->right );
88 if( $this->getHeight( $tree->right ) - $this->getHeight( $tree->left ) == 2 ) {
89 if( $val > $tree->right->val ) {
90 // var_dump( "val = {$val} ;; rotate = singleRotateWithRight ");
91 $tree = $this->singleRotateWithRight( $tree );
92 }else {
93 // var_dump( "val = {$val} ;; rotate = doubleRotateWithRight ");
94 $tree = $this->doubleRotateWithRight( $tree );
95 }
96 }
97 }else if( $val < $tree->val ) {
98 $tree->left = $this->_insert( $val, $tree->left );
99 if( $this->getHeight( $tree->left ) - $this->getHeight( $tree->right ) == 2 ) {
100 if( $val < $tree->left->val ) {
101 // var_dump( "val = {$val} ;; rotate = singleRotateWithLeft ");
102
103 $tree = $this->singleRotateWithLeft( $tree );
104 }else {
105 // var_dump( "val = {$val} ;; rotate = doubleRotateWithLeft ");
106
107 $tree = $this->doubleRotateWithLeft( $tree );
108 }
109 }
110 }else {
111 // do nothing.
112 }
113
114 $tree->height = max( $this->getHeight( $tree->left ), $this->getHeight( $tree->right ) ) + 1;
115
116 return $tree;
117 }
118
119 private function singleRotateWithRight( $tree )
120 {
121 $newRoot = $tree->right;
122 $tree->right = $newRoot->left;
123 $newRoot->left = $tree;
124
125 $newRoot->height = max( $this->getHeight( $newRoot->left ), $this->getHeight( $newRoot->right ) ) + 1;
126 $tree->height = max( $this->getHeight( $tree->left ), $this->getHeight( $tree->right ) ) + 1;
127
128 return $newRoot;
129 }
130
131 private function singleRotateWithLeft( $tree )
132 {
133 $newRoot = $tree->left;
134 $tree->left = $newRoot->right;
135 $newRoot->right = $tree;
136
137 $newRoot->height = max( $this->getHeight( $newRoot->left ), $this->getHeight( $newRoot->right ) ) + 1;
138 $tree->height = max( $this->getHeight( $tree->left ), $this->getHeight( $tree->right ) ) + 1;
139
140 return $newRoot;
141 }
142
143 private function doubleRotateWithRight( $tree )
144 {
145 $tree->right = $this->singleRotateWithLeft( $tree->right );
146 return $this->singleRotateWithRight( $tree );
147 }
148
149 private function doubleRotateWithLeft( $tree )
150 {
151 $tree->left = $this->singleRotateWithRight( $tree->left );
152 return $this->singleRotateWithLeft( $tree );
153 }
154
155 public function dump()
156 {
157 $ret = [];
158 if( $this->_root == null )
159 return $ret;
160
161 $stack = new SplStack();
162 $stack->push( [$this->_root] );
163 while( !$stack->isEmpty() ) {
164 $node = $stack->pop();
165
166 $temp = $stackVal = [];
167 $isAllNull = true;
168 foreach( $node as $_node ) {
169 if( $_node == null )
170 $temp[] = '';
171 else {
172 $temp[] = $_node->val;
173 $isAllNull = false;
174 }
175
176 if( $_node && $_node->left ) {
177 $stackVal[] = $_node->left;
178 }else {
179 $stackVal[] = null;
180 }
181 if( $_node && $_node->right ) {
182 $stackVal[] = $_node->right;
183 }else {
184 $stackVal[] = null;
185 }
186 }
187 if( !$isAllNull ) {
188 if( $stackVal ) $stack->push( $stackVal );
189 if( $temp ) $ret[] = $temp;
190 }
191 }
192
193 $retCount = count( $ret ) - 1;
194 foreach( $ret as $_retVal ) {
195 echo str_repeat( ' ', $retCount );
196 $_retValCount = count( $_retVal );
197 $_tempEcho = '';
198 for( $i = 0; $i < $_retValCount; $i+= 2 ) {
199 $_tempEcho .= '|';
200 if( isset( $_retVal[$i+1] ) ){
201 $_tempEcho .= $_retVal[$i] . '-' . $_retVal[$i+1];
202 }else
203 $_tempEcho .= $_retVal[$i];
204 $_tempEcho .= '|';
205 }
206 echo str_replace( '||', '|', $_tempEcho );
207 $retCount--;
208 echo PHP_EOL;
209 }
210 }
211
212 public function delete( $x )
213 {
214 $this->_root = $this->_delete( $x, $this->_root );
215 return $this->_root;
216 }
217
218 private function _delete( $val, $tree )
219 {
220 if( $tree == null )
221 return $tree;
222
223 if( $val > $tree->val ) {
224 $tree->right = $this->_delete( $val, $tree->right );
225 if( $this->getHeight( $tree->right ) - $this->getHeight( $tree->left ) == 2 ) {
226 if( $val > $tree->right->val ) {
227 $tree = $this->singleRotateWithRight( $tree );
228 }else {
229 $tree = $this->doubleRotateWithRight( $tree );
230 }
231 }
232 }else if( $val < $tree->val ) {
233 $tree->left = $this->_delete( $val, $tree->left );
234 if( $this->getHeight( $tree->left ) - $this->getHeight( $tree->right ) == 2 ) {
235 if( $val < $tree->left->val ) {
236 $tree = $this->singleRotateWithLeft( $tree );
237 }else {
238 $tree = $this->doubleRotateWithLeft( $tree );
239 }
240 }
241
242 }else {
243 if( $tree->left == null && $tree->right == null ) {
244 $tree = null;
245 return $tree;
246 }
247 if( $tree->left == null ) {
248 $tree = $tree->right;
249 }else if( $tree->right == null ) {
250 $tree = $tree->left;
251 }else {
252 $rightMin = $this->findMin( $tree->right );
253 $tree->right = $this->_delete( $rightMin->val, $tree->right );
254 $rightMin->left = $tree->left;
255 $rightMin->right = $tree->right;
256
257 $tree = $rightMin;
258 }
259 }
260
261 $tree->height = max( $this->getHeight( $tree->left ), $this->getHeight( $tree->right ) ) + 1;
262 return $tree;
263 }
264 }
265
266
267 $tree = new AvlTree();
268 $tree->insert(3);
269 $tree->insert(2);
270 $tree->insert(1);
271 $tree->insert(4);
272 $tree->insert(5);
273 $tree->insert(6);
274 $tree->insert(7);
275 $tree->insert(16);
276 $tree->insert(15);
277 $tree->insert(14);
278 $tree->insert(13);
279 $tree->insert(12);
280 $tree->insert(11);
281 $tree->insert(10);
282 $tree->insert(8);
283 $tree->insert(9);
284
285 $tree->delete(7);
286 $tree->delete(8);
287
288 $tree->dump();
289 // var_dump( $tree );