重温数据结构之链表

  数据结构是用来存放和管理各种数据(比如插入、删除、查找和更新等)的一种程序结构,常见的数据结构有数组、字符串、链表、队列、栈、树、HASH表和图等。
  而算法是指解决一个问题的方法及其实现。算法可以理解为由基本运算及规定的运算顺序所构成的完整的解题步骤。比如各种排序方法,折半查找都是常见的算法。算法的判断标准包括时间复杂度和空间复杂度。

0x01 时间复杂度和空间复杂度

1. 时间复杂度

  算法的时间复杂度是指执行算法所需的计算工作量。一个算法花费的时间与算法中语句的执行次数成正比例,哪个算法中语句执行次数多,它花费时间就多。一个算法中的语句执行次数称为语句频度或时间频度,记为T(n),其中n为问题规模。
  一般情况下,算法中基本操作重复执行的次数是问题规模n的某个函数。如T(n)=4n2+5n,或者8n2+1,那么时间复杂度都为:O(n2),取最高幂,并去掉系数。
  常见的时间复杂度有:常数阶O(1),对数阶O(logn),线性阶O(n),线性对数阶O(nlogn),平方阶O(n2),立方阶O(n3),…,k次方阶O(nk),指数阶O(2n)。随着问题规模n的不断增大,上述时间复杂度不断增大,算法的执行效率越低。
  计算的方法是看看有几重循环,只有一重则时间复杂度为O(n),只有二重则时间复杂度为O(n2),以此类推。如果有二分则为O(logn),二分例如快速排序或二分查找,如果一个for循环套一个二分,那么时间复杂度则为O(nlogn)。

2. 空间复杂度

  算法的空间复杂度是指算法需要消耗的内存空间。其计算和表示方法与时间复杂度类似,一般都用复杂度的渐近性来表示。同时间复杂度相比,空间复杂度的分析要简单的多。程序在运行时候动态分配的空间,以及递归栈所需的空间等。这部分的空间大小与算法有关,而那些静态的空间, 比如代码、常量以及简单的变量与空间复杂度无关。

0x01 单链表

  链表通常由一连串节点组成,每个节点包含任意的实例数据和一个用来指向下一个节点地址的指针(next指针)。
  使用链表结构可以克服数组需要预先知道数据大小的缺点,链表结构可以充分利用计算机内存空间,实现灵活的内存动态管理。但是链表失去了数组随机读取的优点,同时链表由于增加了节点的指针域,空间开销相对比较大。
  链表在插入的时候可以达到O(1)的复杂度,但是在查找一个节点或者访问特定编号的节点需要O(n)的时间。
  单链表源码如下:

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
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
#define ERROR   -1000
#define SUCCESS 1000

#define STATUS int

// 节点结构
typedef struct _node {
int val;
struct _node *next;
}Node;

// 链表结构
typedef struct _nodeList {
int length;
}NodeList;

// 创建一个空链表
NodeList* CreateList() {
NodeList *list = (NodeList *)malloc(sizeof(NodeList));
if(list != NULL) {
list->length = 0;
}
return list;
}

// 销毁一个链表
void DestroyList(NodeList *list) {
if(!list) return;

free(list);
}

// 清空一个链表
void ClearList(NodeList *list) {
if(!list) return;

list->length = 0;
}

// 获取链表长度
int GetListLength(NodeList *list) {
if(!list) return ERROR;
return list->length;
}

// 插入节点
STATUS InsertListNode(NodeList *list, Node *node, int position) {
bool status = list != NULL && node != NULL && position >= 0;
if(!status) return ERROR;

Node *currentNode = (Node *)list;
for (int i = 0; i < position && currentNode->next != NULL; i++) {
currentNode = currentNode->next;
}
node->next = currentNode->next;
currentNode->next = node;
list->length++;

return SUCCESS;
}

// 获取某个位置的节点
Node* GetListNode(NodeList *list, int position) {
bool status = list != NULL && position >= 0;
if(!status) return NULL;

Node *node = NULL;

Node *currentNode = (Node *)list;
for (int i = 0; i < position && currentNode->next != NULL; i++) {
currentNode = currentNode->next;
}
node = currentNode->next;

return node;
}

