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中双向链表的实现的主要内容,如果未能解决你的问题,请参考以下文章

链表的java实现(单向双向链表,单向链表的反转)

链表的java实现(单向双向链表,单向链表的反转)

双向链表的实现(双向链表与单向链表的简单区别联系和实现)

双向链表的实现(双向链表与单向链表的简单区别联系和实现)

代码模板实现双向链表的去重拼接合并排序

双向链表的实现