iOS-數據結構之鏈表以及二叉樹

(一)前言html

對於頻繁使用或者是操做的數據應當使用鏈表,提高效率;node

(1)鏈表的優勢:鏈表插入和刪除節點付出的代價較小,主要的操做在於prev或next指針的重指向。缺點:鏈表不能經過下標或者是key查詢某個節點,要想獲取某一指定的節點,須要從_headNode從頭開始遍歷,消耗是極大的。數組

(2)數組、字典等數據結構,相對於鏈表而言,遍歷的效率要好得多,也能夠經過下標或key獲取指定的元素,這個剛好是鏈表的缺點;而數組、字典等,在添加或刪除元素以後,會從頭至尾從新的排列全部的元素,消耗極大;網絡

所以,結合二者的優勢,下面所要介紹的雙向鏈表內容,會使用dictionary保存全部的節點信息,以便經過key能獲取到指定的節點,用於鏈表的操做;數據結構

(3)二叉樹,大多數操做都採用遞歸思想,好比添加節點、前序遍歷、中序遍歷、後序遍歷以及計算節點數等;(遞歸調用是經過棧來實現的,每調用一次函數,系統都將函數當前的變量、返回地址等信息保存爲一個棧幀壓入到棧中,那麼一旦要處理的運算很大或者數據不少,有可能會致使不少函數調用或者很大的棧幀,這樣不斷的壓棧,很容易致使棧的溢出);函數

 

(二)雙向鏈表;post

(1)雙向鏈表節點類,包含key、value以及前節點和後節點等信息;ui

#import <Foundation/Foundation.h>

@interface NTLinkedNode : NSObject

@property (nonatomic, strong) NSString *key;
@property (nonatomic, strong) NSString *value;
@property (nonatomic, strong) NTLinkedNode *prev;
@property (nonatomic, strong) NTLinkedNode *next;

@end

 

(2)雙向鏈表管理類,能夠添加、移動、刪除節點;atom

#import <Foundation/Foundation.h>
@class NTLinkedNode;

@interface NTLinkedMap : NSObject

- (void)addNodeAtHead:(NTLinkedNode *)node;
- (void)addNode:(NTLinkedNode *)newNode beforeNodeForKey:(NSString *)key;
- (void)addNode:(NTLinkedNode *)newNode behindNodeForKey:(NSString *)key;
- (void)bringNodeToHead:(NTLinkedNode *)node;

- (void)readAllNode;
- (void)removeNodeForKey:(NSString *)key;
- (NTLinkedNode *)removeTailNode;

- (void)headNode;
- (void)tailNode;

@end



#import "NTLinkedMap.h"
#import "NTLinkedNode.h"

@interface NTLinkedMap () {
    
    NTLinkedNode *_headNode;//頭節點;
    NTLinkedNode *_tailNode;//尾節點;
    NSMutableDictionary *dicKeyValue;//用於保存全部節點;
}

@end

@implementation NTLinkedMap

- (instancetype)init {
    
    self = [super init];
    if (self) {
        
        dicKeyValue = [NSMutableDictionary dictionary];
    }
    
    return self;
}

//將節點添加在頭部以前;
- (void)addNodeAtHead:(NTLinkedNode *)node {
    
    dicKeyValue[node.key] = node;
    if (_headNode) {
        
        node.next = _headNode;
        _headNode.prev = node;
        _headNode = node;
        
    } else {
        
        _headNode = _tailNode = node;
    }
}

//在指定的節點以前添加新節點;
- (void)addNode:(NTLinkedNode *)newNode beforeNodeForKey:(NSString *)key {
    
    NTLinkedNode *node = dicKeyValue[key];
    dicKeyValue[newNode.key] = newNode;
    
    if (!_headNode && !_tailNode) {
        
        _headNode = _tailNode = newNode;
    }
    
    if (node) {
        
        if ([_headNode isEqual:node]) {
            
            _headNode = newNode;
        }
        
        if (node.prev) {
            
            newNode.prev = node.prev;
            node.prev.next = newNode;
        }
        
        newNode.next = node;
        node.prev = newNode;
    }
}


//在指定的節點以後添加新節點;
- (void)addNode:(NTLinkedNode *)newNode behindNodeForKey:(NSString *)key {
    
    NTLinkedNode *node = dicKeyValue[key];
    dicKeyValue[newNode.key] = newNode;
    
    if (!_headNode && !_tailNode) {
        
        _headNode = _tailNode = newNode;
        
    } else {
        
        if (node) {
            
            if ([_tailNode isEqual:node]) {
                
                _tailNode = newNode;
            }
            
            if (node.next) {
                
                node.next.prev = newNode;
                newNode.next = node.next;
            }
            
            newNode.prev = node;
            node.next = newNode;
        }
    }
}


