基本概念
什么叫二叉搜索树?
1、树节点增加key属性,用来比较谁大谁小,key不可以重复
2、对于任意一个树节点,它的key比左子树的key都大,同时也比右子树的key都小
最优情况的二叉搜索树是左右子树差不多平衡,时间复杂度为O(logn)
最差的情况是左右子树少了一边,又变成线性结构,此时时间复杂度为O(n)
算法实现
这里真的学了好久,也学了好多东西,停滞了好久哈哈哈,我把一些重要的贴上来
存储关键字和对应值(新增)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
|
public void put(int key, Object value) { BSTNode node = root; BSTNode parent = null; while(node != null) { parent = node; if (node.key < key) { node = node.left; } else if (node.key > key) { node = node.right; } else { node.value = value; return; } } if(parent == null) { root = new BSTNode(key, value); return; } if(key < parent.key) { parent.left = new BSTNode(key, value); } else { parent.right = new BSTNode(key, value); } }
|
找二叉搜索树前任
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
|
public Object successor(int key) { BSTNode p = root; BSTNode ancestorFromLeft = null; while(p != null) { if(key < p.key) { p = p.left; } else if (key > p.key) { ancestorFromLeft = p; p = p.right; } else { break; } } if(p == null) { return null; } if(p.left != null) { return max(p.left); } return ancestorFromLeft != null ? ancestorFromLeft.value : null; }
|
找二叉搜索树后继
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
|
public Object predecessor(int key) { BSTNode p = root; BSTNode ancestorFromRight = null; while(p != null) { if(key < p.key) { ancestorFromRight = p; p = p.left; } else if(key > p.key) { p = p.right; } else { break; } } if(p == null) { return null; } if(p.right != null) { return getMin2(p.right); } return ancestorFromRight != null ? ancestorFromRight.value : null; }
|
根据关键字删除(非递归递归)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
|
public Object delete(int key) { BSTNode p = root; BSTNode parent = null; while(p != null) { if(key < p.key) { parent = p; p = p.left; } else if (key > p.key) { parent = p; p = p.right; } else { break; } } if(p == null) { return null; } if(p.left == null) { shift(parent, p, p.right); } else if(p.right == null) { shift(parent, p, p.left); } else { BSTNode s = p.right; BSTNode sParent = p; while(s.left != null) { sParent = s; s = s.left; } if(sParent != p) { shift(sParent, s, s.right); s.right = p.right; } shift(parent, p, s); s.left = p.left; } return p.value; }
private void shift(BSTNode parent, BSTNode deleted, BSTNode child) { if(parent == null) { root = child; } else if (deleted == parent.left) { parent.left = child; } else if (deleted == parent.right) { parent.right = child; } }
|
递归版本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
|
private BSTNode doDelete(BSTNode node, int key) { if(node == null) { return null; } if(key < node.key) { node.left = doDelete(node.left, key); return node; } if(node.key < key) { node.right = doDelete(node.right, key); return node; } if(node.left == null) { return node.right; } if(node.right == null) { return node.left; } BSTNode s = node.right; while(s.left != null) { s = s.left; } doDelete(s.right, s.key); s.left = node.left; return s; }
|
根据关键字范围查询
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
|
public List<Object> between(int key1 , int key2) { ArrayList<Object> result = new ArrayList<>(); BSTNode p = root; LinkedList<BSTNode> stack = new LinkedList<>(); while (p != null || stack.isEmpty()) { if(p != null) { stack.push(p); p = p.left; } else { BSTNode pop = stack.pop(); if(key1 >= pop.key && key2 <= pop.key) { result.add(pop.value); } else if (pop.key > key2) { break; } p = pop.right; } } return result; }
|
力扣题目合集
力扣450-删除节点
见力扣上代码哈哈哈
力扣701-新增节点
递归版本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| public TreeNode insertIntoBST(TreeNode root, int val) { if(root == null) { return new TreeNode(val); } if(root.val < val) { root.right = insertIntoBST(root.right, val); } else { root.left = insertIntoBST(root.left, val); } return root; }
|
力扣700-查询节点
递归版本
1 2 3 4 5 6 7 8 9 10 11 12 13
| public TreeNode searchBST(TreeNode root, int val) { if(root == null) { return null; } if(val < root.val) { return searchBST(root.left, val); } else if(val > root.val) { return searchBST(root.right, val); } else { return root; } }
|
力扣98-验证合法二叉搜索树
简单的方法就是中序遍历如果是升序的那么就是合法的
下面的是递归剪枝方法,很牛
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| long prev = Long.MIN_VALUE;
public boolean isValidBST(TreeNode root) { if(root == null) { return true; } boolean a = isValidBST(root.left); if(!a) { return false; } if(prev >= root.val) { return false; } prev = root.val; return isValidBST(root.right); }
|
力扣938-二叉搜索树范围和
还是d递归剪枝方法,其它方法都很简单
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| public int rangeSumBST(TreeNode root, int low, int high) { if(root == null) { return 0; } if(root.val < low) { return rangeSumBST(root.right, low, high); } if(root.val > high) { return rangeSumBST(root.left, low, high); } return root.val + rangeSumBST(root.left, low, high) + rangeSumBST(root.right, low, high); }
|
力扣1008-前序遍历构造二叉搜索树
递归分而治之法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| public TreeNode bstFromPreorder(int[] preorder) { return fenerzhizhi(preorder, 0, preorder.length - 1); } private TreeNode fenerzhizhi(int[] preorder, int start, int end) { if(start > end) { return null; } TreeNode root = new TreeNode(preorder[start]); int index = start + 1; while(index <= end) { if(preorder[start] < preorder[index]) { break; } index++; } root.left = fenerzhizhi(preorder, start + 1, index - 1); root.right = fenerzhizhi(preorder, index, end); return root; }
|
力扣235-二叉搜索树最近公共祖先
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| 待查找点p q 在某一个结点的两侧,那么此节点就是最近的公共祖先 public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { TreeNode a = root; while(p.val < a.val && q.val < a.val || p.val > a.val && q.val > a.val) { if(p.val < a.val) { a = a.left; } else { a = a.right; } } return a; }
|