单链表具有单向性的缺点,找前驱不方便!
双向链表也叫双链表,是链表的一种,它的每个数据结点中都有两个指针,分别指向直接后继和直接前驱。所以,从双向链表中的任意一个结点开始,都可以很方便地访问它的前驱结点和后继结点。一般我们都构造双向循环链表。
创建一个节点,节点包含前节点,后节点,本节点的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
将链表就地逆置
插入法:扫描a1……an, 将每个ai插入到链表首部即可。