6.30 二刷二叉树
This commit is contained in:
parent
b814779b7d
commit
6976c55204
@ -1,105 +0,0 @@
|
|||||||
package linkedlist;
|
|
||||||
/**
|
|
||||||
* 题目: 146. LRU 缓存 (LRUCache)
|
|
||||||
* 描述:请你设计并实现一个满足 LRU (最近最少使用) 缓存 约束的数据结构。
|
|
||||||
* 实现 LRUCache 类:
|
|
||||||
* LRUCache(int capacity) 以 正整数 作为容量 capacity 初始化 LRU 缓存
|
|
||||||
* int get(int key) 如果关键字 key 存在于缓存中,则返回关键字的值,否则返回 -1 。
|
|
||||||
* void put(int key, int value) 如果关键字 key 已经存在,则变更其数据值 value ;如果不存在,则向缓存中插入该组 key-value 。如果插入操作导致关键字数量超过 capacity ,则应该 逐出 最久未使用的关键字。
|
|
||||||
* 函数 get 和 put 必须以 O(1) 的平均时间复杂度运行。
|
|
||||||
|
|
||||||
示例 1:
|
|
||||||
输入
|
|
||||||
["LRUCache", "put", "put", "get", "put", "get", "put", "get", "get", "get"]
|
|
||||||
[[2], [1, 1], [2, 2], [1], [3, 3], [2], [4, 4], [1], [3], [4]]
|
|
||||||
输出
|
|
||||||
[null, null, null, 1, null, -1, null, -1, 3, 4]
|
|
||||||
|
|
||||||
* 链接:https://leetcode.cn/problems/lru-cache/
|
|
||||||
*/
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
public class LRUCache {
|
|
||||||
class DLinkedNode {
|
|
||||||
int key;
|
|
||||||
int value;
|
|
||||||
DLinkedNode prev;
|
|
||||||
DLinkedNode next;
|
|
||||||
public DLinkedNode() {}
|
|
||||||
public DLinkedNode(int _key, int _value) {key = _key; value = _value;}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Map<Integer, DLinkedNode> cache = new HashMap<>();
|
|
||||||
private int size;
|
|
||||||
private int capacity;
|
|
||||||
private DLinkedNode head, tail;
|
|
||||||
|
|
||||||
public LRUCache(int capacity) {
|
|
||||||
this.size = 0;
|
|
||||||
this.capacity = capacity;
|
|
||||||
// 使用伪头部和伪尾部节点
|
|
||||||
head = new DLinkedNode();
|
|
||||||
tail = new DLinkedNode();
|
|
||||||
head.next = tail;
|
|
||||||
tail.prev = head;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int get(int key) {
|
|
||||||
DLinkedNode node = cache.get(key);
|
|
||||||
if (node == null) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
// 如果 key 存在,先通过哈希表定位,再移到头部
|
|
||||||
moveToHead(node);
|
|
||||||
return node.value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void put(int key, int value) {
|
|
||||||
DLinkedNode node = cache.get(key);
|
|
||||||
if (node == null) {
|
|
||||||
// 如果 key 不存在,创建一个新的节点
|
|
||||||
DLinkedNode newNode = new DLinkedNode(key, value);
|
|
||||||
// 添加进哈希表
|
|
||||||
cache.put(key, newNode);
|
|
||||||
// 添加至双向链表的头部
|
|
||||||
addToHead(newNode);
|
|
||||||
++size;
|
|
||||||
if (size > capacity) {
|
|
||||||
// 如果超出容量,删除双向链表的尾部节点
|
|
||||||
DLinkedNode tail = removeTail();
|
|
||||||
// 删除哈希表中对应的项
|
|
||||||
cache.remove(tail.key);
|
|
||||||
--size;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// 如果 key 存在,先通过哈希表定位,再修改 value,并移到头部
|
|
||||||
node.value = value;
|
|
||||||
moveToHead(node);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void addToHead(DLinkedNode node) {
|
|
||||||
node.prev = head;
|
|
||||||
node.next = head.next;
|
|
||||||
head.next.prev = node;
|
|
||||||
head.next = node;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void removeNode(DLinkedNode node) {
|
|
||||||
node.prev.next = node.next;
|
|
||||||
node.next.prev = node.prev;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void moveToHead(DLinkedNode node) {
|
|
||||||
removeNode(node);
|
|
||||||
addToHead(node);
|
|
||||||
}
|
|
||||||
|
|
||||||
private DLinkedNode removeTail() {
|
|
||||||
DLinkedNode res = tail.prev;
|
|
||||||
removeNode(res);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
}
|
|
67
src/main/java/linkedlist/MergeKLists.java
Normal file
67
src/main/java/linkedlist/MergeKLists.java
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
package linkedlist;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 题目: 23. 合并 K 个升序链表 (mergeKLists)
|
||||||
|
* 描述:给你一个链表数组,每个链表都已经按升序排列。
|
||||||
|
* 请你将所有链表合并到一个升序链表中,返回合并后的链表。
|
||||||
|
* 链接:https://leetcode.cn/problems/merge-k-sorted-lists
|
||||||
|
* <p>
|
||||||
|
* 输入:lists = [[1,4,5],[1,3,4],[2,6]]
|
||||||
|
* 输出:[1,1,2,3,4,4,5,6]
|
||||||
|
* 解释:链表数组如下:
|
||||||
|
* [
|
||||||
|
* 1->4->5,
|
||||||
|
* 1->3->4,
|
||||||
|
* 2->6
|
||||||
|
* ]
|
||||||
|
* 将它们合并到一个有序链表中得到。
|
||||||
|
* 1->1->2->3->4->4->5->6
|
||||||
|
*/
|
||||||
|
//二刷不会
|
||||||
|
public class MergeKLists {
|
||||||
|
//两两合并
|
||||||
|
public ListNode mergeKLists2(ListNode[] lists) {
|
||||||
|
ListNode ans = null;
|
||||||
|
for (int i = 0; i < lists.length; ++i) {
|
||||||
|
ans = mergeTwoLists(ans, lists[i]);
|
||||||
|
}
|
||||||
|
return ans;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ListNode mergeTwoLists(ListNode a, ListNode b) {
|
||||||
|
if (a == null || b == null) {
|
||||||
|
return a != null ? a : b;
|
||||||
|
}
|
||||||
|
ListNode head = new ListNode(0);
|
||||||
|
ListNode tail = head, aPtr = a, bPtr = b;
|
||||||
|
while (aPtr != null && bPtr != null) {
|
||||||
|
if (aPtr.val < bPtr.val) {
|
||||||
|
tail.next = aPtr;
|
||||||
|
aPtr = aPtr.next;
|
||||||
|
} else {
|
||||||
|
tail.next = bPtr;
|
||||||
|
bPtr = bPtr.next;
|
||||||
|
}
|
||||||
|
tail = tail.next;
|
||||||
|
}
|
||||||
|
tail.next = (aPtr != null ? aPtr : bPtr);
|
||||||
|
return head.next;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//分治合并
|
||||||
|
public ListNode mergeKLists(ListNode[] lists) {
|
||||||
|
return merge(lists, 0, lists.length - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ListNode merge(ListNode[] lists, int l, int r) {
|
||||||
|
if (l == r) {
|
||||||
|
return lists[l];
|
||||||
|
}
|
||||||
|
if (l > r) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
int mid = (l + r) >> 1;
|
||||||
|
return mergeTwoLists(merge(lists, l, mid), merge(lists, mid + 1, r));
|
||||||
|
}
|
||||||
|
}
|
@ -6,8 +6,20 @@ package tree;
|
|||||||
* 两节点之间路径的 长度 由它们之间边数表示。
|
* 两节点之间路径的 长度 由它们之间边数表示。
|
||||||
|
|
||||||
* 链接:https://leetcode.cn/problems/diameter-of-binary-tree/
|
* 链接:https://leetcode.cn/problems/diameter-of-binary-tree/
|
||||||
|
1
|
||||||
|
/ \
|
||||||
|
2 3
|
||||||
|
/ \
|
||||||
|
4 5
|
||||||
|
/ \
|
||||||
|
6 7
|
||||||
|
/ \
|
||||||
|
8 9
|
||||||
|
/ \
|
||||||
|
10 11
|
||||||
|
不一定经过root!
|
||||||
*/
|
*/
|
||||||
|
//二刷会做
|
||||||
public class DiameterOfBinaryTree {
|
public class DiameterOfBinaryTree {
|
||||||
|
|
||||||
private int maxDiameter = 0;
|
private int maxDiameter = 0;
|
||||||
|
@ -11,6 +11,7 @@ import java.util.List;
|
|||||||
* 链接:https://leetcode.cn/problems/binary-tree-inorder-traversal/
|
* 链接:https://leetcode.cn/problems/binary-tree-inorder-traversal/
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
//二刷会做
|
||||||
//递归会 迭代需记一下
|
//递归会 迭代需记一下
|
||||||
public class InorderTraversal {
|
public class InorderTraversal {
|
||||||
//递归
|
//递归
|
||||||
@ -29,6 +30,21 @@ public class InorderTraversal {
|
|||||||
inorder(root.right, res);
|
inorder(root.right, res);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<Integer> inorderTraversal2(TreeNode root) {
|
||||||
|
List<Integer> res=new ArrayList<>();
|
||||||
|
Deque<TreeNode>stack=new ArrayDeque<>();
|
||||||
|
while (root!=null || !stack.isEmpty()){
|
||||||
|
while (root!=null){
|
||||||
|
stack.push(root);
|
||||||
|
root=root.left;
|
||||||
|
}
|
||||||
|
root=stack.pop();
|
||||||
|
res.add(root.val);
|
||||||
|
root=root.right;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
//迭代+栈
|
//迭代+栈
|
||||||
public List<Integer> inorderTraversal1(TreeNode root) {
|
public List<Integer> inorderTraversal1(TreeNode root) {
|
||||||
List<Integer> res = new ArrayList<Integer>();
|
List<Integer> res = new ArrayList<Integer>();
|
||||||
|
@ -6,7 +6,24 @@ package tree;
|
|||||||
* 链接:https://leetcode.cn/problems/invert-binary-tree/
|
* 链接:https://leetcode.cn/problems/invert-binary-tree/
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
//二刷会做
|
||||||
public class InvertTree {
|
public class InvertTree {
|
||||||
|
void dfs(TreeNode root){
|
||||||
|
if(root!=null) {
|
||||||
|
TreeNode tp;
|
||||||
|
tp = root.left;
|
||||||
|
root.left = root.right;
|
||||||
|
root.right = tp;
|
||||||
|
dfs(root.left);
|
||||||
|
dfs(root.right);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public TreeNode invertTree2(TreeNode root) {
|
||||||
|
dfs(root);
|
||||||
|
return root;
|
||||||
|
}
|
||||||
|
|
||||||
|
//先调整父节点,再调子节点
|
||||||
public void invert(TreeNode root){
|
public void invert(TreeNode root){
|
||||||
if(root!=null){
|
if(root!=null){
|
||||||
TreeNode temp;
|
TreeNode temp;
|
||||||
@ -21,6 +38,7 @@ public class InvertTree {
|
|||||||
invert(root);
|
invert(root);
|
||||||
return root;
|
return root;
|
||||||
}
|
}
|
||||||
|
//先调子 再调父节点
|
||||||
public TreeNode invertTree(TreeNode root) {
|
public TreeNode invertTree(TreeNode root) {
|
||||||
if (root == null) {
|
if (root == null) {
|
||||||
return null;
|
return null;
|
||||||
|
@ -11,8 +11,10 @@ import java.util.Queue;
|
|||||||
|
|
||||||
*/
|
*/
|
||||||
//不会做,递归和迭代都写一下
|
//不会做,递归和迭代都写一下
|
||||||
|
//二刷不会
|
||||||
public class IsSymmetric {
|
public class IsSymmetric {
|
||||||
|
|
||||||
|
//递归
|
||||||
public boolean isSymmetric(TreeNode root) {
|
public boolean isSymmetric(TreeNode root) {
|
||||||
// 如果根节点为空,则认为是对称的
|
// 如果根节点为空,则认为是对称的
|
||||||
if (root == null) {
|
if (root == null) {
|
||||||
@ -40,6 +42,7 @@ public class IsSymmetric {
|
|||||||
&& isMirror(left.right, right.left);
|
&& isMirror(left.right, right.left);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//层序遍历
|
||||||
public boolean isSymmetric1(TreeNode root) {
|
public boolean isSymmetric1(TreeNode root) {
|
||||||
if (root == null) {
|
if (root == null) {
|
||||||
return true;
|
return true;
|
||||||
|
@ -15,7 +15,9 @@ import java.util.List;
|
|||||||
* 链接:https://leetcode.cn/problems/validate-binary-search-tree/
|
* 链接:https://leetcode.cn/problems/validate-binary-search-tree/
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
//二刷会做
|
||||||
public class IsValidBST {
|
public class IsValidBST {
|
||||||
|
|
||||||
//递归
|
//递归
|
||||||
public boolean helper(TreeNode node, long lower, long upper) {
|
public boolean helper(TreeNode node, long lower, long upper) {
|
||||||
if (node == null) {
|
if (node == null) {
|
||||||
@ -30,6 +32,7 @@ public class IsValidBST {
|
|||||||
return helper(root, Long.MIN_VALUE, Long.MAX_VALUE);
|
return helper(root, Long.MIN_VALUE, Long.MAX_VALUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//中序遍历
|
//中序遍历
|
||||||
public void dfs(TreeNode root,List<Integer>list){
|
public void dfs(TreeNode root,List<Integer>list){
|
||||||
if(root!=null){
|
if(root!=null){
|
||||||
|
@ -8,20 +8,24 @@ import java.util.List;
|
|||||||
* 描述:给定一个二叉搜索树的根节点 root ,和一个整数 k ,请你设计一个算法查找其中第 k 小的元素(从 1 开始计数)。
|
* 描述:给定一个二叉搜索树的根节点 root ,和一个整数 k ,请你设计一个算法查找其中第 k 小的元素(从 1 开始计数)。
|
||||||
|
|
||||||
* 链接:https://leetcode.cn/problems/kth-smallest-element-in-a-bst/
|
* 链接:https://leetcode.cn/problems/kth-smallest-element-in-a-bst/
|
||||||
|
进阶:如果二叉搜索树经常被修改(插入/删除操作)并且你需要频繁地查找第 k 小的值,你将如何优化算法?
|
||||||
*/
|
*/
|
||||||
|
//二刷会做
|
||||||
public class KthSmallest {
|
public class KthSmallest {
|
||||||
//中序遍历
|
//中序遍历
|
||||||
public void dfs(TreeNode root, List<Integer> list){
|
private int k, ans;
|
||||||
if(root!=null){
|
|
||||||
dfs(root.left,list);
|
|
||||||
list.add(root.val);
|
|
||||||
dfs(root.right,list);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public int kthSmallest(TreeNode root, int k) {
|
public int kthSmallest(TreeNode root, int k) {
|
||||||
List<Integer>list=new ArrayList<>();
|
this.k = k;
|
||||||
dfs(root,list);
|
dfs(root);
|
||||||
return list.get(k-1);
|
return ans;
|
||||||
|
}
|
||||||
|
private void dfs(TreeNode node) {
|
||||||
|
if (node == null) return;
|
||||||
|
dfs(node.left);
|
||||||
|
if (--k == 0) { // 访问到第 k 个
|
||||||
|
ans = node.val;
|
||||||
|
return; // 提前结束递归
|
||||||
|
}
|
||||||
|
dfs(node.right);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,7 @@ import java.util.Queue;
|
|||||||
* 链接:https://leetcode.cn/problems/binary-tree-level-order-traversal/
|
* 链接:https://leetcode.cn/problems/binary-tree-level-order-traversal/
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
//二刷会做
|
||||||
public class LevelOrder {
|
public class LevelOrder {
|
||||||
public List<List<Integer>> levelOrder(TreeNode root) {
|
public List<List<Integer>> levelOrder(TreeNode root) {
|
||||||
List<List<Integer>>res=new ArrayList<>();
|
List<List<Integer>>res=new ArrayList<>();
|
||||||
|
@ -13,6 +13,7 @@ import java.util.Queue;
|
|||||||
* 链接:https://leetcode.cn/problems/maximum-depth-of-binary-tree/
|
* 链接:https://leetcode.cn/problems/maximum-depth-of-binary-tree/
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
//二刷会做
|
||||||
public class MaxDepth {
|
public class MaxDepth {
|
||||||
//递归
|
//递归
|
||||||
int dfs(TreeNode root){
|
int dfs(TreeNode root){
|
||||||
@ -23,6 +24,7 @@ public class MaxDepth {
|
|||||||
public int maxDepth1(TreeNode root) {
|
public int maxDepth1(TreeNode root) {
|
||||||
return dfs(root);
|
return dfs(root);
|
||||||
}
|
}
|
||||||
|
|
||||||
//bfs
|
//bfs
|
||||||
public int maxDepth(TreeNode root) {
|
public int maxDepth(TreeNode root) {
|
||||||
if (root == null) {
|
if (root == null) {
|
||||||
|
@ -6,6 +6,7 @@ package tree;
|
|||||||
* 链接:https://leetcode.cn/problems/convert-sorted-array-to-binary-search-tree/
|
* 链接:https://leetcode.cn/problems/convert-sorted-array-to-binary-search-tree/
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
//二刷不会
|
||||||
public class SortedArrayToBST {
|
public class SortedArrayToBST {
|
||||||
//分治
|
//分治
|
||||||
TreeNode func(int left,int right ,int[] nums){
|
TreeNode func(int left,int right ,int[] nums){
|
||||||
|
164
src/main/java/实现类功能/LRUCache.java
Normal file
164
src/main/java/实现类功能/LRUCache.java
Normal file
@ -0,0 +1,164 @@
|
|||||||
|
package 实现类功能;
|
||||||
|
/**
|
||||||
|
* 题目: 146. LRU 缓存 (LRUCache)
|
||||||
|
* 描述:请你设计并实现一个满足 LRU (最近最少使用) 缓存 约束的数据结构。
|
||||||
|
* 实现 LRUCache 类:
|
||||||
|
* LRUCache(int capacity) 以 正整数 作为容量 capacity 初始化 LRU 缓存
|
||||||
|
* int get(int key) 如果关键字 key 存在于缓存中,则返回关键字的值,否则返回 -1 。
|
||||||
|
* void put(int key, int value) 如果关键字 key 已经存在,则变更其数据值 value ;如果不存在,则向缓存中插入该组 key-value 。如果插入操作导致关键字数量超过 capacity ,则应该 逐出 最久未使用的关键字。
|
||||||
|
* 函数 get 和 put 必须以 O(1) 的平均时间复杂度运行。
|
||||||
|
|
||||||
|
示例 1:
|
||||||
|
输入
|
||||||
|
["LRUCache", "put", "put", "get", "put", "get", "put", "get", "get", "get"]
|
||||||
|
[[2], [1, 1], [2, 2], [1], [3, 3], [2], [4, 4], [1], [3], [4]]
|
||||||
|
输出
|
||||||
|
[null, null, null, 1, null, -1, null, -1, 3, 4]
|
||||||
|
|
||||||
|
* 链接:https://leetcode.cn/problems/lru-cache/
|
||||||
|
*/
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
//二刷不会 学习
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对于 get 操作,首先判断 key 是否存在:
|
||||||
|
* 如果 key 不存在,则返回 −1;
|
||||||
|
* 如果 key 存在,则 key 对应的节点是最近被使用的节点。通过哈希表定位到该节点在双向链表中的位置,并将其移动到双向链表的头部,最后返回该节点的值。
|
||||||
|
*
|
||||||
|
* 对于 put 操作,首先判断 key 是否存在:
|
||||||
|
* 如果 key 不存在,使用 key 和 value 创建一个新的节点,在双向链表的头部添加该节点,并将 key 和该节点添加进哈希表中。然后判断双向链表的节点数是否超出容量,如果超出容量,则删除双向链表的尾部节点,并删除哈希表中对应的项;
|
||||||
|
* 如果 key 存在,则与 get 操作类似,先通过哈希表定位,再将对应的节点的值更新为 value,并将该节点移到双向链表的头部。
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* 注意,key和value不必相等
|
||||||
|
*/
|
||||||
|
public class LRUCache {
|
||||||
|
|
||||||
|
/* ----------------------------- 链表节点定义 ----------------------------- */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 双向链表节点
|
||||||
|
*/
|
||||||
|
class DLinkedNode {
|
||||||
|
int key; // 保存 key:便于淘汰节点时同步从 cache 中删除
|
||||||
|
int value; // 保存 value
|
||||||
|
DLinkedNode prev; // 前驱
|
||||||
|
DLinkedNode next; // 后继
|
||||||
|
|
||||||
|
public DLinkedNode() {}
|
||||||
|
|
||||||
|
public DLinkedNode(int _key, int _value) {
|
||||||
|
key = _key;
|
||||||
|
value = _value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ----------------------------- 成员变量 ----------------------------- */
|
||||||
|
|
||||||
|
private final Map<Integer, DLinkedNode> cache = new HashMap<>(); // 哈希表
|
||||||
|
private int size; // 当前键值对数量
|
||||||
|
private final int capacity; // 最大容量
|
||||||
|
|
||||||
|
// 伪头、伪尾(固定不动)
|
||||||
|
private final DLinkedNode head;
|
||||||
|
private final DLinkedNode tail;
|
||||||
|
|
||||||
|
/* ----------------------------- 构造函数 ----------------------------- */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param capacity 缓存最大容量 (正整数)
|
||||||
|
*/
|
||||||
|
public LRUCache(int capacity) {
|
||||||
|
this.size = 0;
|
||||||
|
this.capacity = capacity;
|
||||||
|
|
||||||
|
// 创建伪头、伪尾并相连
|
||||||
|
head = new DLinkedNode();
|
||||||
|
tail = new DLinkedNode();
|
||||||
|
head.next = tail;
|
||||||
|
tail.prev = head;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ----------------------------- 公共接口 ----------------------------- */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param key 查询的键
|
||||||
|
* @return 若存在则返回对应 value,否则返回 -1
|
||||||
|
*/
|
||||||
|
public int get(int key) {
|
||||||
|
DLinkedNode node = cache.get(key);
|
||||||
|
if (node == null) { // 不存在
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
// 存在:移动到链表头部(标记为最近使用)
|
||||||
|
moveToHead(node);
|
||||||
|
return node.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 写入或更新键值对
|
||||||
|
* @param key 键
|
||||||
|
* @param value 值
|
||||||
|
*/
|
||||||
|
public void put(int key, int value) {
|
||||||
|
DLinkedNode node = cache.get(key);
|
||||||
|
|
||||||
|
if (node == null) {
|
||||||
|
/* ---------- 新键 ---------- */
|
||||||
|
DLinkedNode newNode = new DLinkedNode(key, value);
|
||||||
|
cache.put(key, newNode); // 哈希表记录
|
||||||
|
addToHead(newNode); // 链表头插
|
||||||
|
++size;
|
||||||
|
|
||||||
|
// 超容量:弹出尾节点(最久未使用)
|
||||||
|
if (size > capacity) {
|
||||||
|
DLinkedNode tail = removeTail(); // 真尾节点
|
||||||
|
cache.remove(tail.key); // 同步删除哈希表项
|
||||||
|
--size;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* ---------- 已存在键:更新值并提到头部 ---------- */
|
||||||
|
node.value = value;
|
||||||
|
moveToHead(node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ----------------------------- 链表操作辅助 ----------------------------- */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将节点插到伪头之后(链表头部)
|
||||||
|
*/
|
||||||
|
private void addToHead(DLinkedNode node) {
|
||||||
|
node.prev = head;
|
||||||
|
node.next = head.next;
|
||||||
|
head.next.prev = node;
|
||||||
|
head.next = node;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从当前链表中删除节点(不删除哈希表项)
|
||||||
|
*/
|
||||||
|
private void removeNode(DLinkedNode node) {
|
||||||
|
node.prev.next = node.next;
|
||||||
|
node.next.prev = node.prev;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将节点移动到头部:先删再头插
|
||||||
|
*/
|
||||||
|
private void moveToHead(DLinkedNode node) {
|
||||||
|
removeNode(node);
|
||||||
|
addToHead(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 弹出尾部节点(真尾 = 伪尾的前驱)
|
||||||
|
* @return 被移除的节点
|
||||||
|
*/
|
||||||
|
private DLinkedNode removeTail() {
|
||||||
|
DLinkedNode res = tail.prev;
|
||||||
|
removeNode(res);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user