OC数据结构01:链表的探索

张建 lol

数据结构

顺序存储结构

  • 举个例子,数组:1-2-3-4-5-6-7-8-9-10,这个就是一个顺序存储结构,存储是按顺序的。
  • 比如 栈,先进后出,比如 hello world 在栈里面是从 栈底到栈顶的逻辑,依次是 h-e-l-l-o-w-o-r-l-d 这个顺序存储
  • 再比如 队列,先进先出,从头到尾 h-e-l-l-o-w-o-r-l-d 这个顺序排序

链式存储结构-链表

链表是一种 物里存储单元上非连续、非顺序的存储结构,数据元素的顺序是通过链表中的 指针 链接次序实现的。链表由 一系列节点组成,在 运行时动态生成。每个节点包括两部分:一个是 数据域,一个是 指针域

链表

链表的组成

  1. 链表的数据元素的组成部分:指针域数据域
  2. 指针域 用来存放指示数据元素之间的逻辑关系的指针。
  3. 数据域 用来存放数据信息。
  4. 数据元素这种特殊的存储方式称之为 结点(Node)

链表的分类

链表分为4类:

  • 单链表:一个数据域data、一个后继指针域next。也即:上一个节点指向下一个节点,尾节点next指向nil,首节点pre指向nil。

  • 双向链表:一个数据域data、一个前驱指针域previous、一个后继指针域next。也即:上一个节点和下一个节点互相指向,尾节点next指向nil,首节点pre指向nil。

  • 循环链表:一个数据域data、一个后继指针域next。也即:上一个节点指向下一个节点,尾节点next指向首节点。

  • 双向循环链表:一个数据域data、一个前驱指针域previous、一个后继指针域next。也即:上一个节点和下一个节点互相指向,尾节点和首节点也互相指向。

链表的优缺点 面试重点

  1. 数组:

我们知道,用数组存放数据时,必须事先定义固定的长度(即元素个数)。如果事先难以确定元素个数,则必须把数组定义的足够大,以便存放,显然这样会 浪费内存

  1. 而链表可 根据需要开辟内存单元,不会浪费内存

数组 和 链表 的区别?面试重点

  • 数组:数组 静态分配 内存;数组元素在 内存上是连续 的,可以通过 下标查找元素;插入、删除需要移动大量元素,比较使用元素很少变化的情况;数组插入删除操作时间复杂度是 O(n),数组查询操作时间复杂度是 O(1)

  • 链表:链表 动态分配 内存;链表元素在 内存上是不连续的,查找慢;插入、删除只需要对元素指针重新赋值,效率高;链表插入删除操作时间复杂度是 O(1),链表查询操作时间复杂度是 O(n)

如何检测单链表中是否有环? 面试重点

  • 穷举遍历

首先从头节点开始,依次遍历每个节点,每遍历到一个新节点,就从头节点重新遍历新节点之前的所有节点,当 新节点的ID此节点之前的所有节点ID 依次比较,如果发现 ID相同,则证明链表有环。

1
2
外层循环:保证一个新节点ID
内层循环:从头节点遍历到新节点ID之前,如果发现 ID相同,证明链表有环
  • 哈希表缓存

首先创建一个以 节点ID为键HashSet集合,用来 存储曾经遍历过的节点。然后同样是从头节点开始,依次遍历每一个节点,当新节点和HashSet集合当中存储的节点ID相同,则说明链表右环。

1
2
外层循环:HashSet集合存储曾经遍历的节点ID
内层循环:从头节点开始,如果遍历到最新的节点,ID与存储在HashSet集合中存储的节点ID相同,则证 明有环
  • 快慢指针

首先创建两个指针,指针1和指针2,同时指向这个头节点,指针1每次向下移动一个节点,指针2向下移动2个节点,比较节点是否相同,如果相同则说明链表有环。如果不同执行下一次循环。

单向链表代码实现

  1. 定义节点
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 单链表节点
@interface SingleLinkNode : NSObject
@property (nonatomic,strong)id data; // 数据域
@property (nonatomic,strong,nullable)SingleLinkNode * next; // 后继指针域
+ (instancetype)constructNodeWithData:(id)data;
@end

