LRU 近似(二次机会算法)
如果您不熟悉最近最少使用的算法,请查看最近最少使用的算法(页面替换)
该算法结合了使用类似于 FIFO(FIFO(页面替换))的队列以及使用数组来跟踪用于为排队页面提供“第二次机会”的位的组合。算法是如何工作的:
- Set all the values of the bitref as False (Let it be the size of max capacity of queue).
- Set an empty queue to have a max capacity.
- Check if the queue is not full:
- If the element is in the queue, set its corresponding bitref = 1.
- If the element is not in the queue, then push it into the queue.
- If the queue is full:
- Find the first element of the queue that has its bitref = 0 and if any element in the front has bitref = 1, set it to 0. Rotate the queue until you find an element with bitref = 0.
- Remove that element from the queue.
- Push the current element from the input array into the queue.
解释:
在这种情况下,对于 bitref 中的索引,这些位像往常一样设置为 1,直到队列已满。
一旦队列已满,根据 FIFO 页替换算法,我们应该摆脱队列的前端(如果元素是错误/未命中)。但在这里我们不这样做。
相反,我们首先检查它的引用位(又名 bitref)是否为 0 或 1(假或真)。如果为 0(假),我们将其从队列中弹出并将等待元素推入队列。但是如果它是 1(真),我们就将它的引用位 (bitref) 设置为 0 并将它移到队列的后面。我们继续这样做,直到我们遇到队列的前端,使其前端值的引用位 (bitref) 为 0 (false)。
然后我们按照通常的方式将它从队列中移除并将等待元素推入队列。
如果等待元素已经在队列中怎么办?我们只是将其参考位 (bitref) 设置为 1 (true)。
我们现在将所有像 2, 4, 1 这样的值向后移动,直到遇到 3,其 bitref 为 0。将 2, 4, 1 向后移动时,我们将它们的 bitref 值设置为 0。
所以现在,问题是当它清楚地实现 FIFO 而不是 LRU 时,这是 LRU 的近似值。嗯,这是通过为队列的前面提供第二次机会(在 FIFO 的情况下会被弹出和替换)来实现的。在这里,第二次机会基于这样一个事实:如果元素“最近”被看到,它的参考位 (bitref) 被设置为 1 (true)。如果最近没有看到它,我们就不会将其参考位 (bitref) 设置为 1 (true) 并因此将其删除。因此,这就是为什么它是近似值而不是 LRU 或 FIFO。
下面是上述方法的实现:
// C++ implementation of the approach
#include
using namespace std;
// Function to find an element in the queue as
// std::find does not work for a queue
bool findQueue(queue q, int x)
{
while (!q.empty()) {
if (x == q.front())
return true;
q.pop();
}
// Element not found
return false;
}
// Function to implement LRU Approximation
void LRU_Approximation(vector t, int capacity)
{
int n = t.size();
queue q;
// Capacity is the size of the queue
// hits is number of times page was
// found in cache and faults is the number
// of times the page was not found in the cache
int hits = 0, faults = 0;
// Array to keep track of bits set when a
// certain value is already in the queue
// Set bit --> 1, if its a hit
// find the index and set bitref[index] = 1
// Set bit --> 0, if its a fault, and the front
// of the queue has bitref[front] = 1, send front
// to back and set bitref[front] = 0
bool bitref[capacity] = { false };
// To find the first element that does not
// have the bitref set to true
int ptr = 0;
// To check if the queue is filled up or not
int count = 0;
for (int i = 0; i < t.size(); i++) {
if (!findQueue(q, t[i])) {
// Queue is not filled up to capacity
if (count < capacity) {
q.push(t[i]);
count++;
}
// Queue is filled up to capacity
else {
ptr = 0;
// Find the first value that has its
// bit set to 0
while (!q.empty()) {
// If the value has bit set to 1
// Set it to 0
if (bitref[ptr % capacity])
bitref[ptr % capacity] = !bitref[ptr % capacity];
// Found the bit value 0
else
break;
ptr++;
}
// If the queue was empty
if (q.empty()) {
q.pop();
q.push(t[i]);
}
// If queue was not empty
else {
int j = 0;
// Rotate the queue and set the front's
// bit value to 0 until the value where
// the bitref = 0
while (j < (ptr % capacity)) {
int t1 = q.front();
q.pop();
q.push(t1);
bool temp = bitref[0];
// Rotate the bitref array
for (int counter = 0; counter < capacity - 1; counter++)
bitref[counter] = bitref[counter + 1];
bitref[capacity - 1] = temp;
j++;
}
// Remove front element
// (the element with the bitref = 0)
q.pop();
// Push the element from the
// page array (next input)
q.push(t[i]);
}
}
faults++;
}
// If the input for the iteration was a hit
else {
queue temp = q;
int counter = 0;
while (!q.empty()) {
if (q.front() == t[i])
bitref[counter] = true;
counter++;
q.pop();
}
q = temp;
hits++;
}
}
cout << "Hits: " << hits << "\nFaults: " << faults << '\n';
}
// Driver code
int main()
{
vector t = { 2, 3, 2, 1, 5, 2, 4, 5, 3, 2, 5, 2 };
int capacity = 4;
LRU_Approximation(t, capacity);
return 0;
}
Hits: 6
Faults: 6
如果您希望与专家一起参加现场课程,请参阅DSA 现场工作专业课程和学生竞争性编程现场课程。