链表有很多种,有单项、双向链表,带环、不带环链表,带头节点、不带头节点链表,而这些链表又可以两两或者三个三个组成一种链表,下面主要是说带不头节点不带环单向链表的一些操作。
4 //1.链表初始化
5 void LinkListInit(LinkNode** node)
6 {
7 *node = NULL;
8 }
9
10 void LinkListInit2(LinkNode* node)
11 {
12 node = NULL;
13 }
14
15 LinkNode* LinkListInit3()
16 {
17 return NULL;
18 }
19
尾部插入一个节点——尾插
20 LinkNode* CreateNode(LinkNodeType value)
21 {
22 LinkNode *new_node=(LinkNode*)malloc(sizeof(LinkNode));
23 new_node->data=value;
24 new_node->next=NULL;
25 return new_node;
26 }
27 //2.尾插
28 void LinkListPushBack(LinkNode** phead, LinkNodeType value)
29 {
30 if(phead == NULL)
31 {
32 //非法输入
33 return ;
34 }
35 if(*phead == NULL)
36 {
37 //空链表
38 *phead=CreateNode(value);
39 return ;
40 }
41 //链表非空
42 LinkNode *cur=*phead;
43 while(cur->next!=NULL)
44 {
45 cur=cur->next;
46 }
47 LinkNode *new_node=CreateNode(value);
48 cur->next=new_node;
49 new_node->next=NULL;
50 return ;
51 }
53 void DestroyNode(LinkNode *node)
54 {
55 //free(*node->data);
56 free(node);
57 return ;
58 }
59
若链表不只有一个元素,则设一个指针cur指向链表的头节点,设一个指针pre指向NULL,并建立一个循环,让pre指针一直指向指针cur,cur指向cur的下一个节点,直至cur的下一个节点为NULL,则循环结束,此时cur指针一定指向链表的最后一个节点,而pre指针指向链表的倒数第二个节点,这时让pre的next指向NULL,并销毁cur节点,详细见图
60 //3.尾删
61 void LinkListPopBack(LinkNode** phead)
62 {
63 if(phead == NULL)
64 {
65 //非法输入
66 return ;
67 }
68 if(*phead==NULL)
69 {
70 //空链表
71 return ;
72 }
73 if((*phead)->next==NULL)
74 {
75 //只有一个元素
76 DestroyNode(*phead);
77 *phead=NULL;
78 return ;
79 }
80 LinkNode *cur=*phead;
81 LinkNode *pre=NULL;
82 while(cur->next!=NULL)
83 {
84 pre=cur;
85 cur=cur->next;
86 }
87 //当循环结束,cur指向最后一个节点,pre指向倒数第二个节点
88 pre->next=NULL;
89 DestroyNode(cur);
90 return ;
91 }
92
头部插入一个节点——头插
93 //4.头插
94 void LinkListPushFront(LinkNode** phead,LinkNodeType value)
95 {
96 if(phead == NULL)
97 {
98 //非法输入
99 return ;
100 }
101 LinkNode* new_node=CreateNode(value);
102 new_node->next=*phead;
103 *phead=new_node;
104 }
105
106 //5.头删
107 void LinkListPopFront(LinkNode** phead)
108 {
109 if(phead == NULL)
110 {
111 //非法输入
112 return ;
113 }
114 if(*phead == NULL)
115 {
116 //空链表
117 return ;
118 }
119 LinkNode* to_erase=*phead;
120 *phead=(*phead)->next;
121 DestroyNode(to_erase);
122 return ;
123 }
125 //6.将一个新节点插入到pos之后
126 void LinkListInsert(LinkNode* phead,LinkNode* pos,LinkNodeType value)
127 {
128 if(pos == NULL)
129 {
130 //非法输入
131 //pos表示一个节点的指针,若pos为空,则表示根本不存在这样的节点
132 return ;
133 }
134 LinkNode* new_node=CreateNode(value);
135 new_node->next=pos->next;
136 pos->next=new_node;
137 return ;
138
139 }
首先要判断pos位置在哪,若pos为第一个元素,则问题转化为链表的头插法;若pos位置不是链表的第一个元素,则要对链表进遍历来找到pos位置,若找到了就进行插入操作,若没找到,则不进行操作
141 将一个新节点插入到pos之前
142 void LinkListInsertBefore(LinkNode** phead,LinkNode* pos,LinkNodeType value)
143 {
144 if(phead == NULL || pos == NULL)
145 {
146 //非法输入
147 return ;
148 }
149 if(*phead == pos)
150 {
151 //要插入的位置为头结点
152 LinkListPushFront(phead,value);
153 return ;
154 }
155 LinkNode *cur=*phead;
156 for(;cur!=NULL;cur=cur->next)
157 {
158 if(cur->next==pos)
159 {
160 break;
161 }
162 }
163 //循环结束后要知道是由于哪种情况导致的循环结束到底找没找到pos
164 if(cur == NULL)
165 {
166 //没找到
167 return ;
168 }
169 LinkListInsert(phead,cur,&value);
170 return ;
171 }
172
173
175 //7.对LinkListInsertBefore进行优化O(n)->O(1)
176 void LinkListInsertBefore2(LinkNode* pos,LinkNodeType value)
177 {
178 if(pos == NULL)
179 {
180 //非法输入
181 return ;
182 }
183 LinkNode* new_node=CreateNode(pos->data);
184 new_node->next=pos->next;
185 pos->next=new_node;
186 pos->data=value;
187 //或者将上面四行代码改为
188 //LinkListInsert(pos,pos->data);
189 //pos->data=value;
190 }
192 //8.删除pos位置节点
193 void LinkListErase(LinkNode** phead,LinkNode* pos)
194 {
195 if(phead == NULL || pos == NULL)
196 {
197 //非法输入
198 return ;
199 }
200 if(*phead == NULL)
201 {
202 //空链表
203 return ;
204 }
205 LinkNode *cur=*phead;
206 for(;cur!=NULL;cur=cur->next)
207 {
208 if(cur->next==pos)
209 {
210 break;
211 }
212 }
213 //循环结束之后要判定是找到了退出还是没找到pos退出
214 if(cur == NULL)
215 {
216 return ;
217 }
218 cur->next=pos->next;
219 DestroyNode(pos);
220 return ;
221 }
下面对上面的方法进行优化,将时间复杂度从O(n)变为O(1)
223 //对LinkListErase进行优化
224 void LinkListErase2(LinkNode** phead,LinkNode* pos)
225 {
226 if(phead == NULL || pos == NULL)
227 {
228 //非法输入
229 return ;
230 }
231 if(*phead == NULL)
232 {
233 //空链表
234 return ;
235 }
236 if(pos->next == NULL)
237 {
238 //要删除的元素为最后一个元素
239 LinkListPopBack(phead);
240 return ;
241 }
242 pos->data=pos->next->data;
243 LinkNode* to_erase=pos->next;
244 pos->next=to_erase->next;
245 DestroyNode(to_erase);
246 }
248 //9.找到节点就返回节点对应的地址,若没找到就返回NULL
249 LinkNode* LinkListFind(LinkNode* head,LinkNodeType to_find)
250 {
251 if(head == NULL)
252 {
253 //空链表
254 return NULL;
255 }
256 LinkNode* cur=head;
257 while(cur!=NULL)
258 {
259 if(cur->data==to_find)
260 {
261 return cur;
262 }
263 cur=cur->next;
264 }
265 return NULL;
266 }
删除指定元素
268 //10删除指定元素
269 void LinkListRemove(LinkNode** phead,LinkNodeType to_remove)
270 {
271 if(phead == NULL)
272 {
273 //非法输入
274 return ;
275 }
276 if(*phead == NULL)
277 {
278 //空链表
279 return ;
280 }
281 //删除的元素恰好是第一个
282 if((*phead)->data==to_remove)
283 {
284 LinkNode* to_delete=*phead;
285 *phead=(*phead)->next;
286 DestroyNode(to_delete);
287 return ;
288 }
289 LinkNode* cur=*phead;
290 for(;cur->next!=NULL;cur=cur->next)
291 {
292 if(cur->next->data==to_remove)
293 {
294 //cur指向要删除的元素的前一个元素的位置
295 LinkNode* to_delete=cur->next;
296 cur->next=to_delete->next;
297 DestroyNode(to_delete);
298 }
299 }
300 return ;
301 }
303 //11.删除所有指定的元素
304 void LinkListRemoveall(LinkNode** phead,LinkNodeType to_remove)
305 {
306 if(phead == NULL)
307 {
308 //非法输入
309 return ;
310 }
311 if(*phead == NULL)
312 {
313 //空链表
314 return ;
315 }
316 while(1)
317 {
318 LinkNode* pos=LinkListFind(*phead,to_remove);
319 if(pos==NULL)
320 {
321 //没有找到
322 return ;
323 }
324 LinkListErase(phead,pos);
325 }
326 return ;
327 }