@interface SingleLinkNode ()
@end
@implementation SingleLinkNode
+ (instancetype)constructNodeWithData:(id)data{
SingleLinkNode * node = [[SingleLinkNode alloc] init];
node.data = data;
node.next = nil;
return node;
}
  1. 构建链表
1
2
// 构建一个单链表
SingleLinkNode * headNode = [[SingleLinkNode alloc] init];
  1. 对外接口类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@interface LinkInterface : NSObject
// 单链表:在头部插入节点
+ (void)insertNewNodeToHead:(SingleLinkNode *)newNode headNode:(SingleLinkNode *)headNode;
// 单链表:在尾部插入节点
+ (void)insertNewNodeToTail:(SingleLinkNode *)newNode headNode:(SingleLinkNode *)headNode;
// 单链表:在指定位置插入节点
+ (void)insertNodeAtIndex:(int)index node:(SingleLinkNode *)newNode headNode:(SingleLinkNode *)headNode;
// 单链表:删除指定位置节点
+ (void)deleteNodeAtIndex:(int)index headNode:(SingleLinkNode *)headNode;
// 单链表:查询指定位置节点
+ (SingleLinkNode *)queryNodeAtIndex:(int)index headNode:(SingleLinkNode *)headNode;
// 单链表:正序遍历链表
+ (NSArray *)printFromHeadWithNode:(SingleLinkNode *)headNode printPrefixText:(NSString *)text;
// 单链表:倒叙遍历链表
+ (NSMutableArray *)printFromTailWithNode:(SingleLinkNode *)headNode;
// 单链表:反转链表
+ (SingleLinkNode *)reverseWithNode:(SingleLinkNode *)headNode;
// 单链表:两个有序链表合并成一个新的有序链表
+ (SingleLinkNode *)combineWithNode:(SingleLinkNode *)headNode otherNode:(SingleLinkNode *)otherNode;
// 单链表:判断两个链表是否相交
+ (BOOL)intersectWithNode:(SingleLinkNode *)headNode otherNode:(SingleLinkNode *)otherNode;
// 单链表:判断链表是否构成环,如果成环,求出环的入口节点
+ (SingleLinkNode *)circleWithNode:(SingleLinkNode *)headNode;
@end
  1. 插入节点
  • 在头部插入节点
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 在头部插入节点
+ (void)insertNewNodeToHead:(SingleLinkNode *)newNode headNode:(SingleLinkNode *)headNode{
// 判空处理
if (!headNode){
return;
}
// 先把新节点指向头节点的下一个节点,再让头结点指向新节点(比较常用)
if (headNode.next == nil) {
headNode.next = newNode;
}else {
// 将下一个节点赋值给新节点
newNode.next = headNode.next;
// 再将头节点指向新节点
headNode.next = newNode;
}
}

vc实现:

1
2
3
4
5
// 插入节点到头部
SingleLinkNode * newHeadNode = [SingleLinkNode constructNodeWithData:@1];
[LinkInterface insertNewNodeToHead:newHeadNode headNode:headNode];
// 正序打印节点
[LinkInterface printFromHeadWithNode:headNode printPrefixText:@"构造单链表为:"];

打印结果:

1
2022-11-23 16:44:46.140163+0800 单链表[39792:20769651] 单链表为:1
  • 在尾部插入节点
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 在尾部插入节点
+ (void)insertNewNodeToTail:(SingleLinkNode *)newNode headNode:(SingleLinkNode *)headNode{
// 判空处理
if(!headNode){
return;
}
// 如果头节点就是尾节点
if(headNode.next == nil) {
headNode.next = newNode;
}else {
// 设置中间变量
SingleLinkNode * pNode = headNode;
while (pNode.next != nil) { // 未遍历到尾节点
pNode = pNode.next;
}
pNode.next = newNode;
}
}

vc实现:

1
2
3
4
5
6
7
8
9
// 插入节点到尾部
SingleLinkNode * newTailNode = [SingleLinkNode constructNodeWithData:@2];
SingleLinkNode * newTailNode1 = [SingleLinkNode constructNodeWithData:@3];
SingleLinkNode * newTailNode2 = [SingleLinkNode constructNodeWithData:@5];
[LinkInterface insertNewNodeToTail:newTailNode headNode:headNode];
[LinkInterface insertNewNodeToTail:newTailNode1 headNode:headNode];
[LinkInterface insertNewNodeToTail:newTailNode2 headNode:headNode];
// 正序打印节点
[LinkInterface printFromHeadWithNode:headNode printPrefixText:@"单链表为"];

