《Java数据结构与算法:提升代码效率的关键-二叉树篇》

一 . 二叉树数据存储

二叉树是一种每个节点最多有两个子节点的树结构,称为左子节点和右子节点。在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;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

博哥爱学习

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值