LRU算法c++实现

//LRU的实现 LRU是Least Recently Used的缩写,即最近最少使用,是一种常用的页面置换算法,选择最近最久未使用的页面予以淘汰

// 利用双向链表实现

// 双向链表有一个特点就是它的链表是双路的,我们定义好头节点和尾节点,然后利用先进先出(FIFO),最近被放入的数据会最早被获取。
// 其中主要涉及到添加、访问、修改、删除操作。首先是添加,如果是新元素,直接放在链表头上面,其他的元素顺序往下移动;访问的话,
// 在头节点的可以不用管,如果是在中间位置或者尾巴,就要将数据移动到头节点;修改操作也一样,修改原值之后,再将数据移动到头部;
// 删除的话,直接删除,其他元素顺序移动;
// 标准的lru算法实现都是 hashmap+双向链表

// 维护多个lru缓存,将数据大致均匀的映射到这n个 lru缓存中,主要是为了缓解 吊销缓存数据、添加数据等写操作的竞争。
// 维护的lru缓存个数 = CPU的核心数。

// 双向链表实现LRU缓存更新删除平均时间复杂度为O(1)

// 双向链表实现LRU缓存更新删除平均时间复杂度为O(1)

#if 1
#include <iostream>
using namespace std;

const uint32_t MaxSize = 10000;
const uint32_t MaxListSize = 10;
typedef int DataType;

struct DeListNode
{
    DataType data;
    DeListNode* next;
    DeListNode* pri;
};

typedef DeListNode* DeList;

class HashTable
{
public:
    HashTable(uint32_t datanum) : data_num_(datanum)
    {
        head_ = nullptr;
        size_ = 0;
        list_size_ = 0;
    }

    bool Init();
    bool Insert(DataType data); // 新数据插入到链表头部;
    bool Destory();
    bool Print();
private:
    uint32_t GetTableSize();
    bool IsFindEleUpdate(DataType data); // 更新或者访问数据,将该数据移动到链表头部
    uint32_t Hash(DataType data);
    bool DeleFromTail(uint32_t pos);

private:
    DeList head_;   // 存储双向链表头节点的数组
    uint32_t size_;  // 哈希表长度 暂时不考虑扩容
    uint32_t data_num_;  // 业务数据量
    uint32_t list_size_;  // 链表最大长度
};

uint32_t HashTable::GetTableSize()
{
    // 计算哈希表长度 取大于等于业务数据size的第一个素数
    uint32_t data_num_tmp = data_num_;
    while (data_num_tmp <= MaxSize)
    {
        bool IsPri = true;
        uint32_t i = 2;
        while (i < data_num_tmp)
        {
            if (data_num_tmp % i == 0)
            {
                IsPri = false;
            }

            i++;
        }

        if (IsPri)
        {
            break;
        }

        data_num_tmp++;
    }

    size_ = data_num_tmp;
    return data_num_tmp;
}

bool HashTable::Destory()
{
    if (head_)
    {
        delete[] head_;
        head_ = nullptr;
    }

    return true;
}

bool HashTable::Print()
{
    if (head_ == nullptr)
    {
        return false;
    }

    DeList pHead = head_;
    for (int i = 0; i < size_; ++i)
    {
        if (pHead[i].next == nullptr)
            continue;

        DeListNode* pNode = pHead[i].next;
        while (pNode)
        {
            cout << pNode->data << endl;
            pNode = pNode->next;
        }
    }
}

uint32_t HashTable::Hash(DataType data)
{
    return data % size_;
}

bool HashTable::DeleFromTail(uint32_t pos)
{
    if (pos < 0 || pos >= size_)
    {
        return false;
    }

    if (head_ == nullptr)
    {
        return false;
    }

    DeListNode* pNode = head_[pos].next;
  
    if (pNode == nullptr)
    {
        return false;
    }

    while (pNode->next)
    {
        pNode = pNode->next;
    }

    pNode->pri->next = pNode->next;
 
    pNode->next = nullptr;
    pNode->pri = nullptr;
    delete pNode;
    pNode = nullptr;
}

bool HashTable::Insert(DataType data) // 新数据插入到链表头部; 更新或者访问数据,将该数据移动到链表头部; 当链表满时,将链表尾部的数据丢弃
{
    if (head_ == nullptr)
    {
        return false;
    }

    // 头节点默认不存数据
    DeListNode* pNode = new(std::nothrow) DeListNode;
    if (pNode == nullptr)
    {
        return false;
    }

    pNode->next = pNode->pri = nullptr;
    pNode->data = data;

    uint32_t pos = Hash(data);

    if (!IsFindEleUpdate(data))
    {
        // 链表是否满了 满了尾部淘汰数据
        if (list_size_ >= MaxListSize)
        {
            if (!DeleFromTail(pos))
            {
                return false;
            }

            cout << "list is full" << endl;
            return true;
        }

         // 头插入
         DeListNode* pTmp = head_[pos].next;
         if (pTmp == nullptr)
         {
             head_[pos].next = pNode;
             pNode->pri = &head_[pos];
         }
         else
         {
             head_[pos].next = pNode;
             pNode->pri = &head_[pos];
             pNode->next = pTmp;
         }

         list_size_++;
    }
}

bool HashTable::IsFindEleUpdate(DataType data)
{
    bool IsFind = false;
    uint32_t pos = Hash(data);
    
    DeListNode* pNode = head_[pos].next;
    if (pNode == nullptr)
    {
        return false;
    }

    while (pNode->next)
    {
        if (pNode->data == data)
        {
            // 对于Key-Value形式更新值, 此处象征性的赋值
            pNode->data = data;
            IsFind = true;
            break;
        }
        pNode = pNode->next;
    }

    if (IsFind)
    {
        // 移除当前节点
        if (pNode->next == nullptr)
        {
            pNode->pri->next = nullptr;
        }
        else
        {
            pNode->pri->next = pNode->next;
            pNode->next->pri = pNode->pri;
        }

        // 头插入
        DeListNode* pTmp = head_[pos].next;

        pNode->pri = &head_[pos];
        pNode->next = pTmp;
        head_[pos].next = pNode;
    }

    return false;
}

bool HashTable::Init()
{
    uint32_t uTableSize = GetTableSize();
    if (uTableSize <= 0)
    {
        return false;
    }

    DeList pHead = new(std::nothrow) DeListNode[uTableSize];
    if (pHead == nullptr)
    {
        return false;
    }

    // 初始化头节点
    for (int i = 0; i < size_; ++i)
    {
        pHead[i].next = nullptr;
        pHead[i].pri = nullptr;
    }

    head_ = pHead;
    return true;
}

int main()
{
    uint32_t arr[10] = {11,23,45,67,89,12,34,4,5,78};
    HashTable h(sizeof(arr) / sizeof(uint32_t));
    h.Init();
    for (uint32_t i = 0; i < sizeof(arr) / sizeof(uint32_t); ++i)
    {
        h.Insert(arr[i]);
    }
 
    h.Print();
    h.Destory();
	return 0;
}
#endif

 

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值