打印结果:

1
2022-11-23 16:46:42.287876+0800 单链表[39960:20772937] 单链表为:1->2->3->5
  • 在指定位置插入
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 单链表:在指定位置插入节点
+ (void)insertNodeAtIndex:(int)index node:(SingleLinkNode *)newNode headNode:(SingleLinkNode *)headNode{
// 判空处理
if(!headNode){
return;
}
// 如果头节点即尾节点
if (headNode.next == nil){
headNode.next = newNode;
}else {
SingleLinkNode * pNode = headNode;
int i = 1;
while (i < index && pNode.next != nil) {
pNode = pNode.next;
i ++;
}
newNode.next = pNode.next;
pNode.next = newNode;
}

}

vc实现:

1
2
3
4
5
// 插入指定位置节点
SingleLinkNode * newIndexNode = [SingleLinkNode constructNodeWithData:@4];
[LinkInterface insertNodeAtIndex:4 node:newIndexNode headNode:headNode];
// 正序打印节点
[LinkInterface printFromHeadWithNode:headNode printPrefixText:@"单链表为"];

打印结果:

1
2022-11-23 16:47:38.507939+0800 单链表[40048:20774861] 构造单链表为::1->2->3->4->5
  1. 删除节点
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 单链表:删除指定位置节点
+ (void)deleteNodeAtIndex:(int)index headNode:(SingleLinkNode *)headNode{
// 判空处理
if(headNode == nil || !headNode.next || index <= 0){
NSLog(@"%@",[NSString stringWithFormat:@"没有要删除的第%d个节点",index]);
return;
}

SingleLinkNode * pNode = headNode;
SingleLinkNode * p = pNode; // 移动指针
int i = 0;
while (i < index && pNode.next != nil) {
p = pNode;
pNode = pNode.next;
i ++;
}
if(pNode != nil){
p.next = p.next.next;
return;
}
NSLog(@"%@",[NSString stringWithFormat:@"没有要删除的第%d个节点",index]);
}

vc实现:

1
2
3
4
// 删除指定位置的节点
[LinkInterface deleteNodeAtIndex:1 headNode:headNode];
// 正序打印节点
[LinkInterface printFromHeadWithNode:headNode printPrefixText:@"单链表为"];

打印结果:

1
2022-11-23 16:50:48.638460+0800 单链表[40345:20779532] 单链表为:2->3->4->5
  1. 查询节点
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 单链表:查询指定位置节点
+ (SingleLinkNode *)queryNodeAtIndex:(int)index headNode:(SingleLinkNode *)headNode{
// 判空处理
if (!headNode || !headNode.next) {
NSLog(@"%@",[NSString stringWithFormat:@"没有查询到的第%d个节点",index]);
return nil;
}
SingleLinkNode * pNode = headNode.next;
int i = 1;
while (i < index && pNode != nil) {
pNode = pNode.next;
i ++;
}
if(pNode != nil){
return pNode;
}
NSLog(@"%@",[NSString stringWithFormat:@"没有查询到的第%d个节点",index]);
return nil;
}

vc实现:

1
2
3
4
// 查询指定位置的节点
[LinkInterface queryNodeAtIndex:3 headNode:headNode];
// 正序打印节点
[LinkInterface printFromHeadWithNode:headNode printPrefixText:@"单链表为"];

打印结果:

1
2022-11-23 16:55:10.563221+0800 单链表[40694:20785389] 单链表为:2->3->4->5
  1. 遍历链表
  • 正向遍历
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 正序遍历链表
+ (NSArray *)printFromHeadWithNode:(SingleLinkNode *)headNode printPrefixText:(NSString *)text{
// 判空处理
if (!headNode || !headNode.next) {
return nil;
}

// 设置偏移指针
SingleLinkNode * pNode = headNode.next;
NSMutableArray * dataArr = [NSMutableArray array];
while (pNode != nil) {
[dataArr addObject:pNode.data];
pNode = pNode.next; // 指向下一个节点
}
NSLog(@"%@:%@",text,[dataArr componentsJoinedByString:@"->"]);
return dataArr;
}

