二叉树
- 实现一个二叉查找树,并且支持插入、删除、查找操作
public class TreeNode {
int val;
TreeNode left; //左孩子
TreeNode right; //右孩子
public TreeNode(int x) {
this.val = x;
}
}
public class BST {
/**
* 根节点
*/
public static TreeNode root;
public BST() {
this.root = null;
}
/**
* 查找
* 树深(N) O(lgN)
* 1. 从root节点开始
* 2. 比当前节点值小,则找其左节点
* 3. 比当前节点值大,则找其右节点
* 4. 与当前节点值相等,查找到返回TRUE
* 5. 查找完毕未找到,
*
* @param key
* @return
*/
public TreeNode search(int key) {
TreeNode current = root;
while (current != null
&& key != current.value) {
if (key < current.value)
current = current.left;
else
current = current.right;
}
return current;
}
/**
* 插入
* 1. 从root节点开始
* 2. 如果root为空,root为插入值
* 循环:
* 3. 如果当前节点值大于插入值,找左节点
* 4. 如果当前节点值小于插入值,找右节点
*
* @param key
* @return
*/
public TreeNode insert(int key) {
// 新增节点
TreeNode newNode = new TreeNode(key);
// 当前节点
TreeNode current = root;
// 上个节点
TreeNode parent = null;
// 如果根节点为空
if (current == null) {
root = newNode;
return newNode;
}
while (true) {
parent = current;
if (key < current.value) {
current = current.left;
if (current == null) {
parent.left = newNode;
return newNode;
}
} else {
current = current.right;
if (current == null) {
parent.right = newNode;
return newNode;
}
}
}
}
/**
* 删除节点
* 1.找到删除节点
* 2.如果删除节点左节点为空 , 右节点也为空;
* 3.如果删除节点只有一个子节点 右节点 或者 左节点
* 4.如果删除节点左右子节点都不为空
*
* @param key
* @return
*/
public TreeNode delete(int key) {
TreeNode parent = root;
TreeNode current = root;
boolean isLeftChild = false;
// 找到删除节点 及 是否在左子树
while (current.value != key) {
parent = current;
if (current.value > key) {
isLeftChild = true;
current = current.left;
} else {
isLeftChild = false;
current = current.right;
}
if (current == null) {
return current;
}
}
// 如果删除节点左节点为空 , 右节点也为空
if (current.left == null && current.right == null) {
if (current == root) {
root = null;
}
// 在左子树
if (isLeftChild == true) {
parent.left = null;
} else {
parent.right = null;
}
}
// 如果删除节点只有一个子节点 右节点 或者 左节点
else if (current.right == null) {
if (current == root) {
root = current.left;
} else if (isLeftChild) {
parent.left = current.left;
} else {
parent.right = current.left;
}
} else if (current.left == null) {
if (current == root) {
root = current.right;
} else if (isLeftChild) {
parent.left = current.right;
} else {
parent.right = current.right;
}
}
// 如果删除节点左右子节点都不为空
else if (current.left != null && current.right != null) {
// 找到删除节点的后继者
TreeNode successor = getDeleteSuccessor(current);
if (current == root) {
root = successor;
} else if (isLeftChild) {
parent.left = successor;
} else {
parent.right = successor;
}
successor.left = current.left;
}
return current;
}
/**
* 获取删除节点的后继者
* 删除节点的后继者是在其右节点树种最小的节点
*
* @param deleteNode
* @return
*/
public TreeNode getDeleteSuccessor(TreeNode deleteNode) {
// 后继者
TreeNode successor = null;
TreeNode successorParent = null;
TreeNode current = deleteNode.right;
while (current != null) {
successorParent = successor;
successor = current;
current = current.left;
}
// 检查后继者(不可能有左节点树)是否有右节点树
// 如果它有右节点树,则替换后继者位置,加到后继者父亲节点的左节点.
if (successor != deleteNode.right) {
successorParent.left = successor.right;
successor.right = deleteNode.right;
}
return successor;
}
public void toString(TreeNode root) {
if (root != null) {
toString(root.left);
System.out.print("value = " + root.value + " -> ");
toString(root.right);
}
}
}
- 实现查找二叉查找树中某个节点的后继、前驱节点
- 实现二叉树前、中、后序以及按层遍历
public class TreeNode {
int val;
TreeNode left; //左孩子
TreeNode right; //右孩子
TreeNode(int x) {
val = x;
}
@Override
public String toString() {
return val + "";
}
}
每一个子树都遵循遍历方式
- 前序遍历
- 思想:按照根节点->左子树->右子树的顺序访问二叉树
- 步骤:(1)访问根节点;(2)采用先序递归遍历左子树;(3)采用先序递归遍历右子树;
- java实现前序遍历 获得节点引用 通过节点引用可获取节点信息
- 采用队列 先进先出 特点 并递归子树 还可不用递归
public static List<TreeNode> preOrder(TreeNode root) {
if (root == null) {
return null;
}
Queue<TreeNode> queue = new LinkedList<>();
List<TreeNode> list = new ArrayList<>();
queue.add(root);
while (!queue.isEmpty()) {
root = queue.poll();
list.add(root);
if (root.left != null ) {
queue.add(root.left);
preOrder(root.left);
}
if (root.right != null ) {
queue.add(root.right);
preOrder(root.right);
}
}
return list;
}
- 中序遍历
- 思想:按照左子树->根节点->右子树的顺序访问
- 步骤:(1)采用中序遍历左子树;(2)访问根节点;(3)采用中序遍历右子树
- java实现中序遍历 获得节点引用 通过节点引用获取节点信息
- 开始尝试使用队列 以为 与前序遍历 类似 ,然而没能解出来
- 采用栈 后进先出 特点
public static List < TreeNode > inorderTraversal(TreeNode root) {
List < TreeNode > res = new ArrayList < > ();
Stack < TreeNode > stack = new Stack< >();
TreeNode curr = root;
while (curr != null || !stack.isEmpty()) {
while (curr != null) {
stack.push(curr);
curr = curr.left;
}
curr = stack.pop();
res.add(curr);
curr = curr.right;
}
return res;
}
- 后序遍历
- 思想:按照左子树->右子树->根节点的顺序访问
- 步骤:(1)采用后序递归遍历左子树;(2)采用后序递归遍历右子树;(3)访问根节点;
- java实现后序遍历 获得节点引用
LinkedList<TreeNode> res = new LinkedList<>();
LinkedList<TreeNode> stack = new LinkedList<>();
if (root == null) {
return res;
}
stack.add(root);
while (!stack.isEmpty()) {
// 取顶端节点
root = stack.pollLast();
// 倒序添加
res.addFirst(root);
if (root.left != null) {
stack.add(root.left);
}
if (root.right != null) {
stack.add(root.right);
}
}
return res;
- 并完成leetcode上的验证二叉搜索树(98)及二叉树 层次遍历(102,107)
// 102题解 leetcode
public static List<List<Integer>> levelOrder(TreeNode root) {
if (root == null) {
return new ArrayList<>();
}
List<List<Integer>> lists = new ArrayList<>();
Queue<TreeNode> queue = new LinkedList<>();
queue.add(root);
while (!queue.isEmpty()) {
List<Integer> level = new ArrayList<>();
int count = queue.size();
while (count > 0) {
root = queue.poll();
level.add(root.val);
if (root.left != null) {
queue.add(root.left);
}
if (root.right != null) {
queue.add(root.right);
}
count--;
}
lists.add(level);
}
return lists;
堆
堆还在学emmm 只知道思想
- 实现一个小顶堆、大顶堆、优先级队列
- 实现堆排序
- 利用优先级队列合并 K 个有序数组
- 求一组动态数据集合的最大 Top K