(一)前言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