// 删除某个位置的节点
STATUS DeleteListNode(NodeList *list, int position) {
bool status = list != NULL && position > 0;
if(!status) return ERROR;

Node *currentNode = (Node *)list;
for (int i = 0; i < position && currentNode->next != NULL; i++) {
currentNode = currentNode->next;
}

Node *node = currentNode->next; // 要删除的node
currentNode->next = node->next;

list->length--;

return SUCCESS;
}

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
[super viewDidLoad];

NodeList *list = CreateList();

struct _node n1;
struct _node n2;
struct _node n3;

n1.val = 1;
n2.val = 2;
n3.val = 3;

InsertListNode(list, (Node *)&n1, 0);
InsertListNode(list, (Node *)&n2, 1);
InsertListNode(list, (Node *)&n3, 2);

for (int i = 0; i < GetListLength(list); i++) {
Node *node = GetListNode(list, i);
NSLog(@"位置:%d的值:%d", i, node->val);
}

DeleteListNode(list, 1);
NSLog(@"**删除后的链表**\n");

for (int i = 0; i < GetListLength(list); i++) {
Node *node = GetListNode(list, i);
NSLog(@"位置:%d的值:%d", i, node->val);
}

DestroyList(list);
}


@end

// 运行结果:
2018-04-23 16:08:08.572926+0800 testData[34765:133946832] 位置:0的值:1
2018-04-23 16:08:08.573132+0800 testData[34765:133946832] 位置:1的值:2
2018-04-23 16:08:08.575485+0800 testData[34765:133946832] 位置:2的值:3
2018-04-23 16:08:08.575660+0800 testData[34765:133946832] **删除后的链表**

2018-04-23 16:08:08.575789+0800 testData[34765:133946832] 位置:0的值:1
2018-04-23 16:08:08.575915+0800 testData[34765:133946832] 位置:1的值:3

0x02 循环链表

  循环链表即将链表中最后一个元素的next指针指向第一个元素。这样的链表,其任何节点都可以当做头结点,当第一个节点被重复访问时表示遍历结束。
  源码将以约瑟夫问题展现,既:n个人围成一个圆圈,首先第1个人从1开始一个人一个人顺时针报数,报到第m个人,令其出列。然后再从下一个人开始从1顺时针报数,报到第m个人,再令 其出列,…,如此下去,求出列顺序。为了解决这个问题,我们定义一个浮标

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
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
#define ERROR   -1000
#define SUCCESS 1000

#define STATUS int

// 节点结构
typedef struct _node {
int val;
struct _node *next;
}Node;

// 链表结构
typedef struct _nodeList {
int length;
Node *slider; // 浮标
}NodeList;

// 创建一个空链表
NodeList* CreateList() {
NodeList *list = (NodeList *)malloc(sizeof(NodeList));
if(list != NULL) {
list->length = 0;
list->slider = NULL;
}
return list;
}

// 销毁一个链表
void DestroyList(NodeList *list) {
if(!list) return;

free(list);
}

// 清空一个链表
void ClearList(NodeList *list) {
if(!list) return;

list->length = 0;
list->slider = NULL;
}

// 获取链表长度
int GetListLength(NodeList *list) {
if(!list) return ERROR;
return list->length;
}

// 获取某个位置的节点
Node* GetListNode(NodeList *list, int position) {
bool status = list != NULL && position >= 0;
if(!status) return NULL;

Node *node = NULL;

Node *currentNode = (Node *)list;
for (int i = 0; i < position && currentNode->next != NULL; i++) {
currentNode = currentNode->next;
}
node = currentNode->next;

return node;
}

// 插入节点
STATUS InsertListNode(NodeList *list, Node *node, int position) {
bool status = list != NULL && node != NULL && position >= 0;
if(!status) return ERROR;

if(list->length == 0) {
list->slider = node;
}

// list结构体和node结构体相似,所以currentNode这时候的next值跟list的slider一样。所以链表循环自此形成
Node *currentNode = (Node *)list;
for (int i = 0; i < position && currentNode->next != NULL; i++) {
currentNode = currentNode->next;
}
node->next = currentNode->next;
currentNode->next = node;
list->length++;

// 如果插入在第一个位置,需要重新将最后一个节点的next指针指向这个新的第一个节点
if(currentNode == (Node *)list) {
Node *lastNode = GetListNode(list, list->length - 1);
lastNode->next = node;
}

return SUCCESS;
}

