专做袜子的网站,wordpress多重,广州天河区房价2022年最新房价,门户网站网页设计1. 概念
二叉搜索树又称二叉排序树#xff0c;它或者是一棵空树#xff0c;或者是具有以下性质的二叉树:
若它的左子树不为空#xff0c;则左子树上所有节点的值都小于根节点的值若它的右子树不为空#xff0c;则右子树上所有节点的值都大于根节点的值它的左右子树也分别…1. 概念
二叉搜索树又称二叉排序树它或者是一棵空树或者是具有以下性质的二叉树:
若它的左子树不为空则左子树上所有节点的值都小于根节点的值若它的右子树不为空则右子树上所有节点的值都大于根节点的值它的左右子树也分别为二叉搜索树不允许存在相同的结点
如一个int a [] {5,3,4,1,7,8,2,6,0,9}; 数组组成二叉排序树 定义二叉搜索树的结构 static class TreeNode {public int val;public TreeNode left;public TreeNode right;public TreeNode(int val) {this.val val;}}public TreeNode root;
2. 操作 - 查找 /*搜索搜索的时间复杂度最好O(logN)搜索的时间复杂度最坏O(N)*/public boolean search(int key){TreeNode cur root;while(cur ! null){//找到key返回trueif(cur.val key) {return true;}//到右树寻找else if(cur.val key){cur cur.right;}//到左树寻找else{cur cur.left;}}//没有找到值为key的结点return false;}3. 操作 - 插入
1 如果树为空树即根 null直接插入 2如果树不是空树按照查找逻辑确定插入位置插入新结点 /*插入都是插入到叶子结点插入的时间复杂度最好O(logN)插入的时间复杂度最坏O(N)*/public void insert(int val) throws Exception {TreeNode newNode new TreeNode(val);if (root null) {root newNode;return;}TreeNode cur root;TreeNode parent null;while (cur ! null) {parent cur;//判断是否有重复元素进入if (cur.val val) {throw new Exception(有重复元素进入);}//如果要插入的结点的值大于当前结点就应该在cur的右子树if (cur.val val) {cur cur.right;}//如果要插入的结点的值小于当前结点就应该在cur的左子树else if (cur.val val) {cur cur.left;}}//如果要插入的结点小于父节点就应该接在父节点的左子树if (parent.val val) {parent.left newNode;}//如果要插入的结点大于父节点就应该接在父节点的右子树else {parent.right newNode;}}
搜索和插入的运行结果 4. 操作 - 删除 ⭐⭐⭐⭐⭐
分情况讨论如下所示
设待删除结点为 cur, 待删除结点的双亲结点为 parent
1cur.left null
① cur 是 root则 root cur.right ② cur 不是 rootcur 是 parent.left则 parent.left cur.right ③ cur 不是 rootcur 是 parent.right则 parent.right cur.right 2cur.right null
① cur 是 root则 root cur.left ② cur 不是 rootcur 是 parent.left则 parent.left cur.left ③ cur 不是 rootcur 是 parent.right则 parent.right cur.left 3cur.left ! null cur.right ! null
需要使用替换法进行删除即在它的右子树中寻找中序下的第一个结点(关键码最小)用它的值填补到被 删除节点中再来处理该结点的删除问题。 这部分的代码为有bug //3.cur两边的子树都不为空else{TreeNode t cur.left;TreeNode tp null;while(t.right ! null){tp t;t t.right;}cur.val t.val;//这个就变成了删除t指向的结点且t结点的右子树为空tp.right t.left;}
原来的图 第一步进行分析和改进 第二步进行分析和改进 树类的方法 //删除结点的操作public void remove(int val) {TreeNode parent null;TreeNode cur root;while (cur ! null) {//去右子树寻找if (cur.val val) {parent cur;cur cur.right;} else if (cur.val val) {parent cur;cur cur.left;}//找到了else {removeNode(cur, parent);return;}}}private void removeNode(TreeNode cur, TreeNode parent) {//1.cur的左子树为空if (cur.left null) {//1cur 是 root则 root cur.rightif (cur root) {root cur.right;}//2cur 不是 rootcur 是 parent.left则 parent.left cur.rightelse if (cur parent.left) {parent.left cur.right;}//3cur 不是 rootcur 是 parent.right则 parent.right cur.rightelse {parent.right cur.right;}}//2.cur的右子树为空else if (cur.right null) {//1cur 是 root则 root cur.leftif (cur root) {root cur.left;}//2cur 不是 rootcur 是 parent.left则 parent.left cur.leftelse if (cur parent.left) {parent.left cur.right;}//3cur 不是 rootcur 是 parent.right则 parent.right cur.leftelse {parent.right cur.right;}}//3.cur两边的子树都不为空else {TreeNode t cur.left;TreeNode tp cur;while (t.right ! null) {tp t;t t.right;}cur.val t.val;if (cur tp) {tp.left t.left;} else {//这个就变成了删除t指向的结点且t结点的右子树为空tp.right t.left;}}} 测试类
public class Test {public static void main(String[] args) throws Exception {BinarySearchTree binarySearchTree new BinarySearchTree();binarySearchTree.insert(5);binarySearchTree.insert(3);binarySearchTree.insert(7);binarySearchTree.insert(1);binarySearchTree.insert(4);binarySearchTree.insert(6);binarySearchTree.insert(8);binarySearchTree.insert(0);binarySearchTree.insert(9);binarySearchTree.remove(3);}
}5. 二叉搜索树的完整代码
public class BinarySearchTree {static class TreeNode {public int val;public TreeNode left;public TreeNode right;public TreeNode(int val) {this.val val;}}public TreeNode root;/*搜索搜索的时间复杂度最好O(logN)搜索的时间复杂度最坏O(N)*/public boolean search(int key) {TreeNode cur root;while (cur ! null) {//找到key返回trueif (cur.val key) {return true;}//到右树寻找else if (cur.val key) {cur cur.right;}//到左树寻找else {cur cur.left;}}//没有找到值为key的结点return false;}/*插入都是插入到叶子结点插入的时间复杂度最好O(logN)插入的时间复杂度最坏O(N)*/public void insert(int val) throws Exception {TreeNode newNode new TreeNode(val);if (root null) {root newNode;return;}TreeNode cur root;TreeNode parent null;while (cur ! null) {parent cur;//判断是否有重复元素进入if (cur.val val) {throw new Exception(有重复元素进入);}//如果要插入的结点的值大于当前结点就应该在cur的右子树if (cur.val val) {cur cur.right;}//如果要插入的结点的值小于当前结点就应该在cur的左子树else if (cur.val val) {cur cur.left;}}//如果要插入的结点小于父节点就应该接在父节点的左子树if (parent.val val) {parent.left newNode;}//如果要插入的结点大于父节点就应该接在父节点的右子树else {parent.right newNode;}}//删除结点的操作public void remove(int val) {TreeNode parent null;TreeNode cur root;while (cur ! null) {//去右子树寻找if (cur.val val) {parent cur;cur cur.right;} else if (cur.val val) {parent cur;cur cur.left;}//找到了else {removeNode(cur, parent);return;}}}private void removeNode(TreeNode cur, TreeNode parent) {//1.cur的左子树为空if (cur.left null) {//1cur 是 root则 root cur.rightif (cur root) {root cur.right;}//2cur 不是 rootcur 是 parent.left则 parent.left cur.rightelse if (cur parent.left) {parent.left cur.right;}//3cur 不是 rootcur 是 parent.right则 parent.right cur.rightelse {parent.right cur.right;}}//2.cur的右子树为空else if (cur.right null) {//1cur 是 root则 root cur.leftif (cur root) {root cur.left;}//2cur 不是 rootcur 是 parent.left则 parent.left cur.leftelse if (cur parent.left) {parent.left cur.right;}//3cur 不是 rootcur 是 parent.right则 parent.right cur.leftelse {parent.right cur.right;}}//3.cur两边的子树都不为空else {TreeNode t cur.left;TreeNode tp cur;while (t.right ! null) {tp t;t t.right;}cur.val t.val;if (cur tp) {tp.left t.left;} else {//这个就变成了删除t指向的结点且t结点的右子树为空tp.right t.left;}}}}6. 性能分析
插入和删除操作都必须先查找查找效率代表了二叉搜索树中各个操作的性能。 对有n个结点的二叉搜索树若每个元素查找的概率相等则二叉搜索树平均查找长度是结点在二叉搜索树的深度 的函数即结点越深则比较次数越多。 但对于同一个关键码集合如果各关键码插入的次序不同可能得到不同结构的二叉搜索树 最优情况下二叉搜索树为完全二叉树其平均比较次数为最差情况下二叉搜索树退化为单支树其平均比较次数为N
问题如果退化成单支树二叉搜索树的性能就失去了。那能否进行改进不论按照什么次序插入关键码都可以是二叉搜索树的性能最佳
答可以这就涉及到后面的AVL树和红黑树了后期的文章会继续讨论AVL树和红黑树。 7. 和Java类集的关系
TreeMap 和 TreeSet 即 Java 中利用搜索树实现的 Map 和 Set实际上用的是红黑树而红黑树是一棵近似平衡的二叉搜索树即在二叉搜索树的基础之上 颜色以及红黑树性质验证关于红黑树的内容后序再进行讲解。