用OC实现双向链表:构造链表、插入节点、删除节点、遍历节点

一、介绍

双向链表:每一个节点前后指针域都和它的上一个节点互相指向,尾节点的next指向空,首节点的pre指向空。

二、使用

注:跟单链表差不多,简单写常用的。循环链表无法形象化打印,后面也暂不实现了,但是要注意循环链表遍历时结束的标志。

循环链表遍历结束:tailNode.next == firstNode

双向循环链表遍历结束:tailNode.next == firstNode  && firstNode.pre == tailNode

***定义双向节点***

//  DoubleLinkNode.h
//  LinkListDemo
//  Created by 夏远全 on 2019/9/24.
#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface DoubleLinkNode : NSObject
@property (nonatomic, assign) int data; //数据域
@property (nonatomic,   weak, nullable) DoubleLinkNode *pre; //前驱指针域(防止循环引用)
@property (nonatomic, strong, nullable) DoubleLinkNode *next;//后继指针域
+(instancetype)constructNodeWithData:(int)data;
@end 
//  DoubleLinkNode.m
//  LinkListDemo
//  Created by 夏远全 on 2019/9/24.
#import "DoubleLinkNode.h"

@implementation DoubleLinkNode

+(instancetype)constructNodeWithData:(int)data {
    
    DoubleLinkNode *node = [[DoubleLinkNode alloc] init];
    node.data = data;
    node.next = nil;
    node.pre = nil;
    return node;
}
@end

 1、构造双向循环链表

//1、构建一个双向链表
DoubleLinkNode *head = [[DoubleLinkNode alloc] init];
DoubleLinkNode *node1 = [DoubleLinkNode constructNodeWithData:1];
DoubleLinkNode *node2 = [DoubleLinkNode constructNodeWithData:2];
DoubleLinkNode *node3 = [DoubleLinkNode constructNodeWithData:3];
head.next = node1;
node1.next = node2;
node1.pre = head;
node2.next = node3;
node2.pre = node1;
node3.pre = node2;
[FuncontionHandler printFromHeadWithNode:head printPrefixText:@"构造双向链表为"];
2019-09-27 16:12:43.449741+0800 LinkList[39956:2129540] 构造双向链表为:123

 

2、插入节点

2-1:在头部插入节点

//双向链表:在头部插入节点
+(void)insetNodeAfterHead:(DoubleLinkNode *)newNode headNode:(DoubleLinkNode *)headNode {
    
    //判空处理
    if (!headNode) {
        return;
    }
    
    if (headNode.next == nil) {
        headNode.next = newNode;
        newNode.pre = headNode;
    }
    else{
        newNode.next = headNode.next; //当前节点后继指向的头结点后继
        newNode.pre = headNode;       //当前节点的前驱指向头结点
        headNode.next.pre = newNode;  //头结点的后继结点的前驱指向当前节点
        headNode.next = newNode;      //头结点的后继指向当前节点
    }
}
//从头部插入
DoubleLinkNode *node4 = [DoubleLinkNode constructNodeWithData:4];
[FuncontionHandler insetNodeAfterHead:node4 headNode:head];
[FuncontionHandler printFromHeadWithNode:head printPrefixText:@"在双向链表头部插入节点4后"];
2019-09-27 16:12:43.449741+0800 LinkList[39956:2129540] 构造双向链表为:123
2019-09-27 16:12:43.450118+0800 LinkList[39956:2129540] 在双向链表头部插入节点4后:4123

2-2:在尾部插入节点

//双向链表:在尾部插入节点
+(void)insetNodeAfterTail:(DoubleLinkNode *)newNode headNode:(DoubleLinkNode *)headNode {
    
    //判空处理
    if (!headNode) {
        return;
    }
    
    //设置偏移指针
    DoubleLinkNode *pNode = headNode;
    while (pNode.next != nil) {
        pNode = pNode.next;
    }
    pNode.next = newNode;
    newNode.pre = pNode;
}
//从尾部插入
DoubleLinkNode *node5 = [DoubleLinkNode constructNodeWithData:5];
[FuncontionHandler insetNodeAfterTail:node5 headNode:head];
[FuncontionHandler printFromHeadWithNode:head printPrefixText:@"在双向链表尾部插入节点5后"];
2019-09-27 16:12:43.449741+0800 LinkList[39956:2129540] 构造双向链表为:123
2019-09-27 16:12:43.450118+0800 LinkList[39956:2129540] 在双向链表头部插入节点4后:4123
2019-09-27 16:12:43.450209+0800 LinkList[39956:2129540] 在双向链表尾部插入节点5后:41235

2-3:在指定位置插入节点