//移動node至頭部節點;
- (void)bringNodeToHead:(NTLinkedNode *)node {
    
    if ([_headNode isEqual:node]) {
        
        return;
    }
    
    if ([_tailNode isEqual:node]) {
        
        _tailNode = node.prev;
        _tailNode.next = nil;
        
    } else {
        
        node.next.prev = node.prev;
        node.prev.next = node.next;
    }
    
    _headNode.prev = node;
    node.next = _headNode;
    node.prev = nil;
    _headNode = node;
}


//移除某個節點;
- (void)removeNodeForKey:(NSString *)key {
    
    NTLinkedNode *node = dicKeyValue[key];
    if (node) {
        
        [dicKeyValue removeObjectForKey:key];
        if (node.next) {
            
            node.next.prev = node.prev;
        }
        
        if (node.prev) {
            
            node.prev.next = node.next;
        }
        
        if ([_headNode isEqual:node]) {
            
            _headNode = node.next;
        }
        
        if ([_tailNode isEqual:node]) {
            
            _tailNode = node.prev;
        }
    }
}


//移除尾部節點;
- (NTLinkedNode *)removeTailNode {
    
    if (!_tailNode) {
        
        return nil;
    }
    
    NTLinkedNode *tailNode = _tailNode;
    [dicKeyValue removeObjectForKey:_tailNode.key];
    if (_headNode == _tailNode) {
        
        _headNode = _tailNode = nil;
        
    } else {
        
        _tailNode = _tailNode.prev;
        _tailNode.next = nil;
    }
    
    return tailNode;
}


//遍歷全部的node節點;
- (void)readAllNode {
    
    if (_headNode) {
        
        NTLinkedNode *node = _headNode;
        while (node) {
            
            NSLog(@"key -- %@, value -- %@", node.key, node.value);
            node = node.next;
        }
    }
}

- (void)headNode {
    
    NSLog(@"head node key -- %@, head node value -- %@", _headNode.key, _headNode.value);
    NSLog(@"node count -- %lu", (unsigned long)dicKeyValue.count);
}

- (void)tailNode {
    
    NSLog(@"tail node key -- %@, tail node value -- %@", _tailNode.key, _tailNode.value);
    NSLog(@"node count -- %lu", (unsigned long)dicKeyValue.count);
}
@end

 

(三)單向鏈表;指針

(1)單向鏈表節點類,保存節點信息;

#import <Foundation/Foundation.h>

@interface NTSingleLinkedNode : NSObject

@property (nonatomic, strong) NSString *key;
@property (nonatomic, strong) NSString *value;
@property (nonatomic, strong) NTSingleLinkedNode *next;

@end

 

(2)單向鏈表管理類,用於添加、刪除、移動以及遍歷鏈表節點;

#import <Foundation/Foundation.h>
@class NTSingleLinkedNode;

@interface NTSingleLinkedList : NSObject

- (void)addNodeAtHead:(NTSingleLinkedNode *)node;
- (NTSingleLinkedNode *)addNode:(NTSingleLinkedNode *)newNode behindNodeForKey:(NSString *)key;

- (NTSingleLinkedNode *)removeNode:(NTSingleLinkedNode *)node;
- (NTSingleLinkedNode *)selectNode:(NSString *)key;
- (void)bringNodeToHead:(NTSingleLinkedNode *)node;

- (void)readAllNode;

@end


#import "NTSingleLinkedList.h"
#import "NTSingleLinkedNode.h"

@interface NTSingleLinkedList () {
    
    NTSingleLinkedNode *_headNode;
    NSMutableDictionary *dictKeyValue;
}

@end

@implementation NTSingleLinkedList

- (instancetype)init {
    
    self = [super init];
    if (self) {
        
        dictKeyValue = [NSMutableDictionary dictionary];
    }
    
    return self;
}

//新節點添加在頭部以前;
- (void)addNodeAtHead:(NTSingleLinkedNode *)node {
    
    dictKeyValue[node.key] = node;
    if (_headNode) {
        
        node.next = _headNode;
        _headNode = node;
        
    } else {
        
        _headNode = node;
    }
}


//新節點添加值指定節點以後(節點不可重複);
- (NTSingleLinkedNode *)addNode:(NTSingleLinkedNode *)newNode behindNodeForKey:(NSString *)key {
    
    if (!key) {
        
        return _headNode;
    }
    
    NTSingleLinkedNode *node = dictKeyValue[key];
    if (dictKeyValue[newNode.key]) {//判斷節點是否存在;
        
        return _headNode;
    }
    
    dictKeyValue[newNode.key] = newNode;
    newNode.next = node.next;
    node.next = newNode;
    
    
    return newNode;
}


