用双向链表实现LRU算法(c++)

实现LRU算法的方式有两种:数组和单链表。讲讲我为什么要用链表模拟实现。
其实我们知道,cpu从外存取数据到内存是以块为基本单位的,也就是说cpu取一块连续的地址到内存内,这样说的话是不是对数组友好点?因为数组用连续的地址存储着相同类型的数据。但是在我考虑在实际应用中,如果需要分配的地址过大时,可能会由于各种原理(存储空间有限或者空间碎片化)无法分配一块连续的地址给数组,而且在频繁的插入删除操作面前,数组的时间复杂度太高。所以我觉得链表在LRU实现上虽不能一次性传送块数据,但是实现条件却很简单,没有数组的苛刻,且时间复杂度低。

算法实现:用单链表实现LRU算法
1、将需要放进链表的数据同链表中的数据域比较,是否在链表中
true:如果链表没有达到最大存储上限,将原先存储的那一块内存删除,再将数据头插法插入链表;
false:如果链表没有达到上限,直接插入链表头部,Nowlen+1,空间满删除最后一个节点再将数据插入链表头部

在实现的过程中,当需要删除最后一个节点时,单链表往往需要重新遍历链表找到最后一个节点,比较费时,就将单链表转为双向链表实现,这样插入的时候将tail尾指针给插入的第一个元素,这样删除尾元素之前先将尾指针指向尾元素的pre节点,这样就不用重复遍历节点了。但是后来又想了想,其实时间复杂度还是O(n),然后突然想到我们每次都需要遍历一次指针,那不妨同时遍历到尾,将尾指针赋值给tail,就只需要遍历一次,或许也是个可行的办法。
实现头文件

#pragma once
#pragma once
#include<iostream>
#include<string>
using namespace std;
class linknode
{
public:
	char data;
	linknode *next;
	linknode *pre;
	linknode()
	{
		data = '0';
		next = NULL;
		pre = NULL;
	}
};
class list : public linknode
{
private:
	linknode *first;
	linknode *tail;
	int Maxlen;//链表的最大长度
	int Nlen;//链表当前长度
public:
	list();//初始化链表
	void head_insert(linknode *a);//当有新节点被访问时,将新节点查到链表头部
	void  omit(linknode *q);//删除当前节点,但节点还是要存储在链表头,所有不用Delete当前节点
	bool LRU(char a);//遍历链表查找字符是否在链表中,如何存在则删除
	void  getlen(int n);//获得链表最大可允许存储的数据大小
	void output();//输出链表,测试用
};
list::list()
{
	first = new linknode;
	tail = new linknode;
	Maxlen = 0;
	Nlen = 0;
}

void list::head_insert(linknode *a)
{
	
	if (first->next != NULL)//第一个元素插入式时应为first->next没有具体的地址(NULL),需要特殊处理
	{
		a->next = first->next;
		first->next->pre = a;
	}
	first->next = a;
	a->pre = first;
	if (Nlen == 0)
		tail = first->next;
	
}
bool list::LRU(char a)
{   
	linknode *p = first->next;
	linknode *pPre = first;
	while (p != NULL)//如果链表不为空
	{
		if (p->data == a)//查找链表中是否存在元素
		{
            omit(pPre);//存在则删除并重新插入到表头
			head_insert(p);
			return true;
		}
		p = p->next;
		pPre = pPre->next;
	}
	
	if (Nlen == Maxlen)//链表达到上限
	{
		linknode *t = tail->pre;//重新设置尾指针
		tail = t;
		tail->next = NULL;//删除尾结点
		Nlen--;
	}
	linknode *Node=new linknode;
	Node->data = a;
	head_insert(Node);//插入新元素
	Nlen++;
	return false;
	
}
void  list::getlen(int n)
{
	Maxlen = n;
}

void  list::omit(linknode *q)
{

	q->next = q->next->next;
}
void list::output()
{
	linknode *temp = first->next;
	while (temp != NULL)
	{
		cout << temp->data << "   ";
		temp = temp->next;
	}
	cout << endl;
}

测试cpp

#include"list.h"
int main()
{
	char a;
	int n;
	cout << "请输入内存最大可存入的数:";
	cin >> n;
	list *List=new list;
	List->getlen(n);
	while (cin >> a)
	{

		if (List->LRU(a))
		{
			List->output();
		}
		else
		{
			List->output();
		}

	}
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
LRU算法(最近最少使用算法)是一种用于缓存淘汰的算法。其原理是根据数据的访问时间来确定是否将其从缓存中删除。当缓存达到最大容量时,如果要插入新数据,则需要将最近最少使用的数据删除,以腾出空间。 以下是C++实现LRU算法的基本思路: 1. 使用一个双向链表来维护缓存的数据。 2. 使用一个哈希表来快速查找数据是否在缓存中。 3. 当一个数据被访问时,将其移动到链表头部。 4. 当需要插入新数据时,先检查缓存是否已满,如果已满,则删除链表尾部的数据,并将新数据插入到链表头部。 5. 当需要删除数据时,直接从链表中删除即可。 以下是C++代码示例: ``` #include <iostream> #include <unordered_map> using namespace std; class LRUCache { private: struct Node { int key; int value; Node* prev; Node* next; Node(int k, int v) : key(k), value(v), prev(nullptr), next(nullptr) {} }; int capacity; unordered_map<int, Node*> map; Node* head; Node* tail; void addToHead(Node* node) { node->prev = nullptr; node->next = head; if (head) { head->prev = node; } else { tail = node; } head = node; } void removeNode(Node* node) { if (node == head) { head = node->next; } else if (node == tail) { tail = node->prev; } else { node->prev->next = node->next; node->next->prev = node->prev; } } public: LRUCache(int cap) : capacity(cap), head(nullptr), tail(nullptr) {} int get(int key) { if (map.find(key) != map.end()) { Node* node = map[key]; removeNode(node); addToHead(node); return node->value; } else { return -1; } } void put(int key, int value) { if (map.find(key) != map.end()) { Node* node = map[key]; node->value = value; removeNode(node); addToHead(node); } else { Node* newNode = new Node(key, value); if (map.size() == capacity) { map.erase(tail->key); removeNode(tail); delete tail; } map[key] = newNode; addToHead(newNode); } } }; int main() { LRUCache cache(2); cache.put(1, 1); cache.put(2, 2); cout << cache.get(1) << endl; // 输出 1 cache.put(3, 3); // 删除 key 2 cout << cache.get(2) << endl; // 输出 -1 cache.put(4, 4); // 删除 key 1 cout << cache.get(1) << endl; // 输出 -1 cout << cache.get(3) << endl; // 输出 3 cout << cache.get(4) << endl; // 输出 4 return 0; } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值