//双向链表:在指定位置插入节点
+(void)insetNodeAtIndex:(int)k node:(DoubleLinkNode *)newNode headNode:(DoubleLinkNode *)headNode {
    
    //判空处理
    if (!headNode) {
        return;
    }
    
    //设置偏移指针
    DoubleLinkNode *pNode = headNode;
    int i = 1;
    while (pNode!= nil && i<k) {
        pNode = pNode.next;
        i++;
    }
    if (i==k) {
        //与从头结点插入的方式是一样的方法
        newNode.next = pNode.next;
        newNode.pre = pNode;
        pNode.next.pre = newNode;
        pNode.next = newNode;
    }
}
//从指定位置插入
DoubleLinkNode *node6 = [DoubleLinkNode constructNodeWithData:6];
[FuncontionHandler insetNodeAtIndex:2 node:node6 headNode:head];
[FuncontionHandler printFromHeadWithNode:head printPrefixText:@"在双向链表第2个位置插入节点6后"];
2019-09-27 16:12:43.449741+0800 LinkList[39956:2129540] 构造双向链表为:123
2019-09-27 16:12:43.450118+0800 LinkList[39956:2129540] 在双向链表头部插入节点4后:4123
2019-09-27 16:12:43.450209+0800 LinkList[39956:2129540] 在双向链表尾部插入节点5后:41235
2019-09-27 16:12:43.450262+0800 LinkList[39956:2129540] 在双向链表第2个位置插入节点6后:461235

 

3、删除节点

//双向链表:删除第k个位置的节点
+(DoubleLinkNode *)deleteNodeAtIndex:(int)k headNode:(DoubleLinkNode *)headNode {
    
    //判空处理
    if (!headNode) {
        return nil;
    }
    
    //设置偏移指针
    DoubleLinkNode *pNode = headNode.next;
    int i = 1;
    while (pNode!= nil && i<k) {
        pNode = pNode.next;
        i++;
    }
    if (i==k) {
        pNode.pre.next = pNode.next; //当前节点的前驱节点的后继指向当前节点的后继结点
        pNode.next.pre = pNode.pre;  //当前节点的后继结点的前驱指向当前节点的前驱节点
        return pNode;
    }
    return nil;
}
//3、删除节点
DoubleLinkNode *deleteNode = [FuncontionHandler deleteNodeAtIndex:2 headNode:head];
NSString *prefixText = [NSString stringWithFormat:@"删除第2个位置的节点%d后单链表为",deleteNode.data];
[FuncontionHandler printFromHeadWithNode:head printPrefixText:prefixText];
2019-09-27 16:12:43.449741+0800 LinkList[39956:2129540] 构造双向链表为:123
2019-09-27 16:12:43.450118+0800 LinkList[39956:2129540] 在双向链表头部插入节点4后:4123
2019-09-27 16:12:43.450209+0800 LinkList[39956:2129540] 在双向链表尾部插入节点5后:41235
2019-09-27 16:12:43.450262+0800 LinkList[39956:2129540] 在双向链表第2个位置插入节点6后:461235
2019-09-27 16:12:43.450336+0800 LinkList[39956:2129540] 删除第2个位置的节点6后单链表为:41235

 

4、遍历双向循环链表

//双向链表:遍历并打印链表
+(void)printFromHeadWithNode:(DoubleLinkNode *)headNode printPrefixText:(NSString *)text {
    
    //判空处理
    if (!headNode) {
        return;
    }
    
    DoubleLinkNode *pNode = headNode.next;
    NSMutableArray *items = [NSMutableArray array];
    while (pNode!= nil) {
        [items addObject:@(pNode.data)];
        pNode = pNode.next;
    }
    NSLog(@"%@:%@",text,[items componentsJoinedByString:@""]);
}

 

三、源码

FuncontionHandler.h

//
//  FuncontionHandler.h
//  LinkList
//
//  Created by 夏远全 on 2019/9/27.
//

#import <Foundation/Foundation.h>
#import "DoubleLinkNode.h"

NS_ASSUME_NONNULL_BEGIN

@interface FuncontionHandler : NSObject

//双向链表:在头部插入节点
+(void)insetNodeAfterHead:(DoubleLinkNode *)newNode headNode:(DoubleLinkNode *)headNode;

//双向链表:在尾部插入节点
+(void)insetNodeAfterTail:(DoubleLinkNode *)newNode headNode:(DoubleLinkNode *)headNode;

//双向链表:在指定位置插入节点
+(void)insetNodeAtIndex:(int)k node:(DoubleLinkNode *)newNode headNode:(DoubleLinkNode *)headNode;

//双向链表:删除第k个位置的节点
+(DoubleLinkNode *)deleteNodeAtIndex:(int)k headNode:(DoubleLinkNode *)headNode;

//双向链表:遍历并打印链表
+(void)printFromHeadWithNode:(DoubleLinkNode *)headNode printPrefixText:(NSString *)text;

@end

NS_ASSUME_NONNULL_END
View Code

FuncontionHandler.m

//
//  FuncontionHandler.m
//  LinkList
//
//  Created by 夏远全 on 2019/9/27.
//

#import "FuncontionHandler.h"

@implementation FuncontionHandler

//双向链表:在头部插入节点
+(void)insetNodeAfterHead:(DoubleLinkNode *)newNode headNode:(DoubleLinkNode *)headNode {
    
    //判空处理
    if (!headNode) {
        return;
    }
    
    if (headNode.next == nil) {
        headNode.next = newNode;
        newNode.pre = headNode;
    }
    else{
        newNode.next = headNode.next; //当前节点后继指向的头结点后继
        newNode.pre = headNode;       //当前节点的前驱指向头结点
        headNode.next.pre = newNode;  //头结点的后继结点的前驱指向当前节点
        headNode.next = newNode;      //头结点的后继指向当前节点
    }
}