//刪除節點;
- (NTSingleLinkedNode *)removeNode:(NTSingleLinkedNode *)node {
    
    if (!_headNode || !node) {
        
        return _headNode;
    }
    
    NTSingleLinkedNode *tempNode;
    [dictKeyValue removeObjectForKey:node.key];
    
    //若刪除節點不是尾節點,則將當前節點替換成當前節點的下一個節點;
    if (node.next) {
        
        tempNode = node.next;
        node.next = node.next.next;
        node.key = tempNode.key;
        node.value = tempNode.value;
        
        tempNode = nil;
        return _headNode;
        
    } else {
        
        //從_headNode開始遍歷鏈表,找到tempNode即node的前一個節點;
        tempNode = _headNode;
        while (tempNode.next && ![tempNode.next isEqual:node]) {
            
            tempNode = tempNode.next;
        }
        
        if (tempNode.next) {
            
            tempNode.next = node.next;
        }
    }
    
    return _headNode;
}


//將node移至頭部head;
- (void)bringNodeToHead:(NTSingleLinkedNode *)node {
    
    if (!_headNode || !node) {
        
        return;
    }
    
    if ([_headNode isEqual:node]) {
        
        return ;
    }
    
    //從_headNode開始遍歷鏈表,找到tempNode即node的前一個節點;
    NTSingleLinkedNode *tempNode = _headNode;
    while (tempNode.next && ![tempNode.next isEqual:node]) {
        
        tempNode = tempNode.next;
    }
    
    if (tempNode.next) {
        
        tempNode.next = node.next;
    }
    
    node.next = _headNode;
    _headNode = node;
}


//查找單向列表中的一個節點;
- (NTSingleLinkedNode *)selectNode:(NSString *)key {
    
    //固然了,由於定義了字典dicKeyVaue,能夠經過此字典,直接返回對應key的node;
    //return dicKeyVaue[key];
    
    NTSingleLinkedNode *tempNode = _headNode;
    while (tempNode) {
        
        if ([tempNode.key isEqualToString:key]) {
            
            return tempNode;
        }
        
        tempNode = tempNode.next;
    }
    
    return _headNode;
}


//遍歷全部節點;
- (void)readAllNode {
    
    NTSingleLinkedNode *tempNode = _headNode;
    while (tempNode) {
        
        NSLog(@"node key -- %@, node value -- %@", tempNode.key, tempNode.value);
        tempNode = tempNode.next;
    }
}
@end

 

(四)二叉樹(二叉排序樹),參考來自網絡收集資料

(1)二叉樹節點定義,包含左節點leftNode、右節點rightNode、父節點(未使用)以及節點值value;

#import <Foundation/Foundation.h>

@interface NTBinaryTreeNode : NSObject

@property (nonatomic, assign) NSInteger value;

/**
 *  父節點
 */
@property (nonatomic, strong) NTBinaryTreeNode *fatherNode;

/**
 *  左節點
 */
@property (nonatomic, strong) NTBinaryTreeNode *leftNode;
/**
 *  右節點
 */
@property (nonatomic, strong) NTBinaryTreeNode *rightNode;

@end

 

(2)二叉樹管理類,建立和遍歷二叉樹以及增長二叉樹節點等;

#import <Foundation/Foundation.h>
@class NTBinaryTreeNode;

@interface NTBinaryTree : NSObject

+ (NTBinaryTreeNode *)createTreeWithValues:(NSArray *)values;
+ (NTBinaryTreeNode *)addTreeNode:(NTBinaryTreeNode *)treeNode value:(NSInteger)value;

+ (NTBinaryTreeNode *)invertBinaryTree:(NTBinaryTreeNode *)rootNode;

+ (NTBinaryTreeNode *)treeNodeAtIndex:(NSInteger)index inTree:(NTBinaryTreeNode *)treeNode;

+ (void)levelTraverseTree:(NTBinaryTreeNode *)treeNode handler:(void (^)(NTBinaryTreeNode *node))handler;
+ (void)depthTraverseTree:(NTBinaryTreeNode *)treeNode handler:(void (^)(NTBinaryTreeNode *node))handler;

+ (void)preOrderTraverseTree:(NTBinaryTreeNode *)rootNode handler:(void(^)(NTBinaryTreeNode *treeNode))handler;

