题里面要求 set()和get()都是 O(1) 所以没啥说的,至少LRU中的每个数据需要双向链表存储,这样添加/删除/更新的时候才能做到 O(1)
为了实现通过key直接找到LRU中的数据,只能使用hash,这样才能满足O(1),虽然会有冲突发生,但是也比每轮通过循环找key-value要好的多
// 双向链表节点结构
typedef struct element_s{
struct element_s* prev;
struct element_s* next;
int value;
int key;
}element_t;
// 双向链表结构
typedef struct list_s{
element_t *head;
element_t *tail;
int k;
}list_t;
// hash表节点结构
typedef struct hash_element_s{
struct hash_element_s * next;
element_t* value;
}hash_element_t;
// hash表结构
typedef struct hash_s{
hash_element_t **hash;
int hash_size;
}hash_t;
// hash表加入新节点,使用链表方式解决冲突
static void
hash_set_value(hash_t* hash_table,int key,element_t* element)
{
unsigned int _key = (unsigned int)key;
if(hash_table->hash[(_key)%hash_table->hash_size] == NULL)
{
hash_table->hash[(_key)%hash_table->hash_size] = (hash_element_t*)malloc(sizeof(hash_element_t));
hash_table->hash[(_key)%hash_table->hash_size]->next = NULL;
hash_table->hash[(_key)%hash_table->hash_size]->value = element;
}else{
hash_element_t* hash_element_priv = hash_table->hash[(_key)%hash_table->hash_size];
hash_element_t* hash_element = hash_element_priv->next;
while(hash_element != NULL)
{
hash_element_priv = hash_element;
hash_element = hash_element->next;
}
hash_element_priv->next = (hash_element_t*)malloc(sizeof(hash_element_t));
hash_element = hash_element_priv->next;
hash_element->next = NULL;
hash_element->value = element;
}
}
// hash表获取value
static element_t*
hash_get_value(hash_t* hash_table,int key)
{
unsigned int _key = (unsigned int)key;
hash_element_t* hash_element = hash_table->hash[(_key)%hash_table->hash_size];
while(hash_element != NULL && hash_element->value->key != key)
hash_element = hash_element->next;
if(hash_element != NULL && hash_element->value->key == key)
return hash_element->value;
return NULL;
}
// hash表移除key-value对
static void
hash_remove_value(hash_t* hash_table,int key)
{
unsigned int _key = (unsigned int)key;
hash_element_t* hash_element = hash_table->hash[(_key)%hash_table->hash_size];
hash_element_t* hash_element_priv = NULL;
while(hash_element != NULL && hash_element->value->key != key)
{
hash_element_priv = hash_element;
hash_element = hash_element->next;
}
if(hash_element != NULL && hash_element->value->key == key)
{
if(hash_element_priv != NULL)
{
hash_element_priv->next = hash_element->next;
free(hash_element);
}else{
hash_table->hash[(_key)%hash_table->hash_size] = hash_element->next;
free(hash_element);
}
}
}
static hash_t*
hash_init(int size)
{
hash_t* hash_table = (hash_t*)malloc(sizeof(hash_t));
hash_table->hash_size = size;
hash_table->hash = (hash_element_t**)malloc(sizeof(hash_element_t*)*hash_table->hash_size);
memset(hash_table->hash,0,sizeof(hash_element_t*)*hash_table->hash_size);
return hash_table;
}
static void
hash_destroy(hash_t* hash_table)
{
for(int i=0;i<hash_table->hash_size;++i)
{
hash_element_t *temp, *hash_element = hash_table->hash[i];
while(hash_element)
{
temp = hash_element;
hash_element = hash_element->next;
free(temp);
}
}
free(hash_table->hash);
free(hash_table);
}
// 更新双向链表,将新节点或者刚刚访问的节点,放到双向链表的tail部分,head部分是最久未使用的节点
static int
update_list(list_t* list,hash_t* hash_table,int key,element_t *element)
{
element_t *update=NULL;
if(element == NULL)
update = hash_get_value(hash_table,key);
else
update = element;
if(update == NULL)
return -1;
if(list->head == list->tail)
return update->value;
if(list->head == update)
{
list->head = update->next;
update->prev = list->tail;
update->next->prev = NULL;
update->next = NULL;
list->tail->next = update;
list->tail = update;
}else if(list->tail != update){
update->prev->next = update->next;
update->next->prev = update->prev;
update->next = NULL;
update->prev = list->tail;
list->tail->next = update;
list->tail = update;
}else ;
//printf("k=%lld v=%lld\n",update->key,update->value);
return update->value;
}
// 双向链表获取key-value
static int
list_get_value(list_t* list,hash_t* hash_table,int key)
{
return update_list(list,hash_table,key,NULL);
}
static void
insert_list(list_t* list,hash_t* hash_table,int key ,int value)
{
element_t *element = hash_get_value(hash_table,key);
if(element != NULL) //update pos
{
if(update_list(list,hash_table,key,element) != value)
element->value = value;
}else{
if(list->k > 0) //insert at tail
{
element_t *new_elem = (element_t *)malloc(sizeof(element_t));
hash_set_value(hash_table,key,new_elem);
if(list->head == NULL)
{
list->tail = list->head = new_elem;
new_elem->next = new_elem->prev = NULL;
}else{
new_elem->prev = list->tail;
new_elem->next = NULL;
list->tail->next = new_elem;
list->tail = new_elem;
}
new_elem->key = key;
new_elem->value = value;
--list->k;
}else{ // replace
element_t *update = list->head;
update_list(list,hash_table,update->key,update);
update->value = value;
hash_remove_value(hash_table,update->key);
hash_set_value(hash_table,key,update);
update->key = key;
}
}
}
int * LRU(int** operators, int operatorsRowLen, int* operatorsColLen, int k, int* returnSize ) {
*returnSize = 0;
list_t g_list={NULL,NULL,k};
hash_t* hash_table = hash_init(10*k);
int result_size=0;
int *res;
// 计算返回值数组的大小
for(int i=0;i<operatorsRowLen;++i)
{
if(operatorsColLen[i]==2)
++result_size;
}
res=(int*)malloc(sizeof(int)*result_size);
for(int i=0;i<operatorsRowLen;++i)
{
if(operatorsColLen[i]==2){
res[(*returnSize)++] = list_get_value(&g_list,hash_table,operators[i][1]);
}else{
insert_list(&g_list,hash_table,operators[i][1],operators[i][2]);
}
}
hash_destroy(hash_table);
return res;
}