用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] 构造双向链表为:1⇄2⇄3
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] 构造双向链表为:1⇄2⇄3 2019-09-27 16:12:43.450118+0800 LinkList[39956:2129540] 在双向链表头部插入节点4后:4⇄1⇄2⇄3
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] 构造双向链表为:1⇄2⇄3 2019-09-27 16:12:43.450118+0800 LinkList[39956:2129540] 在双向链表头部插入节点4后:4⇄1⇄2⇄3 2019-09-27 16:12:43.450209+0800 LinkList[39956:2129540] 在双向链表尾部插入节点5后:4⇄1⇄2⇄3⇄5
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] 构造双向链表为:1⇄2⇄3 2019-09-27 16:12:43.450118+0800 LinkList[39956:2129540] 在双向链表头部插入节点4后:4⇄1⇄2⇄3 2019-09-27 16:12:43.450209+0800 LinkList[39956:2129540] 在双向链表尾部插入节点5后:4⇄1⇄2⇄3⇄5 2019-09-27 16:12:43.450262+0800 LinkList[39956:2129540] 在双向链表第2个位置插入节点6后:4⇄6⇄1⇄2⇄3⇄5
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] 构造双向链表为:1⇄2⇄3 2019-09-27 16:12:43.450118+0800 LinkList[39956:2129540] 在双向链表头部插入节点4后:4⇄1⇄2⇄3 2019-09-27 16:12:43.450209+0800 LinkList[39956:2129540] 在双向链表尾部插入节点5后:4⇄1⇄2⇄3⇄5 2019-09-27 16:12:43.450262+0800 LinkList[39956:2129540] 在双向链表第2个位置插入节点6后:4⇄6⇄1⇄2⇄3⇄5 2019-09-27 16:12:43.450336+0800 LinkList[39956:2129540] 删除第2个位置的节点6后单链表为:4⇄1⇄2⇄3⇄5
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
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
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]; }
程序猿神奇的手,每时每刻,这双手都在改变着世界的交互方式!