- 数据结构如图所示: 哈希表和双向链表
- 由于查找的时间复杂为o(1),所以只能用哈希表。
- 由于插入删除移动的时间复杂度为o(1),所以只能用双向链表。
哈希表的key是结点值,value是一个指向双向链表的位置的指针,用双向链表才能在o(1)时间内移动或者删除结点。为了简便一些判断,在头部尾部都加入一个dummy结点。
- 查找get(key)
- 如果hash表中没有这个key值,返回-1
- 如果有,通过哈希表的value值找到单链表中的某个结点,将该节点移动到链表表头,并返回结点值
- 插入put(key,value)
- 如果key值不存在
- 在双向链表中创建一个新的结点,并在哈希表中创建一个键值对
- 判断此时的节点数是否超出了容量
- 如果超过容量,删除链表尾的结点,删除在哈希表中对应的项目,更新容量。
- 如果key值存在
- 通过哈希表定位结点,修改结点的值,并将该节点插入到表头。
- 如果key值不存在
太艰难了(加油!),注意事项如下
关于哈希表的操作不熟悉:
- 定义哈希表:unordered_map<int, DListNode*> HashMap;
- 判断哈希表是否为空:if (HashMap.count(key) == 0)return -1;
- 在哈希表中加入新的键值对:HashMap[key] = p;
- 根据哈希表的key值删除对应的表项:HashMap.erase(q->key);
对c++构造函数的语法不熟悉
- 使用初始化列表来初始化字段,冒号后面都是成员变量,在小括号里面直接赋值
- LRUCache(int _capacity) : capacity(_capacity), size(0){中间省略}
- DListNode() : key(0), value(0), front(nullptr), next(nullptr) {}
- DListNode(int _key, int _value) : key(_key), value(_value), front(nullptr),next(nullptr){}
对数据结构理解不透彻
- 双向链表的结点要同时存储key和value:存储value是因为get函数是由key查找value,虽然哈希表的value是一个指针,但是指针指向的双链表结点应该返回给用户一个value值。存储key是因为当容量过大时,除了移除双链表表尾结点之外,还要移除哈希表中对应的表项,erase需要获取key值。
对双链表的各种断链接链操作还是蛮熟悉的,表扬!
struct DListNode {
int key,value;
struct DListNode* front;
struct DListNode* next;
DListNode() : key(0), value(0), front(nullptr), next(nullptr) {}//在结构体中定义构造函数,这是不带参数的
DListNode(int _key, int _value) : key(_key), value(_value), front(nullptr), next(nullptr){}//这是带参数的
};
class LRUCache {
private:
DListNode* head;
DListNode* tail;
int size;
int capacity;
unordered_map<int, DListNode*> HashMap;
public:
LRUCache(int _capacity) : capacity(_capacity), size(0) {//构造函数
head = new DListNode();
tail = new DListNode();
head->next = tail;
tail->front = head;
}
int get(int key) {
if (HashMap.count(key) == 0)return -1;//查找失败返回-1
DListNode* p=HashMap[key];
moveTohead(p);
return p->value;
}
void put(int key,int value) {
if (HashMap.count(key) == 0) {//如果不存在
//创建双链表结点
DListNode* p = new DListNode(key,value);
//插入双链表的表头
insertTohead(p);
//插入hash表
HashMap[key] = p;
++size;
if (size > capacity) {
//如果容量不足,删除表尾
DListNode* q=deleteTail();
//删除哈希表中对应的项
HashMap.erase(q->key);
//防止内存泄漏
delete q;
--size;
}
}
else {
//如果存在
DListNode* p = HashMap[key];
p->value = value;
moveTohead(p);
}
}
DListNode* deleteTail() {
DListNode* p = tail->front;
p->front->next = tail;
tail->front = p->front;
return p;
}
void insertTohead(DListNode* p){
p->front = head;
p->next = head->next;
head->next->front=p;
head->next = p;
}
void moveTohead(DListNode* p) {
p->front->next = p->next;
p->next->front = p->front;
//把p结点取下来
p->front = head;
p->next = head->next;
head->next->front = p;//p结点插入表头
head->next = p;
}
};