//非遞歸遍歷二叉樹;
+ (void)preTraverseTree:(NTBinaryTreeNode *)treeNode handler:(void (^)(NTBinaryTreeNode *node))handler;
+ (void)inTraverseTree:(NTBinaryTreeNode *)treeNode handler:(void (^)(NTBinaryTreeNode *node))handler;
+ (void)postTraverseTree:(NTBinaryTreeNode *)treeNode handler:(void (^)(NTBinaryTreeNode *node))handler;

@end



#import "NTBinaryTree.h"
#import "NTBinaryTreeNode.h"

@implementation NTBinaryTree


/**
 *  建立二叉排序樹
 *  二叉排序樹:左節點值所有小於根節點值,右節點值所有大於根節點值
 *
 *  @param values 數組
 *
 *  @return 二叉樹根節點
 */
+ (NTBinaryTreeNode *)createTreeWithValues:(NSArray *)values {
    
    NTBinaryTreeNode *root = nil;
    for (NSInteger i = 0; i < values.count; i++) {
        
        NSInteger value = [(NSNumber *)[values objectAtIndex:i] integerValue];
        root = [NTBinaryTree addTreeNode:root value:value];
    }
    
    return root;
}


//遞歸添加節點,始終返回根節點;
+ (NTBinaryTreeNode *)addTreeNode:(NTBinaryTreeNode *)treeNode value:(NSInteger)value {
    
    //根節點不存在,建立節點
    if (!treeNode) {
        
        treeNode = [NTBinaryTreeNode new];
        treeNode.value = value;
        //NSLog(@"node:%@", @(value));
        
    } else if (value <= treeNode.value) {
        
        NSLog(@"to left");
        //值小於根節點,則插入到左子樹
        treeNode.leftNode = [NTBinaryTree addTreeNode:treeNode.leftNode value:value];
        
    } else {
        
        NSLog(@"to right");
        //值大於根節點,則插入到右子樹
        treeNode.rightNode = [NTBinaryTree addTreeNode:treeNode.rightNode value:value];
    }
    
    return treeNode;
}


//反轉二叉樹(左右節點互換),遞歸思想;
+ (NTBinaryTreeNode *)invertBinaryTree:(NTBinaryTreeNode *)rootNode {
    
    if (!rootNode) {
        
        return nil;
    }
    
    if (!rootNode.leftNode && !rootNode.rightNode) {
        
        return rootNode;
    }
    
    [self invertBinaryTree:rootNode.leftNode];//遞歸反轉左節點;
    [self invertBinaryTree:rootNode.rightNode];//遞歸反轉右節點;
    NTBinaryTreeNode *tempNode = rootNode.leftNode;
    rootNode.leftNode = rootNode.rightNode;
    rootNode.rightNode = tempNode;
    
    
    return rootNode;
}

//查找index位置的node -- 從0開始查找,根據先進先出的順序查找;
+ (NTBinaryTreeNode *)treeNodeAtIndex:(NSInteger)index inTree:(NTBinaryTreeNode *)treeNode {
    
    if (!treeNode || index < 0) {
        
        return nil;
    }
    
    NSMutableArray *queryArray = [NSMutableArray array];
    [queryArray addObject:treeNode];
    
    while (queryArray.count > 0) {
        
        NTBinaryTreeNode *node = [queryArray firstObject];
        
        if (index == 0) {
            
            return node;
        }
        
        [queryArray removeObjectAtIndex:0];
        index--;
        
        if (node.leftNode) {
            
            [queryArray addObject:node.leftNode];
        }
        
        if (node.rightNode) {
            
            [queryArray addObject:node.rightNode];
        }
    }
    
    return nil;
}


//廣度優先遍歷二叉樹,從上到下,從左到右依次遍歷,先遍歷完一層再遍歷下一層;
+ (void)levelTraverseTree:(NTBinaryTreeNode *)treeNode handler:(void (^)(NTBinaryTreeNode *))handler {
    
    if (!treeNode) {
        
        return;
    }
    
    NSMutableArray *queryArray = [NSMutableArray array];
    [queryArray addObject:treeNode];
    
    while (queryArray.count > 0) {
        
        NTBinaryTreeNode *node = [queryArray firstObject];
        
        if (handler) {
            
            handler(node);
        }
        
        [queryArray removeObjectAtIndex:0];//仿照隊列fifo原則;
        
        if (node.leftNode) {
            
            [queryArray addObject:node.leftNode];
        }
        
        if (node.rightNode) {
            
            [queryArray addObject:node.rightNode];
        }
    }
}


