二分查找法
-对于有序数列,才能使用二分查找法(排序得作用)
-不断把查找数据与目标序列中间值相比较,决定接下来得查找方向,直到查到为止
算法复杂度
O(logN)
代码实现
/*
* 二分查找法,在有序数组arr中,查找target 如果找倒target,返回相应得索引index 如果没有找到返回-1
*/
public int binarySearch(int[] arr, int n, int target) {
// 在 arr[l,r]之中查找target
int l = 0, r = n - 1;
while (l <= r) {
// int mid = (l + r) / 2;
int mid = l+(r-l)/2;
if (arr[mid] == target)
return mid;
if (target < arr[mid])
// 在 arr[l,mid-1]之中查找target
r = mid - 1;
else
// 在 arr[mid+1,r]之中查找target
l = mid + 1;
}
return -1;
}
二分搜索树
-不一定是完全二叉树
二分搜索树的优势
-高效
不仅可以查找数据;还可以高效的插入,删除数据-动态维护数据
代码实现
-遍历时间复杂度:O(n)
-删除节点O(logN)
import java.util.ArrayDeque;
import java.util.Queue;
public class BSTree {
class TreeNode {
int key;
int value;
TreeNode left;
TreeNode right;
TreeNode(int key, int value) {
this.key = key;
this.value = value;
this.left = this.right = null;
}
public TreeNode(TreeNode node) {
this.key = node.key;
this.value = node.value;
this.left = node.left;
this.right = node.right;
}
}
// 根节点
private TreeNode root;
// 计算节点
private int count;
public BSTree() {
root = null;
count = 0;
}
public int size() {
return count;
}
public boolean isEmpty() {
return count == 0;
}
public void insert(int key, int value) {
root = insert(root, key, value);
}
public boolean contain(int key) {
return contain(root, key);
}
public int search(int key) {
return search(root, key);
}
// 前序遍历
public void perOrder() {
preOrder(root);
}
// 中序遍历
public void inOrder() {
inOrder(root);
}
// 后序遍历
public void postOrder() {
postOrder(root);
}
// 层序遍历
public void levelOrder() {
Queue<TreeNode> treeNodes = new ArrayDeque<>();
treeNodes.add(root);
while (!treeNodes.isEmpty()) {
TreeNode root = treeNodes.poll();
System.out.println(root.key);
if (root.left != null)
treeNodes.add(root.left);
if (root.right != null)
treeNodes.add(root.right);
}
}
// 寻找最小键值
public int minmum() {
assert (count != 0);
TreeNode minNode = minmum(root);
return minNode.key;
}
// 寻找最大键值
public int maxmum() {
assert (count != 0);
TreeNode maxNode = maxmum(root);
return maxNode.key;
}
// 从二叉树中删除最小值所在的节点
public void removeMin() {
if (root != null)
root = removeMin(root);
}
// 从二叉树中删除最小值所在的节点
public void removeMax() {
if (root != null)
root = removeMax(root);
}
// 从二叉树中删除键值为key的节点
public void remove(int key) {
remove(root, key);
}
/*
* 删除以root为根的二分搜索树中键值为key的节点 返回删除节点后新的二分搜索树的根
*/
private TreeNode remove(TreeNode root, int key) {
if (root == null)
return null;
if (key < root.key) {
root.left = remove(root.left, key);
return root;
} else if (key > root.key) {
root.right = remove(root.right, key);
return root;
} else {
if (root.left == null) {
TreeNode rightNode = root.right;
count--;
return rightNode;
}
if (root.right == null) {
TreeNode lefttNode = root.left;
count--;
return lefttNode;
}
TreeNode sussessor = new TreeNode(minmum(root.right));
count++;
sussessor.right = removeMin(root.right);
sussessor.left = root.left;
count--;
return sussessor;
}
}
/*
* 删除以root为根的二分搜索树中最大节点并返回删除节点后新的二分搜索树的根
*/
private TreeNode removeMax(TreeNode root) {
if (root.right == null) {
TreeNode leftNode = root.left;
count--;
return leftNode;
}
root.right = removeMax(root.right);
return root;
}
/*
* 删除以root为根的二分搜索树中最小节点并返回删除节点后新的二分搜索树的根
*/
private TreeNode removeMin(TreeNode root) {
if (root.left == null) {
TreeNode rightNode = root.right;
count--;
return rightNode;
}
root.left = removeMin(root.left);
return root;
}
// 在以root为根的二叉搜索树中,返回最大键值的节点
private TreeNode maxmum(TreeNode root) {
if (root.right == null)
return root;
return maxmum(root.right);
}
// 在以root为根的二叉搜索树中,返回最小键值的节点
private TreeNode minmum(TreeNode root) {
if (root.left == null)
return root;
return minmum(root.left);
}
// 对以root为根的二叉搜索树后序遍历
private void postOrder(TreeNode root) {
if (root != null) {
preOrder(root.left);
preOrder(root.right);
System.out.println(root.key);
}
}
// 对以root为根的二叉搜索树中序遍历
private void inOrder(TreeNode root2) {
if (root != null) {
preOrder(root.left);
System.out.println(root.key);
preOrder(root.right);
}
}
// 对以root为根的二叉搜索树前序遍历
private void preOrder(TreeNode root) {
if (root != null) {
System.out.println(root.key);
preOrder(root.left);
preOrder(root.right);
}
}
// 在以root为根的二叉搜索树中查找key所对对应的value
private int search(TreeNode root, int key) {
if (root == null)
return -1;
if (key == root.key)
return root.value;
else if (key < root.key)
return search(root.left, key);
else
return search(root.right, key);
}
// 在以root为根的二叉搜索树中是否包含键值为key的节点
private boolean contain(TreeNode root, int key) {
if (root == null)
return false;
if (key == root.key)
return true;
else if (key < root.key)
return contain(root.left, key);
else
return contain(root.right, key);
}
/*
* 向以root为根的二叉搜索树中,插入节点(key,value) 返回插入新节点后的二叉搜索树的根
*/
private TreeNode insert(TreeNode root, int key, int value) {
if (root == null) {
count++;
return new TreeNode(key, value);
}
if (key == root.key)
root.value = value;
else if (key < root.key)
root.left = insert(root.left, key, value);
else
root.right = insert(root.right, key, value);
return root;
}
}
二分搜索树的局限性
-同样的数据可以对应不同的二分搜索树
-二分搜索树可能退化成链表,出现性能退化
-无法像堆一样保证操作都是logN级别