關于LRU緩存簡單記錄以及代碼補全。

目錄

  • 大概思路
  • 時間空間復雜度分析
  • 指針操作具體細節
    • 代碼
    • 雙向鏈表設計
    • 私有成員變量設計:
    • 構造函數和析構函數設計:
    • get與put具體設計
    • 雙向指針的具體細節
      • 添加到頭節點函數
      • 刪除尾節點函數
      • 刪除節點函數
      • 刪除節點函數
    • 感想

今天面試考到LRU,太緊張了,完全傻了。。。趕緊做個記錄

LRU是Least Recently Used的縮寫,即最近最少使用,是一種常用的頁面置換算法,選擇最近最久未使用的頁面予以淘汰。

LRU 緩存:
設計和構建一個“最近最少使用”緩存,該緩存會刪除最近最少使用的項目。緩存應該從鍵映射到值(允許你插入和檢索特定鍵對應的值),并在初始化時指定最大容量。當緩存被填滿時,它應該刪除最近最少使用的項目。

它應該支持以下操作: 獲取數據 get 和 寫入數據 put 。

獲取數據 get(key) - 如果密鑰 (key) 存在于緩存中,則獲取密鑰的值(總是正數),否則返回 -1。
寫入數據 put(key, value) - 如果密鑰不存在,則寫入其數據值。當緩存容量達到上限時,它應該在寫入新數據之前刪除最近最少使用的數據值,從而為新的數據值留出空間。

示例:

LRUCache cache = new LRUCache( 2 /* 緩存容量 */ );
cache.put(1, 1);
cache.put(2, 2);
cache.get(1); // 返回 1
cache.put(3, 3); // 該操作會使得密鑰 2 作廢
cache.get(2); // 返回 -1 (未找到)
cache.put(4, 4); // 該操作會使得密鑰 1 作廢
cache.get(1); // 返回 -1 (未找到)
cache.get(3); // 返回 3
cache.get(4); // 返回 4

大概思路

這一題面試官說用到雙向鏈表和哈希map。
雙向鏈表按照被使用的順序存儲了這些鍵值對,靠近頭部的鍵值對是最近使用的,而靠近尾部的鍵值對是最久未使用的。
哈希表,通過緩存數據的鍵映射到其在雙向鏈表中的位置。
注意雙向鏈表中存儲的元素是key, value;
哈希表中存儲的是key和雙向鏈表節點。

太緊張了,導致一開始都不知道map的value具體含義,還以為是頻率計數用的。。。其實并無特殊含義,僅僅是一個值。
get操作:
1、判斷key是否存在,不存在返回-1
2、如果存在,返回該節點值并且將對應的節點移動到雙向鏈表的頭部。
put操作:
1、判斷key是否存在
2、key不存在,使用key和value創建一個新的節點,然后在雙向鏈表頭部插入這個鍵值對。
3、將 key 和該節點添加進哈希表中。
4、判斷雙向鏈表的節點數是否超出容量,如果超出容量,則刪除雙向鏈表的尾部節點,并刪除哈希表中對應的項;
5、key存在。先通過哈希表定位,再將對應的節點的值更新為 value,并將該節點移到雙向鏈表的頭部。

時間空間復雜度分析

訪問哈希表的時間復雜度為 O(1)
在雙向鏈表頭和尾部增減節點時間復雜度也是O(1)

指針操作具體細節

將一個節點移動到頭部可以分為:
1、刪除該節點
2、在頭節點前插入一個相同的節點

還有就是虛擬頭節點和虛擬尾節點是使用:
添加節點和刪除節點的時候就就比較方便了,這個在單向鏈表的設計中也有涉及:
707. 設計鏈表
下面給出具體的代碼:

代碼

雙向鏈表設計

關于雙向鏈表節點的定義

class DLinkedNode {//存儲鍵、值int key, value;//定義兩個指針,一個指向前一個節點,一個指向下一個節點DLinkedNode* prev;DLinkedNode* next;//構造函數DLinkedNode(): key(0), value(0), prev(nullptr), next(nullptr) {}DLinkedNode(int _key, int _value): key(_key), value(_value), prev(nullptr), next(nullptr) {}
};

關于LRUCache類的設計:

私有成員變量設計:

private://哈希表unordered_map<int, DLinkedNode*> cache;//虛擬頭指針和虛擬尾指針DLinkedNode* head;DLinkedNode* tail;//當前LRUCache中元素(鍵值對)個數int size;//LRUCache最多能容納多少鍵值對int capacity;

構造函數和析構函數設計:

構造函數:
這里給出最大容量,我們還需要初始化size的大小和主動添加虛擬頭指針和虛擬尾指針,并將兩者鏈接起來

    LRUCache(int capacity) {_capacity = capacity;_size = 0;dummyhead = new DLinkedNode();dummytail = new DLinkedNode();dummyhead->next = dummytail;dummytail->prev = dummyhead;}

