B树(B-Tree)是一种自平衡的树,主要用于数据库和文件系统中。它通过在内部节点中保持多个键来允许更低的树高度,从而优化了数据的读取和写入操作。下面是关于B树的一些关键知识点:
定义和特性
- 平衡性:B树是一棵平衡树,意味着任何两个叶子节点之间的最大高度差为1。
- 分支度(阶):B树的“阶”是指树中节点的最大子节点数目。例如,阶为
m
的B树中每个节点最多有m
个子节点。 - 节点存储:每个节点可以存储多个键值(至少1个,最多
m-1
个)以及指向其子节点的指针(最多m
个)。键在节点内部按升序排列。 - 叶子节点同级:所有叶子节点都位于同一层。
操作
B树支持数据的插入、删除和查找操作,这些操作都能够保持树的平衡性:
- 插入:插入新键时,如果节点未满(即包含少于
m-1
个键),则键直接插入适当位置。如果节点已满,则节点先分裂成两个节点,然后再插入键。 - 删除:删除键时,如果键在一个叶子节点且不会导致节点键数少于最小值,则直接删除。如果删除导致违反B树的性质,则需要通过键的旋转或合并节点来保持平衡。
- 查找:查找操作遍历树从根节点到叶子节点,寻找匹配的键。
应用
- 数据库索引:B树是许多类型的数据库系统(如MySQL、PostgreSQL)中用于索引的标准数据结构。
- 文件系统:B树用于文件系统中管理和索引文件数据。
B+树
B+树是B树的一个变种,广泛用于数据库和操作系统的文件系统中。它的特点包括:
- 所有值都保存在叶子节点中,内部节点只存储键信息。
- 叶子节点之间按键顺序链接,便于范围查询。
B树和B+树通过减少磁盘I/O操作次数来优化大量数据的存储和查询,是处理大数据集合时非常有效的数据结构。为了帮助你准备面试,这里有三道适合大厂面试的编程题,涵盖了数据结构、算法和系统设计的基本知识,以及每题的Java实现代码。
题目1:合并两个有序链表
将两个升序链表合并为一个新的升序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
public class ListNode {int val;ListNode next;ListNode() {}ListNode(int val) { this.val = val; }ListNode(int val, ListNode next) { this.val = val; this.next = next; }
}public class Solution {public ListNode mergeTwoLists(ListNode l1, ListNode l2) {ListNode dummy = new ListNode(-1);ListNode current = dummy;while (l1 != null && l2 != null) {if (l1.val < l2.val) {current.next = l1;l1 = l1.next;} else {current.next = l2;l2 = l2.next;}current = current.next;}current.next = (l1 != null) ? l1 : l2;return dummy.next;}
}
题目2:二叉树的右视图
给定一个二叉树,想象自己站在它的右侧,按照从顶部到底部的顺序,返回你能看到的节点值。
import java.util.List;
import java.util.ArrayList;
import java.util.Queue;
import java.util.LinkedList;public class TreeNode {int val;TreeNode left;TreeNode right;TreeNode(int x) { val = x; }
}class Solution {public List<Integer> rightSideView(TreeNode root) {List<Integer> view = new ArrayList<>();if (root == null) return view;Queue<TreeNode> queue = new LinkedList<>();queue.add(root);while (!queue.isEmpty()) {int levelLength = queue.size();for (int i = 0; i < levelLength; i++) {TreeNode currentNode = queue.poll();if (i == levelLength - 1) view.add(currentNode.val);if (currentNode.left != null) queue.add(currentNode.left);if (currentNode.right != null) queue.add(currentNode.right);}}return view;}
}
题目3:LRU缓存机制
设计和实现一个 LRU (最近最少使用) 缓存机制。实现 LRUCache
类:
LRUCache(int capacity)
以正整数作为容量 capacity 初始化 LRU 缓存int get(int key)
如果关键字 key 存在于缓存中,则返回关键字的值,否则返回 -1 。void put(int key, int value)
如果关键字已经存在,则变更其数据值;如果关键字不存在,则插入该组「关键字-值」。当缓存容量达到上限时,它应该在写入新数据之前删除最久未使用的数据值,从而为新的数据值留出空间。
import java.util.LinkedHashMap;
import java.util.Map;public class LRUCache extends LinkedHashMap<Integer, Integer> {private int capacity;public LRUCache(int capacity) {super(capacity, 0.75F, true);this.capacity = capacity;}public int get(int key) {return super.getOrDefault(key, -1);}public void put(int key, int value) {super.put(key, value);}@Overrideprotected boolean removeEldestEntry(Map.Entry<Integer, Integer> eldest) {return size() > capacity;}
}
这三道题目分别考察了链表操作、树的遍历和设计能力,是面试中经常出现的题型。在准备这些题目时,不仅要理解解题思路,还要注意代码的编写风格和效率。希望这些示例能帮助你在面试中获得成功。