// 删除某个位置的节点
STATUS DeleteListNode(NodeList *list, int position) {
bool status = list != NULL && position >= 0;
if(!status) return ERROR;

Node *currentNode = (Node *)list;
for (int i = 0; i < position && currentNode->next != NULL; i++) {
currentNode = currentNode->next;
}

Node *node = currentNode->next; // 要删除的node
currentNode->next = node->next;

list->length--;

if(list->length == 0) {
list->slider = NULL;
}else{
Node *firstNode = (Node *)list;

// 如果删的是第一个节点,就把最后一个节点的next指针指向被删节点的下一个节点
if(firstNode == node) {
Node *lastNode = GetListNode(list, list->length - 1);
lastNode->next = node->next;
// 如果删的是浮标节点,就把浮标节点的next指针指向被删节点的下一个节点
}else if (node == list->slider) {
list->slider = node->next;
}
}

return SUCCESS;
}

// 删除指定节点
STATUS DeleteListSpecialNode(NodeList *list, Node *node) {
bool status = list != NULL && node != NULL;
if(!status) return ERROR;

Node *currentNode = (Node *)list;
int i = 0;
for (i = 0; i < list->length && currentNode->next != NULL; i++) {
if(currentNode->next == node) break;

currentNode = currentNode->next;
}

return DeleteListNode(list, i);
}

// 重置浮标
void ResetListSlider(NodeList *list) {
if(list == NULL) return;

list->slider = ((Node *)list)->next;
}

// 获取浮标指向的节点
Node* GetListSlider(NodeList *list) {
if(list == NULL) return NULL;

return list->slider;
}

// 将浮标指向下一个节点
Node* NextListSlider(NodeList *list) {
if(list == NULL) return NULL;

Node *node = list->slider;

if(list->slider == NULL){
ResetListSlider(list);
}else{
list->slider = list->slider->next;
}
return node;
}

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
[super viewDidLoad];

NodeList *list = CreateList();

struct _node n1;
struct _node n2;
struct _node n3;
struct _node n4;
struct _node n5;
struct _node n6;
struct _node n7;
struct _node n8;

n1.val = 1;
n2.val = 2;
n3.val = 3;
n4.val = 4;
n5.val = 5;
n6.val = 6;
n7.val = 7;
n8.val = 8;

InsertListNode(list, (Node *)&n1, GetListLength(list));
InsertListNode(list, (Node *)&n2, GetListLength(list));
InsertListNode(list, (Node *)&n3, GetListLength(list));
InsertListNode(list, (Node *)&n4, GetListLength(list));
InsertListNode(list, (Node *)&n5, GetListLength(list));
InsertListNode(list, (Node *)&n6, GetListLength(list));
InsertListNode(list, (Node *)&n7, GetListLength(list));
InsertListNode(list, (Node *)&n8, GetListLength(list));

for (int i = 0; i < GetListLength(list); i++) {
Node *node = GetListNode(list, i);
NSLog(@"位置:%d的值:%d", i, node->val);
}

NSLog(@"------------\n");
ResetListSlider(list);

while (GetListLength(list) > 0) {
for (int i = 1; i < 3; i++) {
NextListSlider(list);
}
Node *node = GetListSlider(list);
DeleteListSpecialNode(list, node);
NSLog(@"出列:%d", node->val);
}

DestroyList(list);
}

@end

// 运行结果:
2018-04-24 09:22:22.752025+0800 testData[39552:141135212] 位置:0的值:1
2018-04-24 09:22:22.752217+0800 testData[39552:141135212] 位置:1的值:2
2018-04-24 09:22:22.752373+0800 testData[39552:141135212] 位置:2的值:3
2018-04-24 09:22:22.752499+0800 testData[39552:141135212] 位置:3的值:4
2018-04-24 09:22:22.752622+0800 testData[39552:141135212] 位置:4的值:5
2018-04-24 09:22:22.752755+0800 testData[39552:141135212] 位置:5的值:6
2018-04-24 09:22:22.752875+0800 testData[39552:141135212] 位置:6的值:7
2018-04-24 09:22:22.752998+0800 testData[39552:141135212] 位置:7的值:8
2018-04-24 09:22:22.753101+0800 testData[39552:141135212] ------------
2018-04-24 09:22:22.753233+0800 testData[39552:141135212] 出列:3
2018-04-24 09:22:22.753356+0800 testData[39552:141135212] 出列:6
2018-04-24 09:22:22.753494+0800 testData[39552:141135212] 出列:1
2018-04-24 09:22:22.753635+0800 testData[39552:141135212] 出列:4
2018-04-24 09:22:22.753787+0800 testData[39552:141135212] 出列:7
2018-04-24 09:22:22.753925+0800 testData[39552:141135212] 出列:2
2018-04-24 09:22:22.754040+0800 testData[39552:141135212] 出列:5
2018-04-24 09:22:22.754307+0800 testData[39552:141135212] 出列:8

