算法与数据结构☞LRU

131 阅读2分钟
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>

#define LRU_CACHE_SIZE 5

typedef struct node {
    struct node* prev;
    struct node* next;
    char* key;
    int value;
} Node;

typedef struct hashmap {
    int capacity;
    int size;
    Node* array[LRU_CACHE_SIZE];
} HashMap;

typedef struct dlist {
    Node *head;
    Node *tail;
} DList;

typedef struct lrucache {
    int itail;
    HashMap* map;
    DList* list;
} LRUCache;

int HashMap_Index(const char* key) {
    if(key == NULL) {
        return -1;
    }
    return atoi(key) % LRU_CACHE_SIZE;
}
int LRU_Get(LRUCache* lru, const char* key) {
    if(key == NULL || strlen(key) == 0) {
        errno = EACCES;
        perror("illegal call");
        exit(0);
    } 
    if(lru == NULL || lru->map == NULL || lru->map->size == 0) {
        return INT_MIN;
    }
    int index = -1;
    int origin_index = -1;
    index = HashMap_Index(key);
    origin_index = index;
    while (1) {
        
        if(lru->map->array[index] == NULL) {
            return INT_MIN;
        }
        if(strcmp(lru->map->array[index]->key, key) == 0) {
            break;
        }
        index = index == LRU_CACHE_SIZE-1 ? 0 : index+1;
        if(index == origin_index) {
            return INT_MIN;
        }
    }
    Node* p = lru->map->array[index];
    Node* q = NULL;
    if(p != lru->list->head) {
        if(p == lru->list->tail) {
            lru->list->tail = p->prev;
            p->prev->next = NULL;
            const char* tail_key = lru->list->tail->key;
            int tail_index = HashMap_Index(tail_key);
            while(strcmp(tail_key, lru->map->array[tail_index]->key) != 0) {
                tail_index = tail_index == LRU_CACHE_SIZE-1 ? 0 : tail_index+1;
            }
            lru->itail = tail_index;
        } else {
            q = p->prev;
            p->prev->next = p->next;
            q->next = p->next;
            p->next->prev = q;
            q = NULL;
        }
        lru->list->head->prev = p;
        p->next = lru->list->head;
        p->prev = NULL;
    }
    return lru->map->array[index]->value;
    
}
void LRU_Eminate(LRUCache* lru) {
    if(lru == NULL || lru->map == NULL || lru->map->size != LRU_CACHE_SIZE) {
        return;
    }
    lru->map->array[lru->itail] = NULL;
    lru->map->size = lru->map->size - 1;
    Node* p = lru->list->tail;
    lru->list->tail = lru->list->tail->prev;
    lru->list->tail->next = NULL;
    free(p);
    return;
}
LRUCache* LRU_Set(LRUCache* lru, const char* key, int value) {
    if(key == NULL || strlen(key) == 0) {
        errno = EACCES;
        perror("illegal call");
        return lru;
    }
    if(lru == NULL) {
        lru = (LRUCache*)malloc(sizeof(LRUCache));
        if(lru == NULL) {
            errno = ENOMEM;
            perror("malloc");
            exit(0);
        }
        lru->itail = -1;
        lru->map = NULL;
        lru->list = NULL;
    }
    if(lru->map == NULL) {
        lru->map = (HashMap*)malloc(sizeof(HashMap));
        if(lru->map == NULL) {
            errno = ENOMEM;
            perror("malloc");
            exit(0);
        }
        lru->map->size = 0;
        for(int i = 0; i < LRU_CACHE_SIZE; i++) {
            lru->map->array[i] = NULL;
        }
        lru->map->capacity = LRU_CACHE_SIZE;

        lru->list = (DList*)malloc(sizeof(DList));
        if(lru->list == NULL) {
            errno = ENOMEM;
            perror("malloc");
            exit(0);
        }
        lru->list->head = NULL;
        lru->list->tail = NULL;
    }
    printf("%d\n", lru->map->size);
    if(lru->map->size == LRU_CACHE_SIZE) {
        LRU_Eminate(lru);
    }
    Node* node = (Node*)malloc(sizeof(Node));
    if(node == NULL) {
        errno = ENOMEM;
        perror("malloc");
        exit(0);
    }
    node->key = strdup(key);
    node->value = value;
    node->prev = NULL;
    node->next = NULL;
    int index = 0;
    index = HashMap_Index(key);
    while(lru->map->array[index] != NULL) {
        index = index == LRU_CACHE_SIZE-1 ? 0 : index+1;
    }
    lru->map->array[index] = node;
    lru->map->size++;
    if(lru->list->head == NULL) {
        lru->list->head = node;
        lru->list->tail = node;
        lru->itail = index;
    } else {
        node->next = lru->list->head;
        lru->list->head->prev = node;
        lru->list->head = node;
    }
    return lru;
}

int main(int argc, char** argv) {
    LRUCache* lru = NULL;
    lru = LRU_Set(lru, "100", 100);
    lru = LRU_Set(lru, "101", 101);
    lru = LRU_Set(lru, "102", 102);
    lru = LRU_Set(lru, "103", 103);
    lru = LRU_Set(lru, "104", 104);
    lru = LRU_Set(lru, "105", 105);
    int x = LRU_Get(lru, "100");
    printf("%d\n", x == INT_MIN);
    return 0;
}