一 . 二叉树数据存储
二叉树是一种每个节点最多有两个子节点的树结构,称为左子节点和右子节点。在Java中,我们可以通过自定义类来实现二叉树的存储。
1. 二叉树节点类实现
(博哥有话说:在树的结构中有三个域,左指针域,数据域,右指针域,
分别储存左孩子,数据,右孩子)
public class TreeNode<T> {
T data; // 存储的数据
TreeNode<T> left; // 左子节点
TreeNode<T> right; // 右子节点
public TreeNode(T data) {
this.data = data;
this.left = null;
this.right = null;
}
// 添加左子节点
public void addLeft(T data) {
this.left = new TreeNode<>(data);
}
// 添加右子节点
public void addRight(T data) {
this.right = new TreeNode<>(data);
}
@Override
public String toString() {
return data.toString();
}
}
2. 二叉树容器类实现
public class BinaryTree<T> {
private TreeNode<T> root;
public BinaryTree() {
this.root = null;
}
public BinaryTree(T rootData) {
this.root = new TreeNode<>(rootData);
}
// 获取根节点
public TreeNode<T> getRoot() {
return root;
}
// 设置根节点
public void setRoot(TreeNode<T> root) {
this.root = root;
}
// 判断树是否为空
public boolean isEmpty() {
return root == null;
}
// 清空树
public void clear() {
this.root = null;
}
// 插入数据(简单实现,实际应根据业务规则)
public void insert(T data) {
if (root == null) {
root = new TreeNode<>(data);
return;
}
Queue<TreeNode<T>> queue = new LinkedList<>();
queue.add(root);
while (!queue.isEmpty()) {
TreeNode<T> current = queue.poll();
if (current.left == null) {
current.left = new TreeNode<>(data);
break;
} else {
queue.add(current.left);
}
if (current.right == null) {
current.right = new TreeNode<>(data);
break;
} else {
queue.add(current.right);
}
}
}
}
二 . 二叉树数据获取
获取二叉树中的数据通常通过遍历实现,常见的遍历方式有前序、中序、后序和层次遍历。
(博哥有话说:好记的方法就是什么顺序就是根在哪,
D - 根,L - Left(左),R - RIGHT(右)
比如前序(DLR)中序(LDR)后序(LRD))
遍历实现
public class BinaryTree<T> {
// ... 前面的代码 ...
// 前序遍历(根-左-右)
public List<T> preOrderTraversal() {
List<T> result = new ArrayList<>();
preOrder(root, result);
return result;
}
private void preOrder(TreeNode<T> node, List<T> result) {
if (node == null) return;
result.add(node.data);
preOrder(node.left, result);
preOrder(node.right, result);
}
// 中序遍历(左-根-右)
public List<T> inOrderTraversal() {
List<T> result = new ArrayList<>();
inOrder(root, result);
return result;
}
private void inOrder(TreeNode<T> node, List<T> result) {
if (node == null) return;
inOrder(node.left, result);
result.add(node.data);
inOrder(node.right, result);
}
// 后序遍历(左-右-根)
public List<T> postOrderTraversal() {
List<T> result = new ArrayList<>();
postOrder(root, result);
return result;
}
private void postOrder(TreeNode<T> node, List<T> result) {
if (node == null) return;
postOrder(node.left, result);
postOrder(node.right, result);
result.add(node.data);
}
// 层次遍历(广度优先)
public List<T> levelOrderTraversal() {
List<T> result = new ArrayList<>();
if (root == null) return result;
Queue<TreeNode<T>> queue = new LinkedList<>();
queue.add(root);
while (!queue.isEmpty()) {
TreeNode<T> current = queue.poll();
result.add(current.data);
if (current.left != null) {
queue.add(current.left);
}
if (current.right != null) {
queue.add(current.right);
}
}
return result;
}
// 获取树的高度
public int getHeight() {
return calculateHeight(root);
}
private int calculateHeight(TreeNode<T> node) {
if (node == null) return 0;
int leftHeight = calculateHeight(node.left);
int rightHeight = calculateHeight(node.right);
return Math.max(leftHeight, rightHeight) + 1;
}
// 获取节点数量
public int size() {
return countNodes(root);
}
private int countNodes(TreeNode<T> node) {
if (node == null) return 0;
return 1 + countNodes(node.left) + countNodes(node.right);
}
}
三 . 二叉树数据查询
在二叉树中查询数据需要遍历整个树结构,以下是几种常见的查询方法。
查询实现
public class BinaryTree<T> {
// ... 前面的代码 ...
// 判断是否包含某个元素
public boolean contains(T data) {
return contains(root, data);
}
private boolean contains(TreeNode<T> node, T data) {
if (node == null) return false;
if (node.data.equals(data)) return true;
return contains(node.left, data) || contains(node.right, data);
}
// 查找指定元素的节点
public TreeNode<T> findNode(T data) {
return findNode(root, data);
}
private TreeNode<T> findNode(TreeNode<T> node, T data) {
if (node == null) return null;
if (node.data.equals(data)) return node;
TreeNode<T> leftResult = findNode(node.left, data);
if (leftResult != null) return leftResult;
return findNode(node.right, data);
}
// 查找父节点
public TreeNode<T> findParent(T data) {
if (root == null || root.data.equals(data)) return null;
return findParent(root, data);
}
private TreeNode<T> findParent(TreeNode<T> node, T data) {
if (node == null) return null;
if ((node.left != null && node.left.data.equals(data)) ||
(node.right != null && node.right.data.equals(data))) {
return node;
}
TreeNode<T> leftResult = findParent(node.left, data);
if (leftResult != null) return leftResult;
return findParent(node.right, data);
}
// 查找最小节点(假设实现了Comparable接口)
@SuppressWarnings("unchecked")
public T findMin() {
if (root == null) return null;
Comparable<T> min = (Comparable<T>) root.data;
return findMin(root, min);
}
@SuppressWarnings("unchecked")
private T findMin(TreeNode<T> node, Comparable<T> min) {
if (node == null) return (T) min;
if (((Comparable<T>) node.data).compareTo((T) min) < 0) {
min = (Comparable<T>) node.data;
}
T leftMin = findMin(node.left, min);
T rightMin = findMin(node.right, min);
Comparable<T> tempMin = min;
if (((Comparable<T>) leftMin).compareTo((T) tempMin) < 0) {
tempMin = (Comparable<T>) leftMin;
}
if (((Comparable<T>) rightMin).compareTo((T) tempMin) < 0) {
tempMin = (Comparable<T>) rightMin;
}
return (T) tempMin;
}
// 查找最大节点(假设实现了Comparable接口)
@SuppressWarnings("unchecked")
public T findMax() {
if (root == null) return null;
Comparable<T> max = (Comparable<T>) root.data;
return findMax(root, max);
}
@SuppressWarnings("unchecked")
private T findMax(TreeNode<T> node, Comparable<T> max) {
if (node == null) return (T) max;
if (((Comparable<T>) node.data).compareTo((T) max) > 0) {
max = (Comparable<T>) node.data;
}
T leftMax = findMax(node.left, max);
T rightMax = findMax(node.right, max);
Comparable<T> tempMax = max;
if (((Comparable<T>) leftMax).compareTo((T) tempMax) > 0) {
tempMax = (Comparable<T>) leftMax;
}
if (((Comparable<T>) rightMax).compareTo((T) tempMax) > 0) {
tempMax = (Comparable<T>) rightMax;
}
return (T) tempMax;
}
}
四 . 二叉树数据删除
删除二叉树中的节点需要考虑多种情况,特别是当删除的节点有子节点时。
删除实现
public class BinaryTree<T> {
// ... 前面的代码 ...
// 删除指定数据的节点
public boolean delete(T data) {
if (root == null) return false;
// 如果要删除的是根节点
if (root.data.equals(data)) {
if (root.left == null && root.right == null) {
root = null;
} else if (root.left == null) {
root = root.right;
} else if (root.right == null) {
root = root.left;
} else {
// 找到右子树的最小节点
TreeNode<T> minNode = findMinNode(root.right);
// 复制数据
root.data = minNode.data;
// 删除右子树的最小节点
deleteNode(root, root.right, minNode.data);
}
return true;
}
return deleteNode(null, root, data);
}
private boolean deleteNode(TreeNode<T> parent, TreeNode<T> current, T data) {
if (current == null) return false;
if (current.data.equals(data)) {
// 情况1: 叶子节点
if (current.left == null && current.right == null) {
if (parent.left == current) {
parent.left = null;
} else {
parent.right = null;
}
}
// 情况2: 只有左子节点
else if (current.right == null) {
if (parent.left == current) {
parent.left = current.left;
} else {
parent.right = current.left;
}
}
// 情况3: 只有右子节点
else if (current.left == null) {
if (parent.left == current) {
parent.left = current.right;
} else {
parent.right = current.right;
}
}
// 情况4: 有两个子节点
else {
// 找到右子树的最小节点
TreeNode<T> minNode = findMinNode(current.right);
// 复制数据
current.data = minNode.data;
// 删除右子树的最小节点
deleteNode(current, current.right, minNode.data);
}
return true;
}
// 递归查找要删除的节点
if (deleteNode(current, current.left, data)) {
return true;
}
return deleteNode(current, current.right, data);
}
// 辅助方法:找到子树中的最小节点
private TreeNode<T> findMinNode(TreeNode<T> node) {
while (node.left != null) {
node = node.left;
}
return node;
}
// 删除整棵树
public void deleteTree() {
root = null;
// 在Java中,垃圾回收器会自动回收内存
}
// 删除指定子树
public void deleteSubtree(T data) {
TreeNode<T> node = findNode(data);
if (node != null) {
if (node == root) {
root = null;
} else {
TreeNode<T> parent = findParent(data);
if (parent.left == node) {
parent.left = null;
} else {
parent.right = null;
}
}
}
}
}
五 . 自定义Map工具类
我们可以基于二叉树实现一个简单的Map结构,类似于Java中的TreeMap。
java.util.TreeMap(红黑树)
(博哥有话说:相较于List体系,Map体系是存在键值对的)
import java.util.Map;
import java.util.TreeMap;
//TreeMap 特点:不重复,无索引,可排序
//数据结构:红黑树
public class TreeMapDemo {
public static void main(String[] args) {
TreeMap<String, Integer> fruitMap = new TreeMap<>();
fruitMap.put("Apple", 1);
fruitMap.put("Banana", 2);
fruitMap.put("Cherry", 3);
// 获取指定键的值
Integer bananaValue = fruitMap.get("Banana"); // 返回 4
// 获取不存在的键返回 null
Integer orangeValue = fruitMap.get("Orange"); // 返回 null
// 获取默认值
Integer defaultValue = fruitMap.getOrDefault("Orange", 0); // 返回 0
// 删除指定键的映射
fruitMap.remove("Banana"); // 删除 Banana 条目
// 删除并返回被删除的值
Integer removedValue = fruitMap.remove("Cherry"); // 返回 3
// 清空 TreeMap
fruitMap.clear();
}
}
(博哥有话说:在下面的方法中,能看出内置的Map更方便于自己建立的,方法更加便捷)
import java.util.Map;
import java.util.TreeMap;
//TreeMap 特点:不重复,无索引,可排序
//数据结构:红黑树
public class TreeMapDemo {
public static void main(String[] args) {
TreeMap<String, Integer> map = new TreeMap<>();
map.put("A", 1);
map.put("B", 2);
map.put("C", 3);
String firstKey = map.firstKey();
System.out.println(firstKey);// "A"
String lastKey = map.lastKey();
System.out.println(lastKey);// "C"
Map.Entry<String, Integer> firstEntry = map.firstEntry();
System.out.println(firstEntry);// "A"=1
Map.Entry<String, Integer> lastEntry = map.lastEntry();
System.out.println(lastEntry);// "C"=3
// 遍历键
for (String key : map.keySet()) {
System.out.println(key);
}
// 遍历值
for (Integer value : map.values()) {
System.out.println(value);
}
}
}
自定义TreeMap实现
public class BinaryTreeMap<K extends Comparable<K>, V> {
private class Entry {
K key;
V value;
Entry left;
Entry right;
public Entry(K key, V value) {
this.key = key;
this.value = value;
this.left = null;
this.right = null;
}
}
private Entry root;
private int size;
public BinaryTreeMap() {
root = null;
size = 0;
}
// 插入或更新键值对
public void put(K key, V value) {
root = put(root, key, value);
}
private Entry put(Entry node, K key, V value) {
if (node == null) {
size++;
return new Entry(key, value);
}
int cmp = key.compareTo(node.key);
if (cmp < 0) {
node.left = put(node.left, key, value);
} else if (cmp > 0) {
node.right = put(node.right, key, value);
} else {
node.value = value; // 更新已有键的值
}
return node;
}
// 获取指定键的值
public V get(K key) {
Entry node = get(root, key);
return node == null ? null : node.value;
}
private Entry get(Entry node, K key) {
if (node == null) return null;
int cmp = key.compareTo(node.key);
if (cmp < 0) {
return get(node.left, key);
} else if (cmp > 0) {
return get(node.right, key);
} else {
return node;
}
}
// 判断是否包含指定键
public boolean containsKey(K key) {
return get(root, key) != null;
}
// 删除指定键
public void remove(K key) {
root = remove(root, key);
}
private Entry remove(Entry node, K key) {
if (node == null) return null;
int cmp = key.compareTo(node.key);
if (cmp < 0) {
node.left = remove(node.left, key);
} else if (cmp > 0) {
node.right = remove(node.right, key);
} else {
// 找到要删除的节点
size--;
// 情况1: 只有一个子节点或没有子节点
if (node.left == null) {
return node.right;
}
if (node.right == null) {
return node.left;
}
// 情况2: 有两个子节点
// 找到右子树的最小节点
Entry minNode = findMin(node.right);
// 复制键值
node.key = minNode.key;
node.value = minNode.value;
// 删除右子树的最小节点
node.right = remove(node.right, minNode.key);
}
return node;
}
// 辅助方法:找到子树中的最小节点
private Entry findMin(Entry node) {
while (node.left != null) {
node = node.left;
}
return node;
}
// 获取Map大小
public int size() {
return size;
}
// 判断Map是否为空
public boolean isEmpty() {
return size == 0;
}
// 清空Map
public void clear() {
root = null;
size = 0;
}
// 获取所有键的有序列表(中序遍历)
public List<K> keySet() {
List<K> keys = new ArrayList<>();
inOrder(root, keys);
return keys;
}
private void inOrder(Entry node, List<K> keys) {
if (node == null) return;
inOrder(node.left, keys);
keys.add(node.key);
inOrder(node.right, keys);
}
// 获取所有值的有序列表(按照键的顺序)
public List<V> values() {
List<V> values = new ArrayList<>();
inOrderValues(root, values);
return values;
}
private void inOrderValues(Entry node, List<V> values) {
if (node == null) return;
inOrderValues(node.left, values);
values.add(node.value);
inOrderValues(node.right, values);
}
// 获取所有键值对的有序列表
public List<Map.Entry<K, V>> entrySet() {
List<Map.Entry<K, V>> entries = new ArrayList<>();
inOrderEntries(root, entries);
return entries;
}
private void inOrderEntries(Entry node, List<Map.Entry<K, V>> entries) {
if (node == null) return;
inOrderEntries(node.left, entries);
entries.add(new AbstractMap.SimpleEntry<>(node.key, node.value));
inOrderEntries(node.right, entries);
}
// 获取最小键
public K firstKey() {
if (root == null) return null;
Entry minNode = findMin(root);
return minNode.key;
}
// 获取最大键
public K lastKey() {
if (root == null) return null;
Entry maxNode = findMax(root);
return maxNode.key;
}
// 辅助方法:找到子树中的最大节点
private Entry findMax(Entry node) {
while (node.right != null) {
node = node.right;
}
return node;
}
}

被折叠的 条评论
为什么被折叠?



