本周主要学习的是二叉查找树的相关知识。二叉查找树是一种带有附加属性的二叉树,即对树中的每一个结点。其左孩子都要小于父结点,而父结点又小于或等于右孩子。
二叉树结点类的操做php
操做 | 说明 |
---|---|
addElement | 往树中添加一个元素 |
removeElement | 从树中删除一个元素 |
removeAllOccurrences | 从树中删除所指定元素的任何存在 |
removeMin | 删除树中的最小元素 |
removeMax | 删除树中的最大元素 |
findMin | 返回一个指向树中最小元素的引用 |
findMax | 返回一个指向树中最大元素的引用 |
用链表实现二叉查找
树。html
一、向链表中添加元素
首先判断树的根是否为空,若是为空则插入根节点中。不为空则将添加的元素同根的左孩子进行比较。若是左孩子为空,则将元素插入左孩子,若是元素比左孩子大,则继续将元素同左孩子的左孩子进行比较,直至元素插入为止。一样,若是元素大于根,则将元素同根的右孩子进行比较,若是右孩子为空则将元素插入右孩子,若是元素大于根的右孩子则将元素继续同根的右孩子进行比较。直至元素插入为止。java
二、从链表中删除元素
第一种状况:结点没有孩子
咱们直接删除结点便可。
第二种状况:结点只有左孩子或者右孩子
用结点的孩子代替节点。
只有左孩子
node
只有右孩子
git
第三种状况:结点有两个孩子
找本身右孩子里面的最小值(最左)而后替换本身和它,而后删除本身
web
其余的操做原理较为简单就不在赘言
11.4平衡二叉查找树
右旋
一般是指左孩子绕着其父结点向右旋转。
若是是由于树根左孩子的左子树中较长的路径而致使的不平衡,优选能够解决它
左旋
一般是指右孩子绕着其父结点向左旋转。
对于有树根右孩子的右子树中较长路径而致使的不平衡,左旋能够解决它。
右左旋
对于由树根右孩子的左子树中较长路径而致使的不平衡。先让树根右孩子的左孩子,绕着树根的右孩子进行一次右旋,而后在让所得的树根右孩子绕着树根进行一次左旋。
左右旋
对于由树根左孩子的右子树中较长路径而致使的不平衡,咱们必须先让树根左孩子的右孩子绕着树根的左孩子进行一次左旋,而后再让所得的树根左孩子绕着树根进行一次右旋。数据结构
有序列表实现分析和二叉查找树实现分析ide
|操做|LinkedList|BinarySearchTreeList|
|removeFirst|O(1)|O(log n)|
|remove|O(n)|O(log n)|
|remove|O(n)|O(log n)|
|first|O(1)|O(log n)|
|last|O(n)|O(log n)*|学习
|contains|O(n)|O(log n)|
|isEmpty|O(1)|O(1)|
|size|O(1)|O(1)|
|add|O(n)|O(log n)*|
11.5 实现二叉查找树:AVL树
AVL树即二叉平衡查找树,即树的左子树和右子树的深度的绝对值之差不能超过1。
结点的平衡因子 = 左子树的高度 - 右子树的高度
插入和删除操做都会致使AVL树的自我调整(自我平衡),使得全部结点的平衡因子保持为+一、-1或0。
AVL树的右旋
若是某结点的平衡银子为-2,则意味着该结点的左子树中有一条过长的路径。因而咱们将检查这个初始结点的左孩子的平衡因子。若是其左孩子的平衡因子是-1,则意味着较长的路径处在这个左孩子的左子树中,因而让这个左孩子绕着初始结点进行一次右旋便可平衡该树。
AVL树的左旋
若是某结点的平衡因子是+2,则意味着该结点的右子树中有一条过长的路径。若是其右孩子的平衡因子是+1,则意味着其较长的路径处在这个右孩子的右子树中,因而让这个右孩子绕着初始结点进行一次左旋便可平衡该树。
AVL树的右左旋
某结点的右子树中有一条过长的路径。若是其右孩子的平衡因子是-1,则意味着较长路径处在这个右孩子的左子树中,因而进行一次右左双旋便可从新平衡该树。
AVL树的左右旋
某结点的平衡因子为-2,则意味着该结点的左子树中有一条过长的路径。若是左孩子的平衡因子是+1,则意味着较长路径处在这个左孩子的右子树中,因而进行一次左右双旋便可从新平衡该树。
测试
实现二叉查找树:红黑树
红黑树在AVL树的基础上有添加了两个属性:红色和黑色。
红黑树对平衡的要求没有AVL树严格
红黑树红黑颜色的要求
1.每一个节点要么是红色,要么是黑色。
2.根节点必须是黑色
3.红色节点不能连续(也便是,红色节点的孩子和父亲都不能是红色)。
4.对于每一个节点,从该点至null(树尾端)的任何路径,都含有相同个数的黑色节点。
红黑树可以以O(log2 n)的时间复杂度进行搜索、插入、删除操做。此外,因为它的设计,任何不平衡都会在三次旋转以内解决。
问题1:书上解释蜕化树的效率比链表还要低下为何?
回答1:由于二叉搜索树中每一个结点不只定义了其自己的元素还定义了其左孩子和右孩子的引用,而在进行查找时每每须要对其左孩子和右孩子的存在进行比较,因此效率比较低。
问题2:用Comparable接口实例化一个对象的做用。
回答2:Comparable接口是对对象进行比较的接口,使用泛型类型对对象进行实例化之后,就没必要再去对他的方法进行重写了能够直接利用他实例化的对象进行compareTo比较,并且由于实例化的对象是泛型,因此利用Comparable接口进行实例化的对象能够和任何类型的对象进行比较。接口的实例化对象能够直接使用已经实现接口的类的方法。那么Comparable接口实例化一个泛型队形就可使用它对全部对象进行比较的方法。
问题:在测试二叉搜索树时发现了这个问题
解答:后来发现是没有写toString方法,后来补上了。
@Override public String toString() { UnorderedListADT<BinaryTreeNode> nodes = new ArrayUnorderedList<BinaryTreeNode>(); UnorderedListADT<Integer> levelList = new ArrayUnorderedList<Integer>(); BinaryTreeNode current; String result = ""; int printDepth = this.getHeight(); int possibleNodes = (int)Math.pow(2, printDepth + 1); int countNodes = 0; nodes.addToRear(root); Integer currentLevel = 0; Integer previousLevel = -1; levelList.addToRear(currentLevel); while (countNodes < possibleNodes) { countNodes = countNodes + 1; current = nodes.removeFirst(); currentLevel = levelList.removeFirst(); if (currentLevel > previousLevel) { result = result + "\n\n"; previousLevel = currentLevel; for (int j = 0; j < ((Math.pow(2, (printDepth - currentLevel))) - 1); j++) result = result + " "; } else { for (int i = 0; i < ((Math.pow(2, (printDepth - currentLevel + 1)) - 1)) ; i++) { result = result + " "; } } if (current != null) { result = result + (current.getElement()).toString(); nodes.addToRear(current.getLeft()); levelList.addToRear(currentLevel + 1); nodes.addToRear(current.getRight()); levelList.addToRear(currentLevel + 1); } else { nodes.addToRear(null); levelList.addToRear(currentLevel + 1); nodes.addToRear(null); levelList.addToRear(currentLevel + 1); result = result + " "; } } return result; }
运行结果
80 10 85 9 16 6 44 7 85 6 85 80 16 85 9 44 6 7 80 16 9 44 6 7 80 16 9 44 7
(statistics.sh脚本的运行结果截图)
-错题一
-问题解答:重复将最小的元素放到最后排序的排序应该是选择排序。
20172304郭恺郭恺同窗的博客依然是一如既往的优秀,既将教材中的内容总结的详略得当,还能具体而全面的对本身的错误进行总结和提高。
20172328李馨雨李馨雨同窗的博客仍是很认真的。
上周博客互评状况
20172304郭恺同窗本次的博客十分优秀,对教材的总结详略得当,而又针对本身在教材中发现的问题进行了深刻的鞭辟入里的思考与解答。整个过程看起来赏心悦目给人一种美的享受。
20172328李馨雨同窗的博客十分的完整与丰富,体现了她认真的学习态度。
本周学习了二叉搜索树的相关知识,二叉搜索树是二叉树的扩展,可是新添了许多不懂的知识,并且利用了二叉树中所学的知识,这让我深入体会到复习的重要性,只有充分掌握已有的知识,进行吸取转化,才能更好的利用旧知识来学习新知识。
代码行数(新增/累积) | 博客量(新增/累积) | 学习时间(新增/累积) | 重要成长 | |
---|---|---|---|---|
目标 | 5000行 | 30篇 | 400小时 | |
第一周 | 30/30 | 1/1 | 10/10 | |
第二周 | 766/796 | 1/2 | 40/50 | |
第三周 | 817/1613 | 1/3 | 20/70 | |
第四周 | 1370/3983 | 2/5 | 30/100 | |
第五周 | 1235/5214 | 1/6 | 10/110 | |
第六周 | 1328/6542 | 1/7 | 20/130 | |
第七周 | 1218/7860 | 1/8 | 20/150 |
1.蓝墨云班课
2.java软件结构与数据结构
3.多动态图详细讲解二叉搜索树