OC中双向链表的实现
Posted 木子沉雨
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了OC中双向链表的实现相关的知识,希望对你有一定的参考价值。
双向链表的概念
双向链表也叫双链表,是链表的一种,它的每个数据结点中都有两个指针,分别指向直接后继和直接前驱。所以,从双向链表中的任意一个结点开始,都可以很方便地访问它的前驱结点和后继结点。一般我们都构造双向循环链表。
双向链表的实现
链表的是由节点构成的,节点的创建代码如下:
@interface BOLoopListNode : NSObject { BOLoopListNode *mpPrev; id mpData; BOLoopListNode *mpNext; } /** 指向前一个数据 */ @property (nonatomic, strong) BOLoopListNode *prev; /** 当前数据 */ @property (nonatomic, strong) id data; /** 指向后一个数据 */ @property (nonatomic, strong) BOLoopListNode *next; + (BOLoopListNode *)node; + (BOLoopListNode *)nodeWithData:(id)data; - (id)initWithData:(id)data;
主要方法
1.链表的初始化方法
- (instancetype)init { if (self = [super init]) { mpHead = [[BOLoopListNode alloc] init]; mpHead.prev = mpHead; mpHead.next = mpHead; mpCurrent = mpHead; } return self; }
链表的初始化方法,此时已经形成了一个双向链表。该链表只有一个头结点,并且该节点的前驱和后继都指向自己。
2.拼接节点
- (BOLoopListNode *) appendNode:(BOLoopListNode *)pNode withPrevNode:(BOLoopListNode *) pPrevNode { if (!pNode) { return nil; } pNode.prev = pPrevNode; pNode.next = pPrevNode.next; pPrevNode.next.prev = pNode; pPrevNode.next = pNode; muCount++; return pNode; }
在pPrevNode处,插入pNode节点,并使当前链表的计数器加一。使pNode的前驱指向pPrevNode,使pNode的后继指向pPrevNode的next,并且使pPrevNode的next的前驱指向pNode。
3.移除节点
- (BOLoopListNode *) removeNode:(BOLoopListNode*) pNode { if (!pNode) { pNode = mpCurrent; } if (pNode != mpHead) { pNode.prev.next = pNode.next; pNode.next.prev = pNode.prev; if (mpCurrent == pNode) { if (mpCurrent.next != mpHead) { mpCurrent = mpCurrent.next; } else { mpCurrent = mpCurrent.prev; } } muCount--; NSLog(@"%zd", muCount); return pNode; } else if(pNode == mpHead) { return nil; } return nil; }
在判断要移除的节点非空并且不是头结点后,把pNode的prev的后继指向pNode的next,把pNode.next的前驱指向pNode的prev。并判断mpCurrent指针是否在该删除的节点上。
4.添加链表到目标链表
-(void)joinToListWithTargetList:(BOLoopList *)targetList withNode:(BOLoopListNode *)pNode { if (muCount == 0) { return; }else if (muCount == 1) { [targetList appendNode:[self getBegin] withPrevNode:pNode]; muCount = 0; }else { pNode.next.prev = mpHead.prev; mpHead.prev.next = pNode.next; pNode.next = mpHead.next; mpHead.next.prev = pNode; mpHead.next = mpHead; mpHead.prev = mpHead; targetList.listCount += muCount; muCount = 0; } }
判断要添加的链表长度,如果为一,当成一个节点拼接进去,若是不是一,就把该链表拼接到目标链表的尾端。
5.排序函数
// 升序排列 - (void)sortByAscendingOrder { if (muCount < 2) { //空链表与一个节点的链表无需排序 return; } //记录下开始节点 BOLoopListNode* pBeginNode = mpHead.next.next; BOLoopListNode* pEndNode = mpHead.prev; BOLoopListNode* pCurrentNode = pBeginNode; //取下链表中第一个节点之外的节点 mpHead.next.next = mpHead; mpHead.next.prev = mpHead; mpHead.prev = mpHead.next; //使取下节点中的开始节点的前一节点与结束节点的后一节点指向nil pBeginNode.prev = nil; pEndNode.next = nil; BOLoopListNode* pEnumNode = nil; BOLoopListNode* pAddNode = nil; kNodeCompare compareResult = kNodeCompareLessThan; while (pCurrentNode) { pAddNode = pCurrentNode; pCurrentNode = pCurrentNode.next; for (pEnumNode = mpHead.prev; pEnumNode != mpHead; pEnumNode = pEnumNode.prev) { //当前链表从大到小(降序)遍历 compareResult = (kNodeCompare)[self.delegate nodeCompare:(pAddNode.data) withSecondData:pEnumNode.data];; if (compareResult != kNodeCompareLessThan) { //要添加的节点不小于当前链表中枚举节点 //将要添加的节点加到枚举节点后面 pAddNode.next = pEnumNode.next; pAddNode.next.prev = pAddNode; pAddNode.prev = pEnumNode; pEnumNode.next = pAddNode; break; } } //要添加的节点比链表中所有的节点都小 //加到头结点的后面 if (pEnumNode == mpHead) { pAddNode.next = mpHead.next; mpHead.next.prev = pAddNode; pAddNode.prev = mpHead; mpHead.next = pAddNode; } } }
这里以升序排序为例,在这里为什么取链表中第一个节点之外的节点。相当于在第二个节点之前截断,第一个节点用作比较,此时从某种意义上说,自头指针那儿分割,已经变成了两个链表。每次取head指针左边的和右边的比较,在合适的节点处插入。
而代码:
compareResult = (kNodeCompare)[self.delegate nodeCompare:(pAddNode.data) withSecondData:pEnumNode.data];
因为链表中的数据类型是不确定的,所以比较方法也是不确定的。则是外界成为了我的代理,传进来的比较链表中数据的方法。
协议代码如下:
typedef enum { kNodeCompareLessThan = -1, kNodeCompareEqual, kNodeCompareMoreThan }kNodeCompare; @protocol kNodeCompareDelegate <NSObject> - (kNodeCompare) nodeCompare:(id)firsrData withSecondData:(id)secondData;
降序排序跟这个类似,就不多说了。
详细代码BOLoopListNode类如下:
#import <Foundation/Foundation.h> @interface BOLoopListNode : NSObject { BOLoopListNode *mpPrev; id mpData; BOLoopListNode *mpNext; } /** 指向前一个数据 */ @property (nonatomic, strong) BOLoopListNode *prev; /** 当前数据 */ @property (nonatomic, strong) id data; /** 指向后一个数据 */ @property (nonatomic, strong) BOLoopListNode *next; + (BOLoopListNode *)node; + (BOLoopListNode *)nodeWithData:(id)data; - (id)initWithData:(id)data; @end
#import "BOLoopListNode.h" @implementation BOLoopListNode - (void)dealloc { self.data = nil; self.prev = nil; self.next = nil; } - (instancetype)init { return [self initWithData:nil]; } - (instancetype)initWithData:(id)data { if (self = [super init]) { self.prev = nil; self.data = data; self.next = nil; } return self; } + (BOLoopListNode *)node { BOLoopListNode *node = [[BOLoopListNode alloc] init]; return node; } + (BOLoopListNode *)nodeWithData:(id)data { BOLoopListNode *node = [[BOLoopListNode alloc] initWithData:data]; return node; } @end
BOLoopList类代码如下:
#import <Foundation/Foundation.h> #import "BOLoopListNode.h" typedef enum { kNodeCompareLessThan = -1, kNodeCompareEqual, kNodeCompareMoreThan }kNodeCompare; @protocol kNodeCompareDelegate <NSObject> - (kNodeCompare) nodeCompare:(id)firsrData withSecondData:(id)secondData; @end; @interface BOLoopList : NSObject { BOLoopListNode *mpHead; BOLoopListNode *mpCurrent; NSUInteger muCount; } @property (nonatomic, weak) id<kNodeCompareDelegate> delegate; /**头指针*/ @property (nonatomic, strong) BOLoopListNode *head; /**开始的指针*/ @property (nonatomic, strong) BOLoopListNode *begin; /**末尾指针*/ @property (nonatomic, strong) BOLoopListNode *end; /**当前的指针*/ @property (nonatomic, strong) BOLoopListNode *current; /**当前链表数据个数*/ @property (nonatomic, assign) NSUInteger listCount; + (id)list; /**得到头部指针*/ - (BOLoopListNode *)getHead; /**得到开始数据的指针*/ - (BOLoopListNode *)getBegin; /**得到末尾数据*/ - (BOLoopListNode *)getEnd; /**移动当前数据指针到开始*/ - (BOLoopListNode *)moveBegin; /**移动当前数据指针到末尾*/ - (BOLoopListNode *)moveEnd; /**移动到头指针*/ - (BOLoopListNode *)moveHead; /**移动当前数据指针到下一个*/ - (BOLoopListNode*) moveNext; /**移动当前指针到上一个*/ - (BOLoopListNode*) movePrev; /**拼接数据*/ - (BOLoopListNode *)appendData:(id)data; /**在某一节点处拼接数据*/ - (BOLoopListNode *)appendData:(id)data withPrevNode:(BOLoopListNode *)prevNode; /**拼接节点*/ - (BOLoopListNode *)appendNode:(BOLoopListNode *)pNode; /**在某个节点处拼接节点*/ - (BOLoopListNode *)appendNode:(BOLoopListNode *)pNode withPrevNode:(BOLoopListNode *)pNode; /**删除某个数据对应的节点*/ - (BOLoopListNode *)removeNodeWithData:(id)data; /**删除某个节点*/ - (BOLoopListNode *)removeNode:(BOLoopListNode *)pNode; /**添加一个链表到另外一个链表*/ - (void)joinToListWithTargetList:(BOLoopList *)targetList withNode:(BOLoopListNode *)pNode; /**升序排列链表*/ - (void) sortByAscendingOrder; /**按降序排序*/ - (void) sortByDeScendingOrder; /**在某个节点后面拼接一个节点*/ - (BOLoopListNode*) preAppendNode:(BOLoopListNode*) pNode withNextNode:(BOLoopListNode*) pNextNode; /**清空链表*/ - (void)clearList; @end
#import "BOLoopList.h" @interface BOLoopList() @end @implementation BOLoopList @synthesize listCount = muCount; - (instancetype)init { if (self = [super init]) { mpHead = [[BOLoopListNode alloc] init]; mpHead.prev = mpHead; mpHead.next = mpHead; mpCurrent = mpHead; } return self; } + (id)list { return [[self alloc] init]; } - (BOLoopListNode *)getHead { return mpHead; } - (BOLoopListNode *)getBegin { return mpHead.next; } - (BOLoopListNode *)getEnd { return mpHead.prev; } - (BOLoopListNode *) moveBegin { return mpCurrent = mpHead.next; } - (BOLoopListNode *) moveEnd { return mpCurrent = mpHead.prev; } - (BOLoopListNode *) moveHead { return mpCurrent = mpHead; } - (BOLoopListNode *) moveNext { return mpCurrent = mpCurrent.next; } - (BOLoopListNode *) movePrev { return mpCurrent = mpCurrent.prev; } - (BOLoopListNode *) appendData:(id) data { return [self appendData:data withPrevNode:mpHead.prev]; } - (BOLoopListNode *) appendData:(NSString *)data withPrevNode:(BOLoopListNode *) pPrevNode { NSLog(@"liupeng%@",data); BOLoopListNode* pNode = [BOLoopListNode nodeWithData:data]; return [self appendNode:pNode withPrevNode:pPrevNode]; } - (BOLoopListNode *) appendNode:(BOLoopListNode *) pNode { return [self appendNode:pNode withPrevNode:mpHead.prev]; } - (BOLoopListNode *) appendNode:(BOLoopListNode *)pNode withPrevNode:(BOLoopListNode *) pPrevNode { if (!pNode) { return nil; } pNode.prev = pPrevNode; pNode.next = pPrevNode.next; pPrevNode.next.prev = pNode; pPrevNode.next = pNode; muCount++; return pNode; } - (BOLoopListNode*) removeNodeWithData:(id) data { for (BOLoopListNode* pNode = mpHead.next; pNode != mpHead; pNode = pNode.next) { if (pNode.data == data) { return [self removeNode:pNode]; } } return nil; } - (BOLoopListNode *) removeNode:(BOLoopListNode*) pNode { if (!pNode) { pNode = mpCurrent; } if (pNode != mpHead) { pNode.prev.next = pNode.next; pNode.next.prev = pNode.prev; if (mpCurrent == pNode) { if (mpCurrent.next != mpHead) { mpCurrent = mpCurrent.next; } else { mpCurrent = mpCurrent.prev; } } muCount--; NSLog(@"%zd", muCount); return pNode; } else if(pNode == mpHead) { return nil; } return nil; } -(void)joinToListWithTargetList:(BOLoopList *)targetList withNode:(BOLoopListNode *)pNode { if (muCount == 0) { return; }else if (muCount == 1) { [targetList appendNode:[self getBegin] withPrevNode:pNode]; muCount = 0; }else { pNode.next.prev = mpHead.prev; mpHead.prev.next = pNode.next; pNode.next = mpHead.next; mpHead.next.prev = pNode; mpHead.next = mpHead; mpHead.prev = mpHead; targetList.listCount += muCount; muCount = 0; } } - (void) clearList { mpCurrent = mpHead.next; while (muCount) { mpCurrent = mpCurrent.next; muCount--; } mpCurrent = mpHead; mpHead.prev = mpHead; mpHead.next = mpHead; return; } // 升序排列 - (void)sortByAscendingOrder { if (muCount < 2) { //空链表与一个节点的链表无需排序 return; } //记录下开始节点 BOLoopListNode* pBeginNode = mpHead.next.next; BOLoopListNode* pEndNode = mpHead.prev; BOLoopListNode* pCurrentNode = pBeginNode; //取下链表中第一个节点之外的节点 mpHead.next.next = mpHead; mpHead.next.prev = mpHead; mpHead.prev = mpHead.next; //使取下节点中的开始节点的前一节点与结束节点的后一节点指向nil pBeginNode.prev = nil; pEndNode.next = nil; BOLoopListNode* pEnumNode = nil; BOLoopListNode* pAddNode = nil; kNodeCompare compareResult = kNodeCompareLessThan; while (pCurrentNode) { pAddNode = pCurrentNode; pCurrentNode = pCurrentNode.next; for (pEnumNode = mpHead.prev; pEnumNode != mpHead; pEnumNode = pEnumNode.prev) { //当前链表从大到小(降序)遍历 compareResult = (kNodeCompare)[self.delegate nodeCompare:(pAddNode.data) withSecondData:pEnumNode.data]; if (compareResult != kNodeCompareLessThan) { //要添加的节点不小于当前链表中枚举节点 //将要添加的节点加到枚举节点后面 pAddNode.next = pEnumNode.next; pAddNode.next.prev = pAddNode; pAddNode.prev = pEnumNode; pEnumNode.next = pAddNode; break; } } //要添加的节点比链表中所有的节点都小 //加到头结点的后面 if (pEnumNode == mpHead) { pAddNode.next = mpHead.next; mpHead.next.prev = pAddNode; pAddNode.prev = mpHead; mpHead.next = pAddNode; } } } // 降序排列 - (void)sortByDeScendingOrder { if (muCount < 2) { //空链表与一个节点的链表无需排序 return; } //记录下开始节点 BOLoopListNode* pBeginNode = mpHead.next.next; BOLoopListNode* pEndNode = mpHead.prev; BOLoopListNode* pCurrentNode = pBeginNode; //取下链表中第一个节点之外的节点 mpHead.next.next = mpHead; mpHead.next.prev = mpHead; mpHead.prev = mpHead.next; //使取下节点中的开始节点的前一节点与结束节点的后一节点指向nil pBeginNode.prev = nil; pEndNode.next = nil; BOLoopListNode* pEnumNode = nil; BOLoopListNode* pAddNode = nil; kNodeCompare compareResult = kNodeCompareLessThan; while (pCurrentNode) { pAddNode = pCurrentNode; pCurrentNode = pCurrentNode.next; for (pEnumNode = mpHead.next; pEnumNode != mpHead; pEnumNode = pEnumNode.next) { //当前链表从大到小(降序)遍历 compareResult = (kNodeCompare)[self.delegate nodeCompare:(pAddNode.data) withSecondData:pEnumNode.data]; if (compareResult != kNodeCompareLessThan) { //要添加的节点不小于当前链表中枚举节点 //将要添加的节点加到枚举节点前面 pAddNode.prev = pEnumNode.prev; pAddNode.prev.next = pAddNode; pAddNode.next = pEnumNode; pEnumNode.prev = pAddNode; break; } } //要添加的节点比链表中所有的节点都小 //加到头结点的前面 if (pEnumNode == mpHead) { pAddNode.prev = mpHead.prev; pAddNode.prev.next = pAddNode; pAddNode.next = mpHead; mpHead.prev = pAddNode; } } } - (BOLoopListNode*) preAppendNode:(BOLoopListNode*) pNode withNextNode:(BOLoopListNode*) pNextNode { if (!pNode) { return nil; } pNode.prev = pNextNode.prev; pNode.next = pNextNode; pNextNode.prev.next = pNode; pNextNode.prev = pNode; muCount++; return pNode; } @end
以上是关于OC中双向链表的实现的主要内容,如果未能解决你的问题,请参考以下文章