自平衡二叉(查找树/搜索树/排序树) binary search tree

在计算机科学中,AVL树是最先发明的自平衡二叉查找树。AVL树得名于它的发明者 G.M. Adelson-Velsky 和 E.M. Landis,他们在 1962 年的论文 "An algorithm for the organization of information" 中发表了它。

一、AVL树的旋转规律

AVL树的基本操作一般涉及运做同在不平衡的二叉查找树所运做的同样的算法。但是要进行预先或随后做一次或多次所谓的"AVL旋转"。

假设由于在二叉排序树上插入结点而失去平衡的最小子树根结点的指针为a(即a是离插入点最近,且平衡因子绝对值超过1的祖先结点),则失去平衡后进行进行的规律可归纳为下列四种情况:

1. LL型

平衡二叉树某一节点的左孩子的左子树上插入一个新的节点,使得该节点不再平衡。这时只需要把树向右旋转一次即可,如图所示,原A的左孩子B变为父结点,A变为其右孩子,而原B的右子树变为A的左子树,注意旋转之后Brh是A的左子树(图上忘在A于Brh之间标实线)

2. RR型

平衡二叉树某一节点的右孩子的右子树上插入一个新的节点,使得该节点不再平衡。这时只需要把树向左旋转一次即可,如图所示,原A右孩子B变为父结点,A变为其左孩子,而原B的左子树Blh将变为A的右子树。

3. LR型

平衡二叉树某一节点的左孩子的右子树上插入一个新的节点,使得该节点不再平衡。这时需要旋转两次,仅一次的旋转是不能够使二叉树再次平衡。如图所示,在B节点按照RR型向左旋转一次之后,二叉树在A节点仍然不能保持平衡,这时还需要再向右旋转一次。

4. RL型

平衡二叉树某一节点的右孩子的左子树上插入一个新的节点,使得该节点不再平衡。同样,这时需要旋转两次,旋转方向刚好同LR型相反。

二、AVL树的基本操作

1.插入

向AVL树插入可以通过如同它是未平衡的二叉查找树一样把给定的值插入树中,接着自底向上向根节点折回,于在插入期间成为不平衡的所有节点上进行旋转来完成。因为折回到根节点的路途上最多有 1.5 乘 log n 个节点,而每次AVL 旋转都耗费恒定的时间,插入处理在整体上耗费 O(log n) 时间。 

在平衡的的二叉排序树Balanced BST上插入一个新的数据元素e的递归算法可描述如下:

若BBST为空树,则插入一个数据元素为e的新结点作为BBST的根结点,树的深度增1;

若e的关键字和BBST的根结点的关键字相等,则不进行;