//双向链表:在尾部插入节点
+(void)insetNodeAfterTail:(DoubleLinkNode *)newNode headNode:(DoubleLinkNode *)headNode {
    
    //判空处理
    if (!headNode) {
        return;
    }
    
    //设置偏移指针
    DoubleLinkNode *pNode = headNode;
    while (pNode.next != nil) {
        pNode = pNode.next;
    }
    pNode.next = newNode;
    newNode.pre = pNode;
}

//双向链表:在指定位置插入节点
+(void)insetNodeAtIndex:(int)k node:(DoubleLinkNode *)newNode headNode:(DoubleLinkNode *)headNode {
    
    //判空处理
    if (!headNode) {
        return;
    }
    
    //设置偏移指针
    DoubleLinkNode *pNode = headNode;
    int i = 1;
    while (pNode!= nil && i<k) {
        pNode = pNode.next;
        i++;
    }
    if (i==k) {
        //与从头结点插入的方式是一样的方法
        newNode.next = pNode.next;
        newNode.pre = pNode;
        pNode.next.pre = newNode;
        pNode.next = newNode;
    }
    
}

//双向链表:删除第k个位置的节点
+(DoubleLinkNode *)deleteNodeAtIndex:(int)k headNode:(DoubleLinkNode *)headNode {
    
    //判空处理
    if (!headNode) {
        return nil;
    }
    
    //设置偏移指针
    DoubleLinkNode *pNode = headNode.next;
    int i = 1;
    while (pNode!= nil && i<k) {
        pNode = pNode.next;
        i++;
    }
    if (i==k) {
        pNode.pre.next = pNode.next; //当前节点的前驱节点的后继指向当前节点的后继结点
        pNode.next.pre = pNode.pre;  //当前节点的后继结点的前驱指向当前节点的前驱节点
        return pNode;
    }
    return nil;
}

//双向链表:遍历并打印链表
+(void)printFromHeadWithNode:(DoubleLinkNode *)headNode printPrefixText:(NSString *)text {
    
    //判空处理
    if (!headNode) {
        return;
    }
    
    DoubleLinkNode *pNode = headNode.next;
    NSMutableArray *items = [NSMutableArray array];
    while (pNode!= nil) {
        [items addObject:@(pNode.data)];
        pNode = pNode.next;
    }
    NSLog(@"%@:%@",text,[items componentsJoinedByString:@""]);
    
}

@end
View Code

main方法

//
//  main.m
//  LinkList
//
//  Created by 夏远全 on 2019/9/25.
//

#import <Foundation/Foundation.h>
#import "FuncontionHandler.h"

void testDoubleLink(void);

int main(int argc, const char * argv[]) {
    @autoreleasepool {
    
        testDoubleLink();

    }
    
    return 0;
}

void testDoubleLink(void){
    
    //1、构建一个双向链表
    DoubleLinkNode *head = [[DoubleLinkNode alloc] init];
    DoubleLinkNode *node1 = [DoubleLinkNode constructNodeWithData:1];
    DoubleLinkNode *node2 = [DoubleLinkNode constructNodeWithData:2];
    DoubleLinkNode *node3 = [DoubleLinkNode constructNodeWithData:3];
    head.next = node1;
    node1.next = node2;
    node1.pre = head;
    node2.next = node3;
    node2.pre = node1;
    node3.pre = node2;
    [FuncontionHandler printFromHeadWithNode:head printPrefixText:@"构造双向链表为"];
    
    //2、从双向链表中插入节点
    DoubleLinkNode *node4 = [DoubleLinkNode constructNodeWithData:4];
    [FuncontionHandler insetNodeAfterHead:node4 headNode:head];
    [FuncontionHandler printFromHeadWithNode:head printPrefixText:@"在双向链表头部插入节点4后"];
 
    DoubleLinkNode *node5 = [DoubleLinkNode constructNodeWithData:5];
    [FuncontionHandler insetNodeAfterTail:node5 headNode:head];
    [FuncontionHandler printFromHeadWithNode:head printPrefixText:@"在双向链表尾部插入节点5后"];
    
    DoubleLinkNode *node6 = [DoubleLinkNode constructNodeWithData:6];
    [FuncontionHandler insetNodeAtIndex:2 node:node6 headNode:head];
    [FuncontionHandler printFromHeadWithNode:head printPrefixText:@"在双向链表第2个位置插入节点6后"];
    
    //3、删除节点
    DoubleLinkNode *deleteNode = [FuncontionHandler deleteNodeAtIndex:2 headNode:head];
    NSString *prefixText = [NSString stringWithFormat:@"删除第2个位置的节点%d后单链表为",deleteNode.data];
    [FuncontionHandler printFromHeadWithNode:head printPrefixText:prefixText];
    
}
View Code

 

posted @ 2019-09-27 16:39  XYQ全哥  阅读(906)  评论(0编辑  收藏  举报