析構函數:
主要是將兩個虛擬頭節點和虛擬尾節點釋放掉

~LRUCache() {delete head;delete tail;}

get與put具體設計

get函數:

int get(int key)
{//如果找不到,返回-1if(chache.find(key) == chache.end()){return -1;}//如果key存在//哈希定位DLinkedNode* node = chache[key];//將該節點添加到雙向鏈表頭部moveHead(node);//返回該節點值return node->value;
}

put函數:

void put(int key, int value)
{//如果key不存在,創建一個新節點if(cache.find(key) == cache.end()){//如果預計超出容量,刪除雙向鏈表尾部節點if(size + 1 > capacity){//刪除雙向鏈表尾部節點DLinkedNode* deleted_node = deleteTail();//刪除哈希表中對應部分cache.erase(deleted_node->key);delete deleted_node;size--;}DLinkedNode* node = new DLinkedNode(key,value);chache[key] = node;//將該節點添加到雙向鏈表頭部addHead(node);size++;}//如果key存在,通過哈希定位,修改value,移動到頭部else{DLinkedNode* node = chache[key];node->value = value;moveHead}
}

雙向指針的具體細節

添加到頭節點函數

void addHead(DLinkedNode* node)
{//雙向指針操作 + 虛擬頭節點node->prev = head;node->next = head->next;head->next->prev = node;head->next = node;
}

刪除尾節點函數

DLinkedNode* deleteTail()
{//尾節點是虛擬tail前面一個。DLinkedNode* node = tail->prev;deleteNode(node);return node;
}

刪除節點函數

指針繞來繞去。。。面試沒寫出來。。。

void deleteNode(DLinkedNode* node)
{node->prev->next = node->next;node->next->prev = node->prev;
}

刪除節點函數

void moveHead(DLinkedNode* node)
{//先刪除當前節點deleteNode(node);//然后將它加入頭部addHead(node);
}

感想

第一次面試,還是太緊張了,說話都說不利索。
關鍵還是指針鏈表操作的繁瑣。。。沒想到面試會考這題。。
這一題和實際應用關聯較大,而且是設計題,比較考研綜合能力。
構造函數和雙向鏈表的定義都得自己寫,雙向鏈表我平時用到的不是很多,還得多加練習。
為了面試,晚飯都沒吃。。。
面試官聲音好聽,態度也很溫和,像個鄰家大哥哥,面完我還要再去面下一個,一個人一個小時,感覺也挺累的。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/377320.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/377320.shtml
英文地址,請注明出處:http://en.pswp.cn/news/377320.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

碼農干貨系列【4】--圖像識別之矩形區域搜索

簡介 定位某個圖片的矩形區域是非常有用的&#xff0c;這個可以通過手動的選擇某個區域來實現定位&#xff0c;圖片相關的軟件都提供了這個功能&#xff1b;也可以像本篇一個通過程序來實現智能定位。前者會有誤差&#xff0c;效率低下&#xff1b;后者選區精度高&#xff0c;效…

算法題復習(回溯)

目錄base code棋盤問題51. N 皇后37. 解數獨組合問題77. 組合未剪枝優化剪枝優化216. 組合總和 III未剪枝優化剪枝優化17. 電話號碼的字母組合39. 組合總和未剪枝優化剪枝優化40. 組合總和 II,挺重要的&#xff0c;涉及到去重了切割問題131. 分割回文串子集問題78. 子集90. 子集…

pfa是什么意思_PFA的完整形式是什么?

pfa是什么意思PFA&#xff1a;預測性故障分析 (PFA: Predictive Failure Analysis) PFA is an abbreviation of Predictive Failure Analysis. It is a technique of a mechanism of the computer that is used to predict impending failures of software or hardware compone…

SqlServer視圖(view)

--上節回顧--1.什么是事務--2.事務的特征--原子性、一致性、隔離性、持久性--3.與事務相關的t-sql命令--開啟事務&#xff1a;begin transaction--提交事務&#xff1a;commit transaction--回滾事務&#xff1a;rollback transaction ----------------視圖-------------------…

Android中的廣播Broadcast詳解

今天來看一下Android中的廣播機制&#xff0c;我們知道廣播Broadcast是Android中的四大組件之一&#xff0c;可見他的重要性了&#xff0c;當然它的用途也很大的&#xff0c;比如一些系統的廣播&#xff1a;電量低、開機、鎖屏等一些操作都會發送一個廣播&#xff0c;具體的And…

sql check約束_在SQL中使用CHECK約束

sql check約束Basically, CHECK constraint is used to LIMIT in columns for the range of values. We can use this constraint for single or multiple columns. 基本上&#xff0c; CHECK約束用于限制值范圍內的列 。 我們可以將此約束用于單列或多列。 In single column,…

.NET線程池