vc实现:

1
2
// 正序打印节点
[LinkInterface printFromHeadWithNode:headNode printPrefixText:@"单链表为"];

打印结果:

1
2022-11-23 16:55:10.563221+0800 单链表[40694:20785389] 单链表为:2->3->4->5
  • 反向遍历
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 单链表:倒叙遍历链表
+ (NSMutableArray *)printFromTailWithNode:(SingleLinkNode *)headNode{
// 判空处理
if(!headNode || !headNode.next){
return nil;
}

// 遍历指针偏移,每次遍历完一次后,要记录最后一个节点,然后将遍历指针移动到开头重新开始,与记录的最后一个节点作比较
NSMutableArray * items = [NSMutableArray array];
SingleLinkNode * pNode = headNode;
SingleLinkNode * lastNode = nil;
while (pNode != nil && lastNode != pNode) {
pNode = pNode.next;
if (pNode.next == nil || pNode.next == lastNode) {
lastNode = pNode;
pNode = headNode;
[items addObject:lastNode.data];
}
}
return items;
}

vc实现:

1
2
3
// 倒叙打印节点
NSMutableArray * tailArr = [LinkInterface printFromTailWithNode:headNode];
NSLog(@"tail:%@",tailArr);

打印结果:

1
2
3
4
5
6
2022-11-23 17:00:09.521947+0800 单链表[41100:20791055] tail:(
5,
4,
3,
2
)
  1. 反转链表
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// 单链表:反转链表
+ (SingleLinkNode *)reverseWithNode:(SingleLinkNode *)headNode{
// 判空处理
if(!headNode|| !headNode.next){
return nil;
}

// 采用头节点插入的方式反转
// 定义遍历指针
SingleLinkNode * p = headNode.next;
// 定义反转后头节点
SingleLinkNode * newHead = [[SingleLinkNode alloc] init];
while (p != nil) {
// 记录下一个节点用来往下循环
SingleLinkNode * temp = p.next;

// 替换当前节点的next为新头next
p.next = newHead.next;
// 更新新头节点指向当前节点即可反转
newHead.next = p;

// 移动p指针
p = temp;
}
return newHead;
}

vc实现:

1
2
// 反转链表
SingleLinkNode * reverseNode = [LinkInterface reverseWithNode:headNode];
  1. 合并有序链表(有问题,排序不对)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
