用OC实现双向链表:构造链表、插入节点、删除节点、遍历节点
时间:2019-09-27
本文章向大家介绍用OC实现双向链表:构造链表、插入节点、删除节点、遍历节点,主要包括用OC实现双向链表:构造链表、插入节点、删除节点、遍历节点使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
一、介绍
双向链表:每一个节点前后指针域都和它的上一个节点互相指向,尾节点的next指向空,首节点的pre指向空。
二、使用
注:跟单链表差不多,简单写常用的。循环链表无法形象化打印,后面也暂不实现了,但是要注意循环链表遍历时结束的标志:(尾节点.next == 头结点.pre )
***定义双向节点***
// 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]; }
原文地址:https://www.cnblogs.com/XYQ-208910/p/11598851.html
- 【Java学习笔记之三十】详解Java单例(Singleton)模式
- 基于Windows下处理Java错误:编码GBK的不可映射字符的解决方案
- 浅析ASCII、Unicode和UTF-8三种常见字符编码
- 【Java学习笔记之三十一】详解Java8 lambda表达式
- 2017 Multi-University Training Contest - Team 9 1003&&HDU 6163 CSGO【计算几何】
- 【Code】关关的刷题日记21——Leetcode 485. Max Consecutive Ones
- 2017 Multi-University Training Contest - Team 9 1002&&HDU 6162 Ch’s gift【树链部分+线段树】
- 【Java学习笔记之三十二】浅谈Java中throw与throws的用法及异常抛出处理机制剖析
- Linux上访问SQL Server数据库
- 2017 Multi-University Training Contest - Team 9 1001&&HDU 6161 Big binary tree【树形dp+hash】
- 【Java学习笔记之三十三】详解Java中try,catch,finally的用法及分析
- 【Java学习笔记之二十九】Java中的"equals"和"=="的用法及区别
- NET跨平台:在Ubuntu下搭建ASP.NET 5开发环境
- 【Code】关关的刷题日记22——Leetcode 53. Maximum Subarray
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- centos7下NFS使用与配置的步骤
- 基于DOM4J的XML文件解析类
- Win7安装和配置Apache2.4服务器的详细方法
- shiro会话管理示例代码
- Windows Apache2.4 VC9(ApacheHaus)详细安装配置教程
- 在centos 7中安装配置k8s集群的步骤详解
- Centos7.2 编译安装方式搭建 phpMyAdmin
- CentOS 6.5 web服务器apache的安装与基本设置
- Linux本机与服务器文件互传及Linux服务器文件上传下载命令写法
- linux利用read命令获取变量中的值
- 解决Centos7 安装腾达U12无线网卡驱动问题
- CentOS 6.5上编译安装Apache服务器的方法(最小化安装)
- 固定QPS压测模式探索
- Centos6 网络配置的实例详解
- centos6.5升级安装配置supervisor的教程