單鏈表具有單向性的缺點,找前驅不方便!
雙向鏈表也叫雙鏈表,是鏈表的一種,它的每個數據結點中都有兩個指針,分別指向直接后繼和直接前驅。所以,從雙向鏈表中的任意一個結點開始,都可以很方便地訪問它的前驅結點和后繼結點。一般我們都構造雙向循環鏈表。
image.png
image.png
創建一個節點,節點包含前節點,后節點,本節點的key和value
/**
節點信息
*/
@interface TwoWayLinkedListNode : NSObject
{
@package
__unsafe_unretained TwoWayLinkedListNode *_prior; // retained by dic
__unsafe_unretained TwoWayLinkedListNode *_next; // retained by dic
id _key;
id _value;
}
@end
@implementation TwoWayLinkedListNode
@end
/**
鏈表
*/
@interface TwoWayLinkedList ()
{
@package
TwoWayLinkedListNode *_head; // 鏈表頭
TwoWayLinkedListNode *_tail; // 鏈表尾
NSMutableDictionary *_dic; // 鏈表字典
}
@end
@implementation TwoWayLinkedList
- (instancetype)init
{
self = [super init];
if (self) {
_dic = [NSMutableDictionary dictionary];
}
return self;
}
- 在最前端添加一個節點
/**
在最前端添加一個節點
@param node node
*/
- (void)insertNodeAtHead:(TwoWayLinkedListNode *)node {
[_dic setObject:node forKey:node->_key];
if (_head) {
node->_next = _head;
_head->_prior = node;
_head = node;
}
else {
_head = _tail = node;
}
}
- 將某個節點移到最前端
/**
將某個節點移到最前端
@param node node
*/
- (void)bringNodeToHead:(TwoWayLinkedListNode *)node {
if (_head == node) {
return;
}
if (_tail == node) {
/*
條件:node節點是tail節點時
將node節點的前一個節點變成tail節點
tail節點的next置空
*/
_tail = node->_prior;
_tail->_next = nil;
}
else {
/*
條件:node節點是中間節點時
將node的前一個節點賦值給node的下一個節點的prev
將node的下一個節點賦值給node的前一個節點
*/
node->_next->_prior = node->_prior;
node->_prior->_next = node->_next;
}
// 將node移動到head節點并且將原head節點的放到head->next節點中
node->_next = _head;
node->_prior = nil;
_head->_prior = node;
_head = node;
}
- 刪除某個節點
/**
刪除某個節點
@param node 節點
*/
- (void)removeNode:(TwoWayLinkedListNode *)node {
[_dic removeObjectForKey:node->_key];
if (node->_next) {
node->_next->_prior = node->_prior;
}
if (node->_prior) {
node->_prior->_next = node->_next;
}
if (_head == node) {
_head = node->_next;
}
if (_tail == node) {
_tail = node->_prior;
}
}
- 清空鏈表
/**
清空鏈表
*/
- (void)removeAll {
_head = nil;
_tail = nil;
_dic = [NSMutableDictionary dictionaryWithCapacity:0];
}
擴展1
最近最久未使用算法
每次將使用到的節點移動到最前方實現LRU算法
TwoWayLinkedList *list = [[TwoWayLinkedList alloc]init];
if (node) {
[list bringNodeToHead:node];
} else {
[list insertNodeAtHead:node];
}
擴展2
將鏈表就地逆置
image.png
插入法:掃描a1……an, 將每個ai插入到鏈表首部即可。
image.png