// 两个有序链表合并成一个新的有序链表
+ (SingleLinkNode *)combineWithNode:(SingleLinkNode *)headNode otherNode:(SingleLinkNode *)otherNode{
// 判空处理
if(!headNode || !headNode.next){
return otherNode;
}
if(!otherNode || !otherNode.next){
return headNode;
}
// 一起遍历
SingleLinkNode * p1 = headNode.next;
SingleLinkNode * p2 = otherNode.next;
// 定义一个新头节点
SingleLinkNode * newHead = [[SingleLinkNode alloc] init];
while (p1 != nil && p2 != nil) {
if([p1.data integerValue] > [p2.data integerValue]){
// 移动otherNode节点指向otherNode当前节点的下一个节点
otherNode.next = p2.next;
// 将当前otherNode节点链表断掉
p2.next = nil;
// 将当前otherNode节点插入到新节点newHead链表的尾部
[self insertNewNodeToTail:p2 headNode:newHead];
// 获取otherNode链表的下一个节点
p2 = otherNode.next;
}else {
headNode.next = p1.next;
p1.next = nil;
[self insertNewNodeToTail:p1 headNode:newHead];
p1 = headNode.next;
}
}

// 处理没扫描结束的链表
while (p1 != nil) {
headNode.next = p1.next;
p1.next = nil;
[self insertNewNodeToTail:p1 headNode:newHead];
p1 = headNode.next;
}

while (p2 != nil) {
otherNode.next = p2.next;
p2.next = nil;
[self insertNewNodeToTail:p2 headNode:newHead];
p2 = otherNode.next;
}

return newHead;
}
  1. 判断两个链表是否相交
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
// 单链表:判断两个链表是否相交
+ (BOOL)intersectWithNode:(SingleLinkNode *)headNode otherNode:(SingleLinkNode *)otherNode{
// 判空处理
if(!headNode || !headNode.next || !otherNode || !otherNode.next){
return NO;
}
// 思路:分别获取两个链表的长度,判断谁的链表更长,链表更长的先走完相差的步数,然后再齐步走
SingleLinkNode * p1 = headNode.next;
SingleLinkNode * p2 = otherNode.next;

int L1 = 1;
int L2 = 1;
while (p1 != nil) {
L1 ++;
p1 = p1.next;
}
while (p2 != nil) {
L2 ++;
p2 = p2.next;
}

p1 = headNode.next; // 将p1遍历指针移动到首节点
p2 = headNode.next; // 将p2遍历指针移动到首节点

int i = 0;
if (L1 > L2) {
while (i < L1 - L2 && p1 != nil) { // p1先走
p1 = p1.next;
i ++;
}
}else {
while (i < L2 - L1 && p2 != nil) { // p2先走
p2 = p2.next;
i ++;
}
}

// p1、p2齐步走
if(i == ABS(L1 - L2)){
while (p1 != nil && p2 != nil) {
if(p1.next == p2.next) return YES;
p1 = p1.next;
p2 = p2.next;
}
}

return NO;
}
  1. 判断链表是否头程还,如果成环,求出环的入口节点
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// 单链表:判断链表是否构成环,如果成环,求出环的入口节点
+ (SingleLinkNode *)circleWithNode:(SingleLinkNode *)headNode{
// 判空处理
if(!headNode || !headNode.next){
return nil;
}
// 思路:采用快慢指针
// 快指针先走两步,满指针走一步,如果成环,必然重合。
// 走到第一次重合的地点后,重新设置一个指针p指向头节点,并与慢节点同步伐齐步走
// 走到第二次相遇的地方,即为构成环的节点
SingleLinkNode * quick = headNode.next;
SingleLinkNode * slow = headNode.next;
SingleLinkNode * p = headNode.next;
while (quick != nil && slow != nil) {
quick = quick.next.next;
slow = slow.next;
if (quick == slow) { // 第一次重合,结束循环
break;
}
}
while (p != nil && slow != nil) {
p = p.next;
slow = slow.next;
if (p == slow) { // 第二次重合,找到成环的入口节点
return p;
}
}
return nil;
}

双向链表

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

  1. 定义节点
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@interface DoubleLinkNode : NSObject
@property (nonatomic,strong)id data; // 数据域
@property (nonatomic,weak,nullable)DoubleLinkNode * pre; // 前驱指针域(防止循环引用)
@property (nonatomic,strong,nullable)DoubleLinkNode * next; // 后继指针域
+ (instancetype)constructNodeWithData:(id)data;
@end

@implementation DoubleLinkNode
+ (instancetype)constructNodeWithData:(id)data{
DoubleLinkNode * node = [[DoubleLinkNode alloc] init];
node.data = data;
node.pre = nil;
node.next = nil;
return node;
}
@end
  1. 构建一个双向链表
1
2
3
4
5
6
7
8
9
// 构造一个双向链表
DoubleLinkNode * head = [[DoubleLinkNode alloc] init];
DoubleLinkNode * node1 = [DoubleLinkNode constructNodeWithData:@1];
DoubleLinkNode * node2 = [DoubleLinkNode constructNodeWithData:@2];
head.next = node1;
node1.pre = head;
node1.next = node2;
node2.pre = node1;
[LinkInterface printDoubleFromHeadWithNode:head printPrefixText:@"双链表为"];

打印结果:

1
2022-11-24 13:38:50.045234+0800 单链表[50291:20937675] 双链表为:1⇄2
  1. 在头部插入节点
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 双向链表:向头部插入节点
+ (void)insertDoubleNewNodeToHead:(DoubleLinkNode *)newNode headNode:(DoubleLinkNode *)headNode{
// 判空处理
if(!headNode){
return;
}
// 如果只有一个头节点
if(headNode.next == nil){
headNode.next = newNode;
newNode.pre = headNode;
}else {
newNode.next = headNode.next; // 当前节点的后继指向头节点的后继
headNode.next.pre = newNode; // 头结点后继的前驱指向当前节点

newNode.pre = headNode; // 当前节点的前驱指向头结点
headNode.next = newNode; // 头结点的后继指向当前节点
}
}

