雙向鏈表

單鏈表具有單向性的缺點,找前驅不方便!

雙向鏈表也叫雙鏈表,是鏈表的一種,它的每個數據結點中都有兩個指針,分別指向直接后繼和直接前驅。所以,從雙向鏈表中的任意一個結點開始,都可以很方便地訪問它的前驅結點和后繼結點。一般我們都構造雙向循環鏈表

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
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容