0x03 双向链表

  双向链表可以解决单链表无法直接访问前驱元素的问题,单链表的逆序访问时一个极其耗时的操作。所以在双链表中,新增一个指向前驱的指针。

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
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
#define ERROR   -1000
#define SUCCESS 1000

#define STATUS int

// 节点结构
typedef struct _node {
int val;
struct _node *next;
struct _node *pre;
}Node;

// 链表结构
typedef struct _nodeList {
int length;
Node *slider; // 浮标
}NodeList;

// 创建一个空链表
NodeList* CreateList() {
NodeList *list = (NodeList *)malloc(sizeof(NodeList));
if(list != NULL) {
list->length = 0;
list->slider = NULL;
}
return list;
}

// 销毁一个链表
void DestroyList(NodeList *list) {
if(!list) return;

free(list);
}

// 清空一个链表
void ClearList(NodeList *list) {
if(!list) return;

list->length = 0;
list->slider = NULL;
}

// 获取链表长度
int GetListLength(NodeList *list) {
if(!list) return ERROR;
return list->length;
}

// 获取某个位置的节点
Node* GetListNode(NodeList *list, int position) {
bool status = list != NULL && position >= 0;
if(!status) return NULL;

Node *node = NULL;

Node *currentNode = (Node *)list;
for (int i = 0; i < position && currentNode->next != NULL; i++) {
currentNode = currentNode->next;
}
node = currentNode->next;

return node;
}

// 插入节点
STATUS InsertListNode(NodeList *list, Node *node, int position) {
bool status = list != NULL && node != NULL && position >= 0;
if(!status) return ERROR;

if(list->length == 0) {
list->slider = node;
}

// list结构体和node结构体相似,所以currentNode这时候的next值跟list的slider一样。所以链表循环自此形成
Node *currentNode = (Node *)list;
for (int i = 0; i < position && currentNode->next != NULL; i++) {
currentNode = currentNode->next;
}
node->next = currentNode->next;
currentNode->next->pre = node;
currentNode->next = node;
node->pre = currentNode;
list->length++;

// 如果插入在第一个位置,需要重新将最后一个节点的next指针指向这个新的第一个节点
if(currentNode == (Node *)list) {
Node *lastNode = GetListNode(list, list->length - 1);
lastNode->next = node;
node->pre = lastNode;
}

return SUCCESS;
}

// 删除某个位置的节点
STATUS DeleteListNode(NodeList *list, int position) {
bool status = list != NULL && position >= 0;
if(!status) return ERROR;

Node *currentNode = (Node *)list;
for (int i = 0; i < position && currentNode->next != NULL; i++) {
currentNode = currentNode->next;
}

Node *node = currentNode->next; // 要删除的node
currentNode->next = node->next;
node->next->pre = currentNode;

list->length--;

if(list->length == 0) {
list->slider = NULL;
}else{
Node *firstNode = (Node *)list;

// 如果删的是第一个节点,就把最后一个节点的next指针指向被删节点的下一个节点
if(firstNode == node) {
Node *lastNode = GetListNode(list, list->length - 1);
lastNode->next = node->next;
// 如果删的是浮标节点,就把浮标节点的next指针指向被删节点的下一个节点
}else if (node == list->slider) {
list->slider = node->next;
}
}

return SUCCESS;
}

// 删除指定节点
STATUS DeleteListSpecialNode(NodeList *list, Node *node) {
bool status = list != NULL && node != NULL;
if(!status) return ERROR;

Node *currentNode = (Node *)list;
int i = 0;
for (i = 0; i < list->length && currentNode->next != NULL; i++) {
if(currentNode->next == node) break;

currentNode = currentNode->next;
}

return DeleteListNode(list, i);
}

// 重置游标
void ResetListSlider(NodeList *list) {
if(list == NULL) return;

list->slider = ((Node *)list)->next;
}

