本周学习了第11章二叉查找树php
操做 说明 addElement 往树中添加一个元素 removeElement 从树中删除一个元素 removeAllOccurrences 从树中删除所指定元素的任何存在 removeMin 删除树中的最小元素 removeMax 删除树中的最大元素 findMin 返回一个指向树中最小元素的引用 findMax 返回一个指向树中最大元素的引用
右旋:右旋能够解决树根左孩子的左子树中较长的路径而致使的不平衡
html
右旋的三步
1.使树根的左孩子元素成为新的根元素
2.使原根元素成为这个新树根的右孩子元素
3.使原树根的左孩子的右孩子,成为原树根的新的左孩子node
左右旋git
规则以下web
根结点为黑色 红色结点的全部孩子为黑色 从树根到树叶的每条路径都包含一样数目的黑色结点
根据被插入节点的父结点的状况,能够将"当节点z被着色为红色结点,并插入二叉树"划分为三种状况来处理。算法
① 状况说明:被插入的结点是根结点。 处理方法:直接把此结点涂为黑色。 ② 状况说明:被插入的结点的父结点是黑色。 处理方法:什么也不须要作。结点被插入后,仍然是红黑树。 ③ 状况说明:被插入的结点的父结点是红色。 处理方法:那么,该状况与红黑树的特性“从一个结点到该结点的子孙结点的全部路径上包含相同数目的黑结点。”相冲突。这种状况下,被插入结点是必定存在非空祖父结点的;进一步的讲,被插入结点也必定存在叔叔结点(即便叔叔结点为空,咱们也视之为存在,空结点自己就是黑色结点)。理解这点以后,咱们依据"叔叔结点的状况",将这种状况进一步划分为3种状况(Case)。
/ | 现象说明 | 处理策略 |
---|---|---|
case1 | 当前结点的父结点是红色,且当前结点的祖父结点的另外一个子结点(叔叔结点)也是红色。 | (01) 将“父结点”设为黑色。(02) 将“叔叔结点”设为黑色。(03) 将“祖父结点”设为“红色”。(04) 将“祖父结点”设为“当前结点”(红色结点);即,以后继续对“当前结点”进行操做。 |
case2 | 当前结点的父结点是红色,叔叔结点是黑色,且当前结点是其父结点的右孩子 | (01) 将“父结点”做为“新的当前结点”。(02) 以“新的当前结点”为支点进行左旋。 |
case3 | 当前结点的父结点是红色,叔叔结点是黑色,且当前结点是其父结点的左孩子 | (01) 将“父结点”设为“黑色”。(02) 将“祖父结点”设为“红色”。(03) 以“祖父结点”为支点进行右旋。 |
当父亲是左孩子的时候
两种运行是对称的数据结构
若是叔叔的颜色是redpost
设置叔叔的颜色为black 设置current的父亲颜色为red 让叔叔绕着current的父亲向右旋转 设置叔叔等于current父亲的左孩子 若是叔叔的两个孩子都是black或者null则须要设置叔叔的颜色为red,设置current等于current的父亲 若是叔叔的两个孩子不全为black,若是叔叔的左孩子是black,则设置右孩子也为black,设置叔叔的颜色为red,再让兄弟的右孩子绕着兄弟自己向右旋转,最后设置叔叔等于current父亲的左孩子 若是叔叔的两个孩子都不为black,则设置叔叔的颜色为current父亲的颜色,设置current父亲的颜色为black,设置叔叔的左孩子的颜色为black,让叔叔绕着current的父亲向右旋转,设置current等于树根。 循环终止后删除该结点,设置其父亲的孩子引用为null
if (current == null) throw new ElementNotFoundException("LinkedBinaryTree");
为何仍是会出现这样的问题?学习
current == root
,二是current.parent.color == black
是如何执行的,同时按照书上的图示,红黑树平衡以后,树的结构彷佛没有发生改变,那么是在什么地方实现了平衡?问题1:PP11.8在二叉树的基础上完成AVL树的方法,其中关于左旋右旋等方法如何用代码实现。测试
private AVLTreeNode<T> rightRightRotation(AVLTreeNode<T> k2) { AVLTreeNode<T> k1; k1 = k2.left; k2.left = k1.right; k1.right = k2; k2.height = max( height(k2.left), height(k2.right)) + 1; k1.height = max( height(k1.left), k2.height) + 1; return k1; }
如图,该树不平衡时,将整个左子树绕着k2点进行旋转,k1是k2的左孩子,因而k1成为新的根结点,k1的右孩子成为k2的左孩子,k2设置为k1的右孩子。以后再从新定义k一、k2的高度,k2从左右子树中选出较长的一支做为其高度,加一是由于树的高度从0开始。k1也是从它的左右子树中取出较长一支,但这里的右子树能够直接调用k2的高度。
再分析一下右左旋的状况
private AVLTreeNode<T> leftRightSpin(AVLTreeNode<T> node) { node.left = rightRightSpin(node.left); return leftLeftSpin(node); }
原理便是让初始结点的右孩子的左孩子绕初始结点的右孩子进行一次右旋node.left = rightRightSpin(node.left);
,再让初始结点的右孩子绕着初始结点进行一次左旋return leftLeftSpin(node);
。
相似地能够写出右旋和左右旋的方法,可是何时调用右旋,何时进行左右旋的方法尚未进行定义。以添加元素为例,这里编写了一公一私两个方法
public void addElement(T key) { root = addElement(root, key); } private AVLTreeNode<T> addElement(AVLTreeNode<T> tree, T element) { if (!(element instanceof Comparable)) { throw new NonComparableElementException("AVLTreeNode"); } if (tree == null) { // 新建节点 tree = new AVLTreeNode<T>(element, null, null); if (tree==null) { throw new EmptyCollectionException("EmptyCollectionException"); } } else { if (element.compareTo(tree.getElement()) < 0) { // 应该将key插入到"tree的左子树"的状况 tree.left = addElement(tree.left, element); // 插入节点后,若AVL树失去平衡,则进行相应的调节。 if (height(tree.right) - height(tree.left) == -2) {//由于查到左子树,必然左侧感度大于右侧暗度 if (element.compareTo(tree.left.getElement()) < 0) tree = leftLeftSpin(tree); else tree = leftRightSpin(tree); } } else if (element.compareTo(tree.getElement()) >= 0) { // 应该将key插入到"tree的右子树"的状况 tree.right = addElement(tree.right, element); // 插入节点后,若AVL树失去平衡,则进行相应的调节。 if (height(tree.left) - height(tree.right) == -2) { if (element.compareTo(tree.right.getElement()) > 0) tree = rightRightSpin(tree); else tree = rightLeftSpin(tree); } } } tree.height = Math.max( height(tree.left), height(tree.right)) + 1; return tree; }
最后打印树的方法调用了EXpressionTree的PrintTree方法,结果以下
上周的测试彷佛都是错在没有看清楚单词-_-||
中文 | 英文 |
---|---|
前序遍历 | preorder traversal |
中序遍历 | inorder traversal |
后序遍历 | postorder traversal |
层序遍历 | level-order traversal |
基于评分标准,我给谭鑫的博客打分:8分。得分状况以下:
正确使用Markdown语法(加1分):
模板中的要素齐全(加1分)
教材学习中的问题和解决过程, 一个问题加1分
代码调试中的问题和解决过程, 五个问题加5分
基于评分标准,我给方艺雯的博客打分:6分。得分状况以下:、
正确使用Markdown语法(加1分):
模板中的要素齐全(加1分)
教材学习中的问题和解决过程, 三个问题加3分
代码调试中的问题和解决过程, 一个问题加1分
教材学习在红黑树这个地方卡了壳,前思后想左思右想地看教材上的讲解,一边写博客一边想一边提出疑问,致使写了一大堆啰嗦话,但是最终也没有理得太顺,也不知道我挑的教材上出现的错误是否是只是我没有理解到他真正的意图。
代码行数(新增/累积) | 博客量(新增/累积) | 学习时间(新增/累积) | 重要成长 | |
---|---|---|---|---|
目标 | 5000行 | 30篇 | 400小时 | |
第一周 | 0/0 | 1/1 | 8/8 | |
第二周 | 470/470 | 1/2 | 12/20 | |
第三周 | 685/1155 | 2/4 | 10/30 | |
第四周 | 2499/3654 | 2/6 | 12/42 | |
第六周 | 1218/4872 | 2/8 | 10/52 | |
第七周 | 590/5462 | 1/9 | 12/64 | |
第八周 | 993/6455 | 1/10 | 12/76 |