算法-LRU存儲算法(OC、Python)

需求場景

數據緩存或者持久化一般分爲磁盤緩存和內存緩存,如果從讀寫速度上我們當然希望數據讀取的書讀越快越好,所以內存緩存倍受青睞,但是內存緩存由於成本限制,我們不能把全部的數據放在內存緩存裏,我們該如何取捨呢?
在這裏插入圖片描述

LRU

LRU是Least Recently Used的縮寫,意思是最近最少使用的數據,也就是最近使用的數據在未來的一段時間內任然被使用,已經使用很久的數據在未來的一段時間內任然不會變使用。基於這個理念我們可以在內存中保留常用的數據!

就是我們定義一個指定容量的list,每次新加的數據我們都會放在list的最上面,每次訪問的數據也會被放在list的最上面,要是加入的數據超出最大容量,刪除list的最好一個!

算法源碼

1.OC源碼

a.實現

/// 初始化
/// @param capacity 容量大小
- (instancetype)initWithCapacity:(NSUInteger)capacity{
    if(self == [super init]){
        _capacity = capacity;
    }
    return self;
}

/// 將對象存入緩存,如果 anyValue 爲 nil,會刪除對象
/// @param anyValue value
/// @param key key
- (void)setValue:(id)anyValue forKey:(NSString *)key{
    if(anyValue == nil){
        // 刪除對象
        return;
    }
    if([self.cacheDict.allKeys containsObject:key]){
        // 當前值已經存在
        [self.keys removeObject:key];
    }else{
        // 新存入的值
        if(self.keys.count == _capacity){
            // 超出最大值了 刪除棧裏第一個
            NSString *firstKey = [self.keys firstObject];
            [self.keys removeObject:firstKey];
            [self.cacheDict removeObjectForKey:firstKey];
        }
    }
    [self.cacheDict setValue:anyValue forKey:key];
    [self.keys addObject:key];
}

/// 取對象
/// @param key key
- (id)valueForKey:(NSString *)key{
    // 判斷是否存在
    if([self.cacheDict.allKeys containsObject:key]){
        [self.keys removeObject:key];
        [self.keys addObject:key];
        return [self.cacheDict objectForKey:key];
    }else{
        return nil;
    }
}

/// 刪除對象
/// @param key key
- (void)removeObjectForKey:(NSString *)key{
    if([self.cacheDict.allKeys containsObject:key]){
        [self.keys removeObject:key];
        [self.cacheDict removeObjectForKey:key];
    }else{
        /// 不存在
    }
}

/// 獲取所有的數據
/// @param block 鍵值對回調
- (void)enumerateKeysAndValuesUsingBlock:(void (^)(NSString *key, id obj, BOOL *stop))block{
    [self.keys enumerateObjectsUsingBlock:^(NSString * _Nonnull key, NSUInteger idx, BOOL * _Nonnull stop) {
        if(block){
            block(key, [self.cacheDict objectForKey:key], stop);
        }
    }];
}

/// 更新容量大小
/// @param capacity 容量大小
- (void)resetCapacity:(NSInteger)capacity{
    _capacity = capacity;
}

- (NSMutableArray *)keys{
    if(_keys == nil){
        _keys = [[NSMutableArray alloc] init];
    }
    return _keys;
}

- (NSMutableDictionary *)cacheDict{
    if(_cacheDict == nil){
        _cacheDict = [[NSMutableDictionary alloc] init];
    }
    return _cacheDict;
}

b.使用示例

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    for (int i = 1; i<=5; i++) {
        NSString *key = [NSString stringWithFormat:@"%d",i];
        NSString *value = [NSString stringWithFormat:@"%d",i * 100];
        [self.lruCacheMap setValue:value forKey:key];
    }
    [self.lruCacheMap enumerateKeysAndValuesUsingBlock:^(NSString *key, id obj, BOOL *stop) {
        NSLog(@"key, value == %@, %@",key, obj);
    }];
    NSLog(@"------------");
    
    [self.lruCacheMap setValue:@"600" forKey:@"6"];
    [self.lruCacheMap enumerateKeysAndValuesUsingBlock:^(NSString *key, id obj, BOOL *stop) {
        NSLog(@"key, value == %@, %@",key, obj);
    }];
    NSLog(@"------------");

    NSLog(@"%@", [self.lruCacheMap valueForKey:@"5"]);
    [self.lruCacheMap enumerateKeysAndValuesUsingBlock:^(NSString *key, id obj, BOOL *stop) {
        NSLog(@"key, value == %@, %@",key, obj);
    }];
    NSLog(@"------------");
    
    NSLog(@"%@", [self.lruCacheMap valueForKey:@"4"]);
    [self.lruCacheMap enumerateKeysAndValuesUsingBlock:^(NSString *key, id obj, BOOL *stop) {
        NSLog(@"key, value == %@, %@",key, obj);
    }];
}