若e的关键字小于BBST的根结点的关键字,而且在BBST的左子树中不存在和e有相同关键字的结点,则将e插入在BBST的左子树上,并且当插入之后的左子树深度增加(+1)时,分别就下列不同情况处理之:BBST的根结点的平衡因子为-1(右子树的深度大于左子树的深度,则将根结点的平衡因子更改为 0,BBST的深度不变; BBST的根结点的平衡因子为0(左、右子树的深度相等):则将根结点的平衡因子更改为1,BBST的深度增1;BBST的根结点的平衡因子为1(左子树的深度大于右子树的深度):则若BBST的左子树根结点的平衡因子为1:则需进行单向右旋平衡处理,并且在右旋处理之后,将根结点和其右子树根结点的平衡因子更改为0,树的深度不变;若e的关键字大于BBST的根结点的关键字,而且在BBST的右子树中不存在和e有相同关键字的结点,则将e插入在BBST的右子树上,并且当插入之后的 右子树深度增加(+1)时,分别就不同情况处理之。

2.删除

从AVL树中删除可以通过把要删除的节点向下旋转成一个叶子节点,接着直接剪除这个叶子节点来完成。因为在旋转成叶子节点期间最多有 log n个节点被旋转,而每次 AVL 旋转耗费恒定的时间,删除处理在整体上耗费 O(log n) 时间。

删除操作需要考虑的情况较多,具体见代码实现吧。

3.查找

在AVL树中查找同在一般BST完全一样的进行,所以耗费 O(log n) 时间,因为AVL树总是保持平衡的。不需要特殊的准备,树的结构不会由于查询而改变。(这是与伸展树查找相对立的,它会因为查找而变更树结构。)

三、代码实现

时间仓促,对于插入、删除操作没有就各种情况配上插图,代码里面有一些注释,可以对着代码理解。日后再研究这个的时候定配上插图。

[java] view plain copy

  1. package ly.dataStructures.tree;
  2. import java.util.Comparator;
  3. /**
  4. * AVL树
  5. * @author 无间道风云
  6. * 2014.0526
  7. * @param <AnyType>
  8. */
  9. public class AvlTree<AnyType extends Comparable<? super AnyType>> {
  10. private AvlNode<AnyType> root;
  11. private Comparator<? super AnyType> cmp;
  12. /*********  AVL树节点数据结构定义   **********/
  13. private static class AvlNode<AnyType>{
  14. AnyType element;
  15. AvlNode<AnyType> left;
  16. AvlNode<AnyType> right;
  17. int height;
  18. AvlNode(AnyType theElement){
  19. this(theElement, null, null);
  20. }
  21. AvlNode(AnyType theElement, AvlNode<AnyType> lt, AvlNode<AnyType> rt){
  22. element = theElement;
  23. left = lt;
  24. right = rt;
  25. height = 0;
  26. }
  27. }
  28. public AvlTree(){
  29. root = null;
  30. }
  31. public void makeEmpty(){
  32. root = null;
  33. }
  34. public boolean isEmpty(){
  35. return root == null;
  36. }
  37. public void insert(AnyType element){
  38. root = insert(element, root);
  39. }
  40. public boolean contains(AnyType x){
  41. return contains(x, root);
  42. }
  43. public void remove(AnyType element){
  44. root = remove(element, root);
  45. }
  46. private int myCompare(AnyType lhs, AnyType rhs){
  47. if(cmp != null)
  48. return cmp.compare(lhs, rhs);
  49. else
  50. return ((Comparable)lhs).compareTo(rhs);
  51. }
  52. private boolean contains(AnyType x, AvlNode<AnyType> t){
  53. //空树处理
  54. if(t == null)
  55. return false;
  56. //正常情况处理
  57. //@方式一:对Comparable型的对象进行比较
  58. //int compareResult = x.compareTo(t.element);
  59. //@方式二:使用一个函数对象而不是要求这些项是Comparable的
  60. int compareResult = myCompare(x, t.element);
  61. if(compareResult < 0)
  62. return contains(x, t.left);
  63. else if(compareResult > 0)
  64. return contains(x, t.right);
  65. else
  66. return true;
  67. }
  68. private int height(AvlNode<AnyType> t){
  69. return t == null ? -1 : t.height;
  70. }
  71. private AvlNode<AnyType> findMin(AvlNode<AnyType> t){
  72. if(t == null)
  73. return null;
  74. if(t.left == null)
  75. return t;
  76. return findMin(t.left);
  77. }
  78. private AvlNode<AnyType> findMax(AvlNode<AnyType> t){
  79. if(t == null)
  80. return null;
  81. if(t.right == null)
  82. return t;
  83. return findMax(t.right);
  84. }
  85. private AvlNode<AnyType> insert(AnyType x, AvlNode<AnyType> t){
  86. if(t == null)
  87. return new AvlNode<AnyType>(x, null, null);
  88. int compareResult = myCompare(x, t.element);
  89. if(compareResult < 0){
  90. t.left = insert(x, t.left);
  91. if(height(t.left)-height(t.right) == 2){
  92. if(myCompare(x, t.left.element) < 0)     //左左情况
  93. t = rotateWithLeftChild(t);
  94. else                                    //左右情况
  95. t = doubleWithLeftChild(t);
  96. }
  97. }else if(compareResult > 0){
  98. t.right = insert(x, t.right);
  99. if(height(t.right)-height(t.left) == 2){
  100. if(myCompare(x, t.right.element) < 0)        //右左情况
  101. t = doubleWithRightChild(t);
  102. else                                        //右右情况
  103. t = rotateWithRightChild(t);
  104. }
  105. }
  106. //完了之后更新height值
  107. t.height = Math.max(height(t.left), height(t.right))+1;
  108. return t;
  109. }
  110. private AvlNode<AnyType> remove(AnyType x, AvlNode<AnyType> t){
  111. if(t == null)
  112. return null;
  113. int compareResult = myCompare(x, t.element);
  114. if(compareResult < 0){
  115. t.left = remove(x, t.left);
  116. //完了之后验证该子树是否平衡
  117. if(t.right != null){        //若右子树为空,则一定是平衡的,此时左子树相当对父节点深度最多为1, 所以只考虑右子树非空情况
  118. if(t.left == null){     //若左子树删除后为空,则需要判断右子树
  119. if(height(t.right)-t.height == 2){
  120. AvlNode<AnyType> k = t.right;
  121. if(k.right != null){        //右子树存在,按正常情况单旋转
  122. System.out.println("-----------------------------------------------------------------------------11111");
  123. t = rotateWithRightChild(t);
  124. }else{                      //否则是右左情况,双旋转
  125. System.out.println("-----------------------------------------------------------------------------22222");
  126. t = doubleWithRightChild(t);
  127. }
  128. }
  129. }else{                  //否则判断左右子树的高度差
  130. //左子树自身也可能不平衡,故先平衡左子树,再考虑整体
  131. AvlNode<AnyType> k = t.left;
  132. //删除操作默认用右子树上最小节点补删除的节点
  133. //k的左子树高度不低于k的右子树
  134. if(k.right != null){
  135. if(height(k.left)-height(k.right) == 2){
  136. AvlNode<AnyType> m = k.left;
  137. if(m.left != null){     //左子树存在,按正常情况单旋转
  138. System.out.println("-----------------------------------------------------------------------------33333");
  139. k = rotateWithLeftChild(k);
  140. }else{                      //否则是左右情况,双旋转
  141. System.out.println("-----------------------------------------------------------------------------44444");
  142. k = doubleWithLeftChild(k);
  143. }
  144. }
  145. }else{
  146. if(height(k.left) - k.height ==2){
  147. AvlNode<AnyType> m = k.left;
  148. if(m.left != null){     //左子树存在,按正常情况单旋转
  149. System.out.println("-----------------------------------------------------------------------------hhhhh");
  150. k = rotateWithLeftChild(k);
  151. }else{                      //否则是左右情况,双旋转
  152. System.out.println("-----------------------------------------------------------------------------iiiii");
  153. k = doubleWithLeftChild(k);
  154. }
  155. }
  156. }
  157. if(height(t.right)-height(t.left) == 2){
  158. //右子树自身一定是平衡的,左右失衡的话单旋转可以解决问题
  159. System.out.println("-----------------------------------------------------------------------------55555");
  160. t = rotateWithRightChild(t);
  161. }
  162. }
  163. }
  164. //完了之后更新height值
  165. t.height = Math.max(height(t.left), height(t.right))+1;
  166. }else if(compareResult > 0){
  167. t.right = remove(x, t.right);
  168. //下面验证子树是否平衡
  169. if(t.left != null){         //若左子树为空,则一定是平衡的,此时右子树相当对父节点深度最多为1
  170. if(t.right == null){        //若右子树删除后为空,则只需判断左子树
  171. if(height(t.left)-t.height ==2){
  172. AvlNode<AnyType> k = t.left;
  173. if(k.left != null){
  174. System.out.println("-----------------------------------------------------------------------------66666");
  175. t = rotateWithLeftChild(t);
  176. }else{
  177. System.out.println("-----------------------------------------------------------------------------77777");
  178. t = doubleWithLeftChild(t);
  179. }
  180. }
  181. }else{              //若右子树删除后非空,则判断左右子树的高度差
  182. //右子树自身也可能不平衡,故先平衡右子树,再考虑整体
  183. AvlNode<AnyType> k = t.right;
  184. //删除操作默认用右子树上最小节点(靠左)补删除的节点
  185. //k的右子树高度不低于k的左子树
  186. if(k.left != null){
  187. if(height(k.right)-height(k.left) == 2){
  188. AvlNode<AnyType> m = k.right;
  189. if(m.right != null){        //右子树存在,按正常情况单旋转
  190. System.out.println("-----------------------------------------------------------------------------88888");
  191. k = rotateWithRightChild(k);
  192. }else{                      //否则是右左情况,双旋转
  193. System.out.println("-----------------------------------------------------------------------------99999");
  194. k = doubleWithRightChild(k);
  195. }
  196. }
  197. }else{
  198. if(height(k.right)-k.height == 2){
  199. AvlNode<AnyType> m = k.right;
  200. if(m.right != null){        //右子树存在,按正常情况单旋转
  201. System.out.println("-----------------------------------------------------------------------------aaaaa");
  202. k = rotateWithRightChild(k);
  203. }else{                      //否则是右左情况,双旋转
  204. System.out.println("-----------------------------------------------------------------------------bbbbb");
  205. k = doubleWithRightChild(k);
  206. }
  207. }
  208. }
  209. if(height(t.left) - height(t.right) == 2){
  210. //左子树自身一定是平衡的,左右失衡的话单旋转可以解决问题
  211. System.out.println("-----------------------------------------------------------------------------ccccc");
  212. t = rotateWithLeftChild(t);
  213. }
  214. }
  215. }
  216. //完了之后更新height值
  217. t.height = Math.max(height(t.left), height(t.right))+1;
  218. }else if(t.left != null && t.right != null){
  219. //默认用其右子树的最小数据代替该节点的数据并递归的删除那个节点
  220. t.element = findMin(t.right).element;
  221. t.right = remove(t.element, t.right);
  222. if(t.right == null){        //若右子树删除后为空,则只需判断左子树与根的高度差
  223. if(height(t.left)-t.height ==2){
  224. AvlNode<AnyType> k = t.left;
  225. if(k.left != null){
  226. System.out.println("-----------------------------------------------------------------------------ddddd");
  227. t = rotateWithLeftChild(t);
  228. }else{
  229. System.out.println("-----------------------------------------------------------------------------eeeee");
  230. t = doubleWithLeftChild(t);
  231. }
  232. }
  233. }else{              //若右子树删除后非空,则判断左右子树的高度差
  234. //右子树自身也可能不平衡,故先平衡右子树,再考虑整体
  235. AvlNode<AnyType> k = t.right;
  236. //删除操作默认用右子树上最小节点(靠左)补删除的节点
  237. if(k.left != null){
  238. if(height(k.right)-height(k.left) == 2){
  239. AvlNode<AnyType> m = k.right;
  240. if(m.right != null){        //右子树存在,按正常情况单旋转
  241. System.out.println("-----------------------------------------------------------------------------fffff");
  242. k = rotateWithRightChild(k);
  243. }else{                      //否则是右左情况,双旋转
  244. System.out.println("-----------------------------------------------------------------------------ggggg");
  245. k = doubleWithRightChild(k);
  246. }
  247. }
  248. }else{
  249. if(height(k.right)-k.height == 2){
  250. AvlNode<AnyType> m = k.right;
  251. if(m.right != null){        //右子树存在,按正常情况单旋转
  252. System.out.println("-----------------------------------------------------------------------------hhhhh");
  253. k = rotateWithRightChild(k);
  254. }else{                      //否则是右左情况,双旋转
  255. System.out.println("-----------------------------------------------------------------------------iiiii");
  256. k = doubleWithRightChild(k);
  257. }
  258. }
  259. }
  260. //左子树自身一定是平衡的,左右失衡的话单旋转可以解决问题
  261. if(height(t.left) - height(t.right) == 2){
  262. System.out.println("-----------------------------------------------------------------------------jjjjj");
  263. t = rotateWithLeftChild(t);
  264. }
  265. }
  266. //完了之后更新height值
  267. t.height = Math.max(height(t.left), height(t.right))+1;
  268. }else{
  269. System.out.println("-----------------------------------------------------------------------------kkkkk");
  270. t = (t.left != null)?t.left:t.right;
  271. }
  272. return t;
  273. }
  274. //左左情况单旋转
  275. private AvlNode<AnyType> rotateWithLeftChild(AvlNode<AnyType> k2){
  276. AvlNode<AnyType> k1 = k2.left;
  277. k2.left = k1.right;
  278. k1.right = k2;
  279. k2.height = Math.max(height(k2.left), height(k2.right)) + 1;
  280. k1.height = Math.max(height(k1.left), k2.height) + 1;
  281. return k1;      //返回新的根
  282. }
  283. //右右情况单旋转
  284. private AvlNode<AnyType> rotateWithRightChild(AvlNode<AnyType> k2){
  285. AvlNode<AnyType> k1 = k2.right;
  286. k2.right = k1.left;
  287. k1.left = k2;
  288. k2.height = Math.max(height(k2.left), height(k2.right)) + 1;
  289. k1.height = Math.max(height(k1.right), k2.height) + 1;
  290. return k1;      //返回新的根
  291. }
  292. //左右情况
  293. private AvlNode<AnyType> doubleWithLeftChild(AvlNode<AnyType> k3){
  294. try{
  295. k3.left = rotateWithRightChild(k3.left);
  296. }catch(NullPointerException e){
  297. System.out.println("k.left.right为:"+k3.left.right);
  298. throw e;
  299. }
  300. return rotateWithLeftChild(k3);
  301. }
  302. //右左情况
  303. private AvlNode<AnyType> doubleWithRightChild(AvlNode<AnyType> k3){
  304. try{
  305. k3.right = rotateWithLeftChild(k3.right);
  306. }catch(NullPointerException e){
  307. System.out.println("k.right.left为:"+k3.right.left);
  308. throw e;
  309. }
  310. return rotateWithRightChild(k3);
  311. }
  312. }
  313. /*注明:由于删除操作考虑的情况甚多,代码中出现的打印信息主要为方便排错*/

测试用例如下:

[java] view plain copy

  1. import static org.junit.Assert.*;
  2. import java.util.Random;
  3. import org.junit.Test;
  4. public class AvlTreeTest {
  5. private AvlTree<Integer> avlTree = new AvlTree<Integer>();
  6. @Test
  7. public void testInsert(){
  8. avlTree.insert(100);
  9. avlTree.insert(120);
  10. avlTree.insert(300);
  11. avlTree.insert(500);
  12. avlTree.insert(111);
  13. avlTree.insert(92);
  14. avlTree.insert(77);
  15. avlTree.insert(125);
  16. System.out.println(avlTree.contains(120));
  17. avlTree.remove(120);
  18. avlTree.remove(125);    //需要单旋转
  19. System.out.println(avlTree.contains(120));
  20. avlTree.insert(78);     //需要双旋转
  21. System.out.println("Insert Success !");
  22. }
  23. @Test
  24. public void testRotate(){
  25. avlTree.insert(100);
  26. avlTree.insert(90);
  27. avlTree.insert(92);
  28. avlTree.insert(78);
  29. avlTree.insert(76);
  30. System.out.println("Insert Success !");
  31. }
  32. /**
  33. * 通过较大数据进行测试,暂时还没有发现问题
  34. */
  35. @Test
  36. public void testAll(){
  37. avlTree.makeEmpty();
  38. Random random = new Random();
  39. for(int i=1;i<=1000000;i++){
  40. avlTree.insert(random.nextInt(1000000));
  41. }
  42. for(int i=2000000;i>=1000000;i--){
  43. avlTree.insert(i);
  44. }
  45. /*for(int i=700000;i>=400000;i--){
  46. avlTree.insert(i);
  47. }
  48. for(int i=100000;i<=200000;i++){
  49. avlTree.insert(i);
  50. }
  51. for(int i=400000;i<=500000;i++){
  52. avlTree.insert(random.nextInt(600000));
  53. }*/
  54. for(int i=200000;i<1400000;i++){
  55. int target = random.nextInt(1500000);
  56. if(avlTree.contains(target)){
  57. avlTree.remove(target);
  58. }
  59. }
  60. System.out.println("Insert Success !");
  61. }
  62. }
时间: 2024-08-04 04:46:30

自平衡二叉(查找树/搜索树/排序树) binary search tree的相关文章

LeetCode 669. 修剪二叉搜索树(Trim a Binary Search Tree)

669. 修剪二叉搜索树 669. Trim a Binary Search Tree 题目描述 LeetCode LeetCode669. Trim a Binary Search Tree简单 Java 实现 TreeNode Class public class TreeNode { int val; TreeNode left; TreeNode right; TreeNode(int x) { val = x; } } class Solution { public TreeNode

平衡二叉搜索树(AVL树,红黑树)数据结构和区别

平衡二叉搜索树(Balanced Binary Search Tree) 经典常见的自平衡的二叉搜索树(Self-balancing Binary Search Tree)有 ① AVL树 :Windows NT 内核中广泛使用 ② 红黑树:C++ STL(比如 map.set )Java 的 TreeMap.TreeSet.HashMap.HashSet  Linux 的进程调度  Ngix 的 timer 管理 1 AVL树  vs  红黑树 ①AVL树 平衡标准比较严格:每个左右子树的高度

[LeetCode] Lowest Common Ancestor of a Binary Search Tree 二叉搜索树的最小共同父节点

Given a binary search tree (BST), find the lowest common ancestor (LCA) of two given nodes in the BST. According to the definition of LCA on Wikipedia: “The lowest common ancestor is defined between two nodes v and w as the lowest node in T that has

平衡二叉搜索树(AVL树)的原理及实现源代码(有图文详解和C++、Java实现代码)

一.AVL树(平衡二叉搜索树)是什么? AVL树是根据它的发明者G.M. Adelson-Velsky和E.M. Landis命名的.AVL树本质上还是一棵二叉搜索树,它的特点是: 1.本身首先是一棵二叉搜索树. 2.带有平衡条件:每个非叶子结点的左右子树的高度之差的绝对值(平衡因子)最多为1. 例如: 5             5 / \            /  \ 2   6         2   6 / \    \         / \ 1  4   7       1  4

数据结构(三):非线性逻辑结构-特殊的二叉树结构:堆、哈夫曼树、二叉搜索树、平衡二叉搜索树、红黑树、线索二叉树

在上一篇数据结构的博文<数据结构(三):非线性逻辑结构-二叉树>中已经对二叉树的概念.遍历等基本的概念和操作进行了介绍.本篇博文主要介绍几个特殊的二叉树,堆.哈夫曼树.二叉搜索树.平衡二叉搜索树.红黑树.线索二叉树,它们在解决实际问题中有着非常重要的应用.本文主要从概念和一些基本操作上进行分类和总结. 一.概念总揽 (1) 堆 堆(heap order)是一种特殊的表,如果将它看做是一颗完全二叉树的层次序列,那么它具有如下的性质:每个节点的值都不大于其孩子的值,或每个节点的值都不小于其孩子的值

[数据结构]二叉搜索树(BST) VS 平衡二叉排序树(AVL) VS B树(平衡多路搜索树) VS B+树 VS 红黑树(平衡二叉B树)

1 二叉排序树/二叉查找树/Binary Sort Tree 1种对排序和查找都很有用的特殊二叉树 叉排序树的弊端的解决方案:平衡二叉树 二叉排序树必须满足的3条性质(或是具有如下特征的二叉树) 若它的左子树不为空,则:左子树上所有结点的值< 它根结点的值 若它的右子树不为空,则:右子树上所有结点的值 > 它根结点的值 它的左子树.右子树也分别为二叉排序树(递归性) (按照如上定义,即: 1 无键值相等的结点 2 中序遍历一颗二叉树时,可得一个结点值递增的有序序列) 2 平衡二叉排序树/Bal

二叉查找(排序)树的分析与实现

二叉排序树(Binary Sort Tree)又称二叉查找树(Binary Search Tree),亦称二叉搜索树. 图from baike 二叉排序树或者是一棵空树,或者是具有下列性质的二叉树: (1)若左子树不空,则左子树上所有结点的值均小于它的根结点的值: (2)若右子树不空,则右子树上所有结点的值均大于或等于它的根结点的值: (3)左.右子树也分别为二叉排序树: (4)没有键值相等的节点. 步骤:若根结点的关键字值等于查找的关键字,成功.否则,若小于根结点的关键字值,递归查左子树.若大

【算法学习】AVL平衡二叉搜索树原理及各项操作编程实现(C语言)

#include<stdio.h> #include "fatal.h" struct AvlNode; typedef struct AvlNode *Position; typedef struct AvlNode *AvlTree; typedef int ElementType ; AvlTree MakeEmpty(AvlTree T); Position Find(ElementType X,AvlTree T); Position FindMin(AvlTre

原生JS实现二叉搜索树(Binary Search Tree)

1.简述 二叉搜索树树(Binary Search Tree),它或者是一棵空树,或者是具有下列性质的二叉树: 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值: 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值: 它的左.右子树也分别为二叉排序树. 2.代码说明 首先先创建一个辅助节点类Node,它初始化了三个属性:节点值,左孩子,有孩子. class Node { constructor(value) { this.value = value; this.left =