//深度優先遍歷,先遍歷左子樹,再遍歷右子樹;
+ (void)depthTraverseTree:(NTBinaryTreeNode *)treeNode handler:(void (^)(NTBinaryTreeNode *))handler {
    
    if (!treeNode) {
        
        return;
    }
    
    NSMutableArray *queryArray = [NSMutableArray array];
    [queryArray addObject:treeNode];
    
    while (queryArray.count > 0) {
        
        NTBinaryTreeNode *node = [queryArray firstObject];
        
        if (handler) {
            
            handler(node);
        }
        
        [queryArray removeObjectAtIndex:0];//仿照隊列fifo原則;
        
        if (node.rightNode) {
            
            [queryArray addObject:node.rightNode];
        }
        
        if (node.leftNode) {
            
            [queryArray addObject:node.leftNode];
        }
    }
}


/**
 *  前序遍歷 (中序遍歷 -- 先左子樹,再根,再右子樹;後序遍歷 -- 先左子樹,再右子樹,再根。)
 *  先訪問根,再遍歷左子樹,再遍歷右子樹;遞歸思想,每個不爲空的節點都重複先訪問根,再遍歷左子樹,再遍歷右子樹的流程;
 *
 *  @param rootNode 根節點
 *  @param handler  訪問節點處理函數
 */
+ (void)preOrderTraverseTree:(NTBinaryTreeNode *)rootNode handler:(void(^)(NTBinaryTreeNode *treeNode))handler {
    
    if (rootNode) {
        
        //讀取節點信息;
        if (handler) {
            
            handler(rootNode);
        }
        
        [self preOrderTraverseTree:rootNode.leftNode handler:handler];
        [self preOrderTraverseTree:rootNode.rightNode handler:handler];
    }
}


//非遞歸 -- 模擬節點進出棧方法實現,前序遍歷;
+ (void)preTraverseTree:(NTBinaryTreeNode *)treeNode handler:(void (^)(NTBinaryTreeNode *))handler {
    
    if (!treeNode) {
        
        return;
    }
    
    NSMutableArray *queryArray = [NSMutableArray array];
    NTBinaryTreeNode *node = treeNode;
    
    while (node || queryArray.count > 0) {
        
        while (node) {
            
            //讀取節點信息;
            if (handler) {
                
                handler(node);
            }
            
            [queryArray addObject:node];
            node = node.leftNode;
        }
        
        if (queryArray.count > 0) {
            
            node = [queryArray lastObject];
            [queryArray removeObject:node];
            node = node.rightNode;
        }
    }
}


//非遞歸 -- 模擬節點進出棧方法實現,中序遍歷;
+ (void)inTraverseTree:(NTBinaryTreeNode *)treeNode handler:(void (^)(NTBinaryTreeNode *))handler {
    
    if (!treeNode) {
        
        return;
    }
    
    NTBinaryTreeNode *node = treeNode;
    NSMutableArray *queryArray = [NSMutableArray array];
    
    while (node || queryArray.count > 0) {
        
        while (node) {
            
            [queryArray addObject:node];
            node = node.leftNode;
        }
        
        if (queryArray.count > 0) {
            
            node = [queryArray lastObject];
            [queryArray removeObject:node];
            
            //讀取節點信息;
            if (handler) {
                
                handler(node);
            }
            
            node = node.rightNode;
        }
    }
}


//非遞歸 -- 模擬節點進出棧方法實現,後序遍歷;
+ (void)postTraverseTree:(NTBinaryTreeNode *)treeNode handler:(void (^)(NTBinaryTreeNode *))handler {
    
    if (!treeNode) {
        
        return;
    }
    
    NTBinaryTreeNode *preNode = nil;
    NTBinaryTreeNode *curNode;
    NSMutableArray *queryArray = [NSMutableArray array];
    [queryArray addObject:treeNode];
    
    while (queryArray.count > 0) {
        
        //(1)當前節點左右孩子都不存在,能夠直接訪問該節點;
        //(2)存在左孩子節點或者是右孩子節點,且其左右孩子節點已經被訪問過,也能夠直接訪問該節點;
        curNode = [queryArray lastObject];
        if ((!curNode.leftNode && !curNode.rightNode) || (preNode && ([preNode isEqual:curNode.leftNode] || [preNode isEqual:curNode.rightNode]))) {
            
            if (handler) {
                
                handler(curNode);
            }
            
            [queryArray removeObject:curNode];
            preNode = curNode;
            
        }  else {
            
            if (curNode.rightNode) {
                
                [queryArray addObject:curNode.rightNode];
            }
            
            if (curNode.leftNode) {
                
                [queryArray addObject:curNode.leftNode];
            }
        }
    }
}
@end
相關文章
相關標籤/搜索