// 获取游标指向的节点
Node* GetListSlider(NodeList *list) {
if(list == NULL) return NULL;

return list->slider;
}

// 将游标指向下一个节点
Node* NextListSlider(NodeList *list) {
if(list == NULL) return NULL;

Node *node = list->slider;

if(list->slider == NULL){
ResetListSlider(list);
}else{
list->slider = list->slider->next;
}
return node;
}

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
[super viewDidLoad];

NodeList *list = CreateList();

struct _node n1;
struct _node n2;
struct _node n3;
struct _node n4;
struct _node n5;
struct _node n6;
struct _node n7;
struct _node n8;

n1.val = 1;
n2.val = 2;
n3.val = 3;
n4.val = 4;
n5.val = 5;
n6.val = 6;
n7.val = 7;
n8.val = 8;

InsertListNode(list, (Node *)&n1, GetListLength(list));
InsertListNode(list, (Node *)&n2, GetListLength(list));
InsertListNode(list, (Node *)&n3, GetListLength(list));
InsertListNode(list, (Node *)&n4, GetListLength(list));
InsertListNode(list, (Node *)&n5, GetListLength(list));
InsertListNode(list, (Node *)&n6, GetListLength(list));
InsertListNode(list, (Node *)&n7, GetListLength(list));
InsertListNode(list, (Node *)&n8, GetListLength(list));

for (int i = 0; i < GetListLength(list); i++) {
Node *node = GetListNode(list, i);
NSLog(@"出列:%d,其前值:%d,其后值:%d", node->val, node->pre->val, node->next->val);
}

DestroyList(list);
}

@end

// 运行结果:
2018-04-24 10:38:34.810183+0800 testData[48305:141728412] 出列:1,其前值:8,其后值:2
2018-04-24 10:38:34.810361+0800 testData[48305:141728412] 出列:2,其前值:1,其后值:3
2018-04-24 10:38:34.810465+0800 testData[48305:141728412] 出列:3,其前值:2,其后值:4
2018-04-24 10:38:34.810589+0800 testData[48305:141728412] 出列:4,其前值:3,其后值:5
2018-04-24 10:38:34.810699+0800 testData[48305:141728412] 出列:5,其前值:4,其后值:6
2018-04-24 10:38:34.810818+0800 testData[48305:141728412] 出列:6,其前值:5,其后值:7
2018-04-24 10:38:34.810910+0800 testData[48305:141728412] 出列:7,其前值:6,其后值:8
2018-04-24 10:38:34.811000+0800 testData[48305:141728412] 出列:8,其前值:7,其后值:1

  那么,如果不通过双向链表,一个单链表怎么反转呢?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
for (int i = len-1; i >= 0; i--) {
Node *node = GetListNode(list, i);
NSLog(@"出列:%d", node->val);
}

// 运行结果:
2018-04-24 10:56:29.439705+0800 testData[50135:141858946] 出列:1
2018-04-24 10:56:29.439830+0800 testData[50135:141858946] 出列:2
2018-04-24 10:56:29.439925+0800 testData[50135:141858946] 出列:3
2018-04-24 10:56:29.440032+0800 testData[50135:141858946] 出列:4
2018-04-24 10:56:29.440128+0800 testData[50135:141858946] 出列:5
2018-04-24 10:56:29.440233+0800 testData[50135:141858946] 出列:6
2018-04-24 10:56:29.440325+0800 testData[50135:141858946] 出列:7
2018-04-24 10:56:29.440432+0800 testData[50135:141858946] 出列:8
2018-04-24 10:56:29.440512+0800 testData[50135:141858946] ----开始反转-----
2018-04-24 10:56:29.440594+0800 testData[50135:141858946] 出列:8
2018-04-24 10:56:29.440667+0800 testData[50135:141858946] 出列:7
2018-04-24 10:56:29.440741+0800 testData[50135:141858946] 出列:6
2018-04-24 10:56:29.440815+0800 testData[50135:141858946] 出列:5
2018-04-24 10:56:29.440888+0800 testData[50135:141858946] 出列:4
2018-04-24 10:56:29.441030+0800 testData[50135:141858946] 出列:3
2018-04-24 10:56:29.441216+0800 testData[50135:141858946] 出列:2
2018-04-24 10:56:29.441386+0800 testData[50135:141858946] 出列:1

  这样就完成了这个需求。