vc实现

1
2
3
4
// 在头部插入节点
DoubleLinkNode * node0 = [DoubleLinkNode constructNodeWithData:@0];
[LinkInterface insertDoubleNewNodeToHead:node0 headNode:head];
[LinkInterface printDoubleFromHeadWithNode:head printPrefixText:@"双链表为"];

打印结果:

1
2022-11-24 13:53:01.240605+0800 单链表[51484:20953802] 双链表为:0⇄1⇄2
  1. 在尾部插入节点
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 双向链表:向尾部插入节点
+ (void)insertDoubleNewNodeToTail:(DoubleLinkNode *)newNode headNode:(DoubleLinkNode *)headNode{
// 判空处理
if(!headNode){
return;
}
// 设置偏移指针
DoubleLinkNode * pNode = headNode.next;
while (pNode.next != nil) {
pNode = pNode.next;
}
pNode.next = newNode;
newNode.pre = pNode;
}

vc实现

1
2
3
4
// 在尾部插入节点
DoubleLinkNode * node4 = [DoubleLinkNode constructNodeWithData:@4];
[LinkInterface insertDoubleNewNodeToTail:node4 headNode:head];
[LinkInterface printDoubleFromHeadWithNode:head printPrefixText:@"双向链表为"];

打印结果

1
2022-11-24 13:59:04.853558+0800 单链表[52038:20962187] 双向链表为:0⇄1⇄2⇄4
  1. 在指定位置插入节点
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// 双向链表:在指定位置插入节点
+(void)insertDoubleNewNodeToIndex:(int)index newNode:(DoubleLinkNode *)newNode headNode:(DoubleLinkNode *)headNode{
if(!headNode){
return;
}
// 如果头结点即尾节点
if (headNode.next == nil){
headNode.next = newNode;
newNode.pre = headNode;
}else {

}
// 如果头节点即尾节点
if (headNode.next == nil){
headNode.next = newNode;
}else {
// 设置偏移指针
DoubleLinkNode * pNode = headNode.next;
int i = 1;
while (i < index && pNode.next != nil) {
pNode = pNode.next;
i ++;
}
newNode.next = pNode.next;
pNode.next.pre = newNode;
newNode.pre = pNode;
pNode.next = newNode;
}
}

vc实现

1
2
3
4
// 在指定位置插入节点
DoubleLinkNode * node3 = [DoubleLinkNode constructNodeWithData:@3];
[LinkInterface insertDoubleNewNodeToIndex:3 newNode:node3 headNode:head];
[LinkInterface printDoubleFromHeadWithNode:head printPrefixText:@"双向链表为"];

打印结果

1
2022-11-24 14:08:41.539116+0800 单链表[52850:20973592] 双向链表为:0⇄1⇄2⇄3⇄4
  1. 删除指定位置节点
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 双向链表:删除指定位置节点
+ (DoubleLinkNode *)deleteDoubleNodeAtIndex:(int)index headNode:(DoubleLinkNode *)headNode{
// 判空处理
if(!headNode){
return nil;
}
// 设置偏移指针
DoubleLinkNode * pNode = headNode.next;
int i = 1;
while (i < index && pNode.next != nil) {
pNode = pNode.next;
i ++;
}
if(i == index){
pNode.pre.next = pNode.next;
pNode.next.pre = pNode.pre;
return pNode;
}
return nil;
}

vc实现

1
2
3
// 删除指定位置节点
[LinkInterface deleteDoubleNodeAtIndex:1 headNode:head];
[LinkInterface printDoubleFromHeadWithNode:head printPrefixText:@"双向链表为"];

打印结果

1
2022-11-24 14:15:01.766124+0800 单链表[53365:20980542] 双向链表为:1⇄2⇄3⇄4
  1. 遍历并打印链表
// 双向链表:遍历并打印链表
+ (void)printDoubleFromHeadWithNode:(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:@"⇄"]);
}
  • Post title:OC数据结构01:链表的探索
  • Post author:张建
  • Create time:2020-08-09 22:39:22
  • Post link:https://redefine.ohevan.com/2020/08/09/OC数据结构和算法/OC数据结构01:链表的探索/
  • Copyright Notice:All articles in this blog are licensed under BY-NC-SA unless stating additionally.