- (LRUCacheMap *)lruCacheMap{
    if(_lruCacheMap == nil){
        _lruCacheMap = [[LRUCacheMap alloc] initWithCapacity:5];
    }
    return _lruCacheMap;
}

c.運行結果

2020-05-22 14:47:01.414530+0800 LRUDemo[65621:2173464] key, value == 1, 100
2020-05-22 14:47:01.414716+0800 LRUDemo[65621:2173464] key, value == 2, 200
2020-05-22 14:47:01.414809+0800 LRUDemo[65621:2173464] key, value == 3, 300
2020-05-22 14:47:01.414905+0800 LRUDemo[65621:2173464] key, value == 4, 400
2020-05-22 14:47:01.414995+0800 LRUDemo[65621:2173464] key, value == 5, 500
2020-05-22 14:47:01.415076+0800 LRUDemo[65621:2173464] ------------
2020-05-22 14:47:01.415169+0800 LRUDemo[65621:2173464] key, value == 2, 200
2020-05-22 14:47:01.415272+0800 LRUDemo[65621:2173464] key, value == 3, 300
2020-05-22 14:47:01.415519+0800 LRUDemo[65621:2173464] key, value == 4, 400
2020-05-22 14:47:01.415698+0800 LRUDemo[65621:2173464] key, value == 5, 500
2020-05-22 14:47:01.416035+0800 LRUDemo[65621:2173464] key, value == 6, 600
2020-05-22 14:47:01.416124+0800 LRUDemo[65621:2173464] ------------
2020-05-22 14:47:01.416314+0800 LRUDemo[65621:2173464] 500
2020-05-22 14:47:01.416453+0800 LRUDemo[65621:2173464] key, value == 2, 200
2020-05-22 14:47:01.416681+0800 LRUDemo[65621:2173464] key, value == 3, 300
2020-05-22 14:47:01.416763+0800 LRUDemo[65621:2173464] key, value == 4, 400
2020-05-22 14:47:01.852132+0800 LRUDemo[65621:2173464] key, value == 6, 600
2020-05-22 14:47:01.852262+0800 LRUDemo[65621:2173464] key, value == 5, 500
2020-05-22 14:47:01.852345+0800 LRUDemo[65621:2173464] ------------
2020-05-22 14:47:01.852431+0800 LRUDemo[65621:2173464] 400
2020-05-22 14:47:01.852507+0800 LRUDemo[65621:2173464] key, value == 2, 200
2020-05-22 14:47:01.852596+0800 LRUDemo[65621:2173464] key, value == 3, 300
2020-05-22 14:47:01.852668+0800 LRUDemo[65621:2173464] key, value == 6, 600
2020-05-22 14:47:01.852760+0800 LRUDemo[65621:2173464] key, value == 5, 500
2020-05-22 14:47:01.852835+0800 LRUDemo[65621:2173464] key, value == 4, 400
Message from debugger: Terminated due to signal 15

Python源碼

a.源碼實現

from collections import OrderedDict

class LRUCacheMap(object):
	def __init__(self, size):
		super(LRUCacheMap, self).__init__()
		# 總的容量大小
		self.total_capcity = size
		# 所有的鍵值對
		self.cache_map = OrderedDict()

	# 添加新值
	def set_value(self, key, value):
		if key in self.cache_map.keys():
			# 當前值已經存在
			value = self.cache_map.pop(key)
			self.cache_map[key] = value
		else:
			# 新存入的值
			if len(self.cache_map) == self.total_capcity:
				# 超出最大值了 刪除棧裏第一個
				self.cache_map.popitem(last = False)
			else:
				pass

			# 添加新的值
			self.cache_map[key] = value

	def get_value(self, key):
		# 判斷是否存在
		if key in self.cache_map.keys():
			value = self.cache_map.pop(key)
			self.cache_map[key] = value
		else:
			value = None

		return value

if __name__ == '__main__':
	cache_map = LRUCacheMap(5)
	for index in range(1, 6):
		cache_map.set_value(str(index), index * 100)

	print(cache_map.cache_map)
	print('-' * 100 + '\n')

	cache_map.set_value('6', 600)

	print(cache_map.cache_map)
	print('-' * 100 + '\n')

	print(cache_map.get_value('5'))
	print(cache_map.cache_map)
	print('-' * 100 + '\n')

	print(cache_map.get_value('4'))
	print(cache_map.cache_map)
	print('-' * 100 + '\n')

b.運行結果

OrderedDict([('1', 100), ('2', 200), ('3', 300), ('4', 400), ('5', 500)])
-------------------------------------------------------------------------

OrderedDict([('2', 200), ('3', 300), ('4', 400), ('5', 500), ('6', 600)])
-------------------------------------------------------------------------

500
OrderedDict([('2', 200), ('3', 300), ('4', 400), ('6', 600), ('5', 500)])
-------------------------------------------------------------------------
400
OrderedDict([('2', 200), ('3', 300), ('6', 600), ('5', 500), ('4', 400)])
-------------------------------------------------------------------------

[Finished in 0.0s]
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章