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 == ) {
return;
}else if (muCount == ) {
[targetList appendNode:[self getBegin] withPrevNode:pNode];
muCount = ;
}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 = ;
}
}
判断要添加的链表长度,如果为一,当成一个节点拼接进去,若是不是一,就把该链表拼接到目标链表的尾端。
5.排序函数
// 升序排列
- (void)sortByAscendingOrder {
if (muCount < )
{
//空链表与一个节点的链表无需排序
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 = -,
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 = -,
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 == ) {
return;
}else if (muCount == ) {
[targetList appendNode:[self getBegin] withPrevNode:pNode];
muCount = ;
}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 = ;
}
}
- (void) clearList
{
mpCurrent = mpHead.next;
while (muCount)
{
mpCurrent = mpCurrent.next;
muCount--;
}
mpCurrent = mpHead;
mpHead.prev = mpHead;
mpHead.next = mpHead; return;
}
// 升序排列
- (void)sortByAscendingOrder {
if (muCount < )
{
//空链表与一个节点的链表无需排序
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 < )
{
//空链表与一个节点的链表无需排序
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中双向链表的实现的更多相关文章
- OC中加载html5调用html方法和修改HTML5内容
1.利用webView控件加载本地html5或者网络上html5 2.设置控制器为webView的代理,遵守协议 3.实现代理方法webViewDidFinishLoad: 4.在代理方法中进行操作H ...
- java中的继承与oc中的继承的区别
为什么要使用继承? 继承的好处: (1)抽取出了重复的代码,使代码更加灵活 (2)建立了类和类之间的联系 继承的缺点: 耦合性太强 OC中的继承 1.OC中不允许子类和父类拥有相同名称的成员变量名:( ...
- Swift: 比较Swift中闭包传值、OC中的Block传值
一.介绍 开发者对匿名函数应该很清楚,其实它就是一个没有名字的函数或者方法,给人直观的感觉就是只能看到参数和返回值.在iOS开发中中,它又有自己的称呼,在OC中叫Block代码块,在Swift中叫闭包 ...
- OC中类别、扩展、协议与委托
一.类别(category) 类别(category)——通过使用类别,我们可以动态地为现有的类添加新方法,而且可以将类定义模块化地分不到多个相关文件中.通常只在类别中定义方法.(类别,接口部分的定义 ...
- OC中的私有变量和description
.OC中的私有变量 在类的实现即.m @implementation中也可以声明成员变量,但是因为在其他文件中通常都只 是包含头文件而不会包含实现文件,所以在.m文件中声明的成员变量是@private ...
- Oc中的数组
========================== 数组 ========================== 一.认识数组 oc中可以把NSObject对象的子类放到数组这个集合中,但是int.f ...
- OC中面向对象2
一. 定义OC的类和创建OC的对象 接下来就在OC中模拟现实生活中的情况,创建一辆车出来.首先要有一个车子类,然后再利用车子类创建车子对象 要描述OC中的类稍微麻烦一点,分2大步骤:类的声明.类的实现 ...
- OC中的面向对象语法
一. 面向对象和面向过程思想 OC是面向对象的,C是面向过程的.面向对象和面向过程只是解决问题的两种不同思想 1. 面向对象和面向过程的区别 1) 以用电脑听歌为例子 a) 面向过程 打开电脑 播放电 ...
- OC中的指针
NSError *err = nil; NSError __strong **error = &err; //因为在oc中,通过* *err 创建的指针是用__strong修改的,所以要一致, ...
随机推荐
- php socket通过smtp发送邮件(纯文本、HTML,多收件人,多抄送,多密送)
<?php /** * 邮件发送类 * 支持发送纯文本邮件和HTML格式的邮件,可以多收件人,多抄送,多秘密抄送 * @example * $mail = new MySendMail(); * ...
- mysql的一些配置优化
[mysqld]lower_case_table_names=1datadir=/var/lib/mysqlsocket=/var/lib/mysql/mysql.sockuser=mysql# Di ...
- 2018.10.30 NOIP模拟 有环无向图(dijkstra+巧妙建图)
传送门 建图巧妙啊. 对于每个点的出边,我们将它们排序之后依次连边. 这样可以把O(m2)O(m^2)O(m2)的边数变成O(m)O(m)O(m)的了. 连的权值就是max(edgemax(edgem ...
- 2018.10.25 uoj#308. 【UNR #2】UOJ拯救计划(排列组合)
传送门 有一个显然的式子:Ans=∑A(n,i)∗用i种颜色的方案数Ans=\sum A(n,i)*用i种颜色的方案数Ans=∑A(n,i)∗用i种颜色的方案数 这个东西貌似是个NPCNPCNPC. ...
- flex布局中的主轴和侧轴的确定
1.主轴和侧轴是通过flex-direction确定的 如果flex-direction是row或者row-reverse,那么主轴就是justify-contain 如果flex-direction ...
- PARSEC安环境配置、运行
1.getting started 2.run PARSEC on simulators Full-System Simulators: such as Simics, GEM5.Trace-Driv ...
- vue动态路由
我们经常需要把某种模式匹配到的所有路由,全都映射到同个组件.例如,我们有一个 User 组件,对于所有 ID 各不相同的用户,都要使用这个组件来渲染.能够提供参数的路由即为动态路由第一步:定义组件 c ...
- django调用py报错 django.core.exceptions.ImproperlyConfigured: Requested setting DEFAULT_INDEX_TABLESPACE, but settings are not configured.
完整报错信息如下 django.core.exceptions.ImproperlyConfigured: Requested setting DEFAULT_INDEX_TABLESPACE, bu ...
- js parseInt函数
在代码中,用到数字的地方,如果是字符串,需要将字符串转化为数字型. 1.使用parseInt(string,radix),将整数类型的字符串变为整型,radix表示以什么样的基数来解析字符串,通常是1 ...
- spring mvc ajax异步文件的上传和普通文件上传
表单提交方式文件上传和ajax异步文件上传 一:首先是我在spring mvc下的表单提交方式上传 ssm的包配置我就不一一详细列出来了,但是上传的包我还是列出来 这一段我也不知道怎么给大家讲解就是直 ...