摘要 深度探索 Microsoft .NET提供的線程池&#xff0c; 揭示什么情況下你需要用線程池以及 .NET框架下的線程池是如何實現的&#xff0c;并告訴你如何去使用線程池。 內容 介紹 .NET中的線程池 線程池中執行的函數 使用定時器 同步對象的執行 異步I/O操作 監視線程池 死鎖 有關…

折線分割平面

Input輸入數據的第一行是一個整數C,表示測試實例的個數&#xff0c;然后是C 行數據&#xff0c;每行包含一個整數n(0<n<10000),表示折線的數量。Output對于每個測試實例&#xff0c;請輸出平面的最大分割數&#xff0c;每個實例的輸出占一行。Sample Input2 1 2Sample Ou…

《c++特性》

目錄多態構造函數和析構函數存在多態嗎&#xff1f;虛函數表虛析構函數純虛函數和抽象類運行時多態和編譯時多態的區別繼承設計實例指針對象和普通對象的區別正確初始化派生類方式繼承和賦值的兼容規則protected 和 private 繼承基類與派生類的指針強制轉換如何用C實現C的三大特…

Scala中的while循環

在Scala中的while循環 (while loop in Scala) while loop in Scala is used to run a block of code multiple numbers of time. The number of executions is defined by an entry condition. If this condition is TRUE the code will run otherwise it will not run. Scala中…

Linux操作系統啟動過程

在做開發的過程中&#xff0c;突然發現&#xff0c;要對系統做一些有意義的改變&#xff0c;必須要對操作系統的啟動過程有一定的了解&#xff0c;不然就是修改你都不知道從哪里下手啊&#xff0c;然后就是找來資料看&#xff0c;去網上看別人的博客&#xff0c;有了前一周一些…

方法命名的區別

GetDecimalFromString ExtractDecimal 這2個方法名那個比較好呢。上邊的明顯的是中式英語&#xff0c;單詞拼湊而成的。下邊的更加流暢一些。方法名稱取名還是很有要求的。要通俗易懂還要符合文法。從上邊的可以擴展出什么想法呢。 ExtractDecimalExtractDoubleExtractInt16Ext…

工作排序問題

Problem statement: 問題陳述&#xff1a; Given an array of jobs where every job has a deadline and a profit. Profit can be earned only if the job is finished before the deadline. It is also given that every job takes a single unit of time, so the minimum p…

牛客網與leetcode刷題(高頻題中簡單or中等的)

目錄1、反轉鏈表2、排序3、先序中序后序遍歷4、最小的k個數5、子數組的最大累加和6、 用兩個棧實現隊列7、142. 環形鏈表 II8、20. 有效的括號9、最長公共子串(動態規劃),磕磕絆絆10、二叉樹之字形層序遍歷11、重建二叉樹12、LRU緩存13、合并兩個有序鏈表15、大數加法16、一個二…

AMUL的完整形式是什么?

AMUL&#xff1a;阿南德牛奶聯盟有限公司 (AMUL: Anand Milk Union Limited) AMUL is an abbreviation of Anand Milk Union Limited. It is an Indian milk product cooperative dairy organization that is based in the small town of Anand in the state of Gujarat. AMUL …

mochiweb 源碼閱讀(十一)

大家好&#xff0c;今天周六&#xff0c;繼續接著上一篇&#xff0c;跟大家分享mochiweb源碼。上一篇&#xff0c;最后我們看到了mochiweb_socket_server:listen/3函數&#xff1a; listen(Port, Opts, State#mochiweb_socket_server{sslSsl, ssl_optsSslOpts}) ->case moch…

Android下拉刷新完全解析,教你如何一分鐘實現下拉刷新功能 (轉)

轉載請注明出處&#xff1a;http://blog.csdn.net/guolin_blog/article/details/9255575 最 近項目中需要用到ListView下拉刷新的功能&#xff0c;一開始想圖省事&#xff0c;在網上直接找一個現成的&#xff0c;可是嘗試了網上多個版本的下拉刷新之后發現效果都不怎么理 想。有…

Python中的append()和extend()

列出append()方法 (List append() method) append() method is used to insert an element or a list object to the list and length of the List increased by the 1. append()方法用于將元素或列表對象插入列表&#xff0c;并且列表長度增加1。 Syntax: 句法&#xff1a; …

紅黑樹的實現

目錄1、紅黑樹原理1、紅黑樹性質2、變換規則&#xff08;從插入結點的角度來講&#xff09;1.變色2.左旋3.右旋3、刪除結點需要注意的地方2、代碼1、定義結點以及構造函數2、定義紅黑樹類以及聲明它的方法3、左旋4、右旋5、插入操作6、修正操作7、刪除操作3、參考鏈接1、紅黑樹…

118 - ZOJ Monthly, July 2012

http://acm.zju.edu.cn/onlinejudge/showContestProblems.do?contestId339 都是賽后做的。。。弱爆了 A題是找由2和5組成的數字的個數 直接打個表就行了 只是比賽的時候不知道怎么打表啊。。 View Code #include<cstdio> #include<cstring> #include<algorith…