数据结构_链表2

总结一些常见的链表问题。以下例子都是单向无头结点链表,部分带环。

1.从尾到头打印链表元素
    即逆序打印链表,可以创建一个新的链表,每次找出原来链表的最后一个元素头插到新链表里,再打印出新链表,但是这种办法太麻烦而且效率低。还可以采用递归的思路,在打印当前元素之前递归调用打印函数,递归出口为指针为NULL,每调用一次,传进来的参数就往链表下一个元素移动。下图为3个元素时例子:

71 void LinkReversePrint(LinkList* head)                                                                                             
72 {                                                                                                                                 
73     if(head == NULL){                                                                                                             
74         // 空链表,直接返回                                                                                                       
75         return;                                                                                                                   
76     }                                                                                                                             
77     LinkListReversePrint(head->next);    // 递归调用                                                                                          
78     printf("[%c|%p]",head->data,head);                                                                                            
79 }

2.删除链表的非尾结点(不能遍历链表)
    单向链表要对一个结点进行操作,通常需要遍历链表,找到当前结点的前一个,更改前一个结点的 next 指针,但是这里限制不能遍历结点,可以换一个思路,交换要删除结点和后一个结点的值,这样就可以删除后一个结点等同于删除指定结点,思路如下图所示:
  83 void LinkEraserNodeNotTail(LinkList* pos)                                                                                        
  84 {                                                                                                                                
  85     if(pos == NULL){                                                                                                             
  86         return;                                                                                                                  
  87     }                                                                                                                            
  88     LinkList* to_delete = pos->next;        // 保存要删除结点                                                                                    
  89     pos->next = to_delete->next;                 // 交换 next                                                                               
  90     pos->data = to_delete->data;                                                                                                 
  91     DestroyNode(to_delete);                                                                                                      
  92     return;                                                                                                                      
  93 }
                                                 
3.单链表实现约瑟夫环   
    约瑟夫环是一个环,这个环遵守某种规则,每次淘汰一个成员,直到最后剩下一个成员为止。用首尾相连的单向环链表来实现,约定一个数字,开始计数,每逢这个数字就删除当前结点,然后下一个结点重新开始计数,知道剩下最后一个结点为止。
  96 LinkList* JosephCircle(LinkList* head, size_t out)                                                                               
  97 {                                                                                                                                
  98     if(head == NULL){                                                                                                            
  99         // 空链表                                                                                                                
100         return NULL;                                                                                                             
101     }                                                                                                                            
102     if(out == 0){         // 未约定,直接返回                                                                                                         
103         return NULL;                                                                                                             
104     }                                                                                                                            
105     LinkList* cur = head;                                                                                                        
106     while(cur->next != cur){          // 剩一个结点时跳出循环                                                                                           
107         size_t count = 1;                                                                                                        
108         for(; count < out; count++){                                                                                             
109             cur = cur->next;                                                                                                     
110         }                                                                                                                        
111         LinkEraserNodeNotTail(cur);           // 调用上一个函数(删除非尾结点)                                                                                
112     }                                                                                                                            
113     return cur;                                                                                                                  
114 }    
   测试条件: 链表 a,b,c,d,e,f,g,h,i,j   约定为 4
                                                                                                                                                                                                                                                                                                     
4.逆置反转单链表(不允许创建新链表)     
    (1)方法一:创建三个指针 pre、cur、next,pre 指向头结点,cur 指向第二个, next指向 cur 的 next 先保存 cur 的下一个操作结点, 让 cur 的 next 指向 pre ,这样就完成了 b 和 a 的逆置,cur 回到 next  ,更新 next 指针,保存下一个结点。知道 cur 指向空时,最后一个结点也就逆置了。如下图所示:
117 void LinkListReverse1(LinkList** head)                                                                                           
118 {                                                                                                                                
119     if(head == NULL || *head == NULL){                                                                                           
120         return;                                                                                                                  
121     }                                                                                                                            
122     LinkList* pre = *head;                                                                                                       
123     LinkList* cur = pre->next;                                                                                                   
124     pre->next = NULL;     // 逆置后的尾结点,设置尾结点的 next 为 NULL ,这里是 a 结点                                                            
125     while(cur != NULL){                                                                                                          
126         LinkList* next = cur->next;                                                                                              
127         cur->next = pre;                                                                                                         
128         pre = cur;                                                                                                               
129         cur = next;                                                                                                              
130     }                                                                                                                            
131     *head = pre;                                                                                                                 
132     return;                                                                                                                      
133 }

    (2)方法二: 将头指针后的结点,头插到头结点之前,移动头结点,和方法一的思路是差不多的,操作有区别。
135 void LinkListReverse2(LinkList** head)                                                                                           
136 {                                                                                                                                
137     if(head == NULL || *head == NULL){                                                                                           
138         return;                                                                                                                  
139     }                                                                                                                            
140     LinkList* cur = *head;                                                                                                       
141     while(cur->next != NULL){                                                                                                    
142         LinkList* to_move = cur->next;  // 拿出头结点后边的元素插入到头节点之前                                                  
143         cur->next = to_move->next;        // 保存要移动结点的 next                                                                                    
144         to_move->next = *head;    // cur的next已经更改,移动的结点需要指向头指针                                                 
145         *head = to_move;             // 移动头结点                                                                                            
146     }                                                                                                                            
147     cur->next = NULL;                     // 链表结尾置空                                                                                       
148     return;                                                                                                                      
149 }  
                                                                                   
                                                              
5.单链表排序(冒泡排序,升序)            
     n 个元素,冒泡排序一趟排出一个元素,第一趟比较 n-1 次,得出最大值,再进行第二趟比较,最后一个元素已经确定了,第二趟就比第一趟少比较一次,比较 n 趟。链表冒泡排序原理是一样的,但是得注意,需要创建一个尾变量指针,移动尾指针的位置,减少比较次数。
152 void LinkListBubbleSort(LinkList* head)                                                                                          
153 {                                                                                                                                
154     if(head == NULL){                                                                                                            
155         return;                                                                                                                  
156     }                                                                                                                            
157     LinkList* count = head;          // 趟数                                                                                            
158     LinkList* tail = NULL;                  // 次数                                                                                     
159     for(; count != NULL; count = count->next){                                                                                   
160         LinkList* cur = head;                                                                                                    
161         for(; cur->next != tail; cur = cur->next){                                                                               
162             if(cur->data > cur->next->data){                                                                                     
163                 LinkListType pos = cur->data;                                                                                    
164                 cur->data = cur->next->data;                                                                                     
165                 cur->next->data = pos;                                                                                           
166             }                                                                                                                    
167         }                                                                                                                        
168         tail = cur;           //  更新尾指针                                                                                                    
169     }                                                                                                                            
170 }
                                                                                         
                                                                                                                      
6.合并两个有序链表,合并后依然有序          
    定义两个指针,比较两个元素的大小,较小的元素放到新链表中,然后小指针向后移动,再次比较,直到一个链表为空。
 
173 LinkList* LinkListMerge(LinkList* head1, LinkList* head2)                                                                        
174 {                                                                                                                                
175     if(head1 == NULL){                 // 一个链表为空,返回另一个链表                                                                                          
176         if(head2 == NULL){                                                                                                       
177             return NULL;                                                                                                         
178         }                                                                                                                        
179         return head2;                                                                                                            
180     }else if(head2 == NULL){                                                                                                     
181         return head1;                                                                                                            
182     }                                                                                                                            
183     LinkList* cur1 = head1;                                                                                                      
184     LinkList* cur2 = head2;                                                                                                      
185     LinkList* new_head = NULL;                                                                                                   
186     LinkList* new_tail = NULL;                                                                                                   
187     while(cur1 != NULL && cur2 != NULL){                                                                                         
188         if(cur1->data < cur2->data){                                                                                             
189             if(new_head == NULL){                                                                                                
190                 new_head = cur1;                                                                                                 
191                 new_tail = cur1;                                                                                                 
192             }else{  
193                 new_tail->next = cur1;                                                                                           
194                 new_tail = new_tail->next;                                                                                       
195             }                                                                                                                    
196             cur1 = cur1->next;                                                                                                   
197         }else{                                                                                                                   
198             if(new_head == NULL){                                                                                                
199                 new_head = cur2;                                                                                                 
200                 new_tail = cur2;                                                                                                 
201             }else{                                                                                                               
202                 new_tail->next = cur2;                                                                                           
203                 new_tail = new_tail->next;                                                                                       
204             }                                                                                                                    
205             cur2 = cur2->next;                                                                                                   
206         }                                                                                                                        
207     }                                                                                                                            
208     if(cur1 == NULL){                                                                                                            
209         new_tail->next = cur2;                                                                                                   
210     }else{                                                                                                                       
211         new_tail->next = cur1;                                                                                                   
212     }                                                                                                                            
213     return new_head;                                                                                                             
214 }   
                                                                                                                                                                                                       
7.查找单链表的中间结点(只遍历一次链表)    
    定义快慢指针,快指针每次走两步,慢指针每次走一步,快指针走到链表结尾的时候,满指针刚好走到一半。
217 LinkList* LinkFindMidNode(LinkList* head)                                                                                        
218 {                                                                                                                                
219     if(head == NULL){                                                                                                            
220         // 空链表                                                                                                                
221         return NULL;                                                                                                             
222     }                                                                                                                            
223     LinkList* fast = head;                                                                                                       
224     LinkList* slow = head;                                                                                                       
225     while(fast != NULL && fast->next != NULL){       // fast 可以为 NULL(退出条件) 要保证 fast->next 的合法性,走两步                
226         fast = fast->next->next;                                                                                                 
227         slow = slow->next;                                                                                                       
228     }                                                                                                                            
229     return slow;                                                                                                                 
230 }

8.寻找单链表的倒数第 k 个结点(只能遍历一次链表)  
    类似于找中间结点,快慢指针,快指针先走 k 步,接下来快指针走一步,慢指针走一步,当快指针走到链表尾部,慢指针走到倒数第 k 个结点。
233 LinkList* LinkFindLastKNode(LinkList* head, size_t size)                                                                         
234 {                                                                                                                                
235     if(head == NULL || size == 0){                                                                                               
236         return NULL;                                                                                                             
237     }                                                                                                                            
238     size_t link_size = 0;                                                                                                        
239     LinkList* cur = head;                                                                                                        
240     while(cur != NULL){                                                                                                          
241         link_size ++;                                                                                                            
242         cur = cur->next;                                                                                                         
243     }                                                                                                                            
244     if(size > link_size){                                                                                                       
245         // 查找的大小超过链表最大个数,查找不到                                                                                                              
246         return NULL;                                                                                                             
247     }                                                                                                                            
248     LinkList* fast = head;                                                                                                       
249     LinkList* slow = head;                                                                                                       
250     size_t count = 0;                                                                                                            
251     while(count++ < size){                                                                                                       
252         fast = fast->next;                                                                                                       
253     }                                                                                                                            
254     while(fast != NULL){  
255         fast = fast->next;                                                                                                       
256         slow = slow->next;                                                                                                       
257     }                                                                                                                            
258     return slow;                                                                                                                 
259 }
     
                                                                         
9.删除链表的倒数第 k 个结点                    
    先找到倒数第 k 个结点,删除该结点,可以遍历链表找到前一个结点进行删除,也可以交换该结点与后一个结点的值,再删除后一个结点,第二种效率更高一点。 
                      
             
262 void LinkEraserLastKNode(LinkList** head, size_t size)                                                                           
263 {                                                                                                                                
264     if(head == NULL || size == 0){                                                                                               
265         // 非法输入                                                                                                              
266         return;                                                                                                                  
267     }                                                                                                                            
268     if(*head == NULL){                                                                                                           
269         // 空链表                                                                                                                
270         return;                                                                                                                  
271     }                                                                                                                            
272     LinkList* to_delete = NULL;                                                                                                  
273     LinkList* k_node = LinkFindLastKNode(*head,size);                                                                            
274     if(k_node == NULL){                                                                                                          
275         // 无删除元素                                                                                                            
276         return;                                                                                                                  
277     }                                                                                                                            
278     if(k_node == *head){                                                                                                         
279         to_delete = *head;                                                                                                       
280         *head = k_node->next;                                                                                                    
281         DestroyNode(to_delete);                                                                                                  
282     }
283     to_delete = k_node->next;                                                                                                    
284     k_node->data = to_delete->data;                                                                                              
285     k_node->next = to_delete->next;                                                                                              
286     DestroyNode(to_delete);                                                                                                      
287 }

                                         
10.判断单链表是否带环?若带环,求环的长度,入口点,并计算算法的时间复杂度和空间复杂度   
    定义快慢两个指针,快指针一次走两步,慢指针一次一步,快指针要是为空说明无环,快慢指针要是能相遇说明带环,如果带环,从快慢指针相遇点标记,下一次走到相遇点就是环的长度,链表头部到环入口的位移等于环入口到相遇点位移的n(n>=1)倍,所以从头结点、相遇点开始走,两个指针相等时,为环入口点。
290 LinkList* LinkHasCircle(LinkList* head)    // 判断是否带环 时间复杂度 O(n) 空间复杂度O(1)                                        
291 {                                                                                                                                
292     if(head == NULL){                                                                                                            
293         // 空链表                                                                                                                
294         return;                                                                                                                  
295     }                                                                                                                            
296     LinkList* fast = head;                                                                                                       
297     LinkList* slow = head;                                                                                                       
298     while(fast != NULL && fast->next != NULL){          // 快指针走两步,不能越界                                                                         
299         fast = fast->next->next;                                                                                                 
300         slow = slow->next;                                                                                                       
301         if(fast == slow){                                                                                                        
302             return fast;                                                                                                         
303         }                                                                                                                        
304     }                                                                                                                            
305     return NULL;                                                                                                                 
306 }

308 size_t LinkCircleLength(LinkList* head)   // 求环的长度  时间复杂度 O(n) 空间复杂度O(1)                                          
309 {                                                                                                                                
310     if(head == NULL){                                                                                                            
311         // 空链表                                                                                                                
312         return;                                                                                                                  
313     }                                                                                                                            
314     LinkList* meet = LinkHasCircle(head);                                                                                        
315     if(meet == NULL){                                                                                                            
316         // 不带环                                                                                                                
317         return 0;                                                                                                                
318     }                                                                                                                            
319     LinkList* cur = meet->next;                                                                                                  
320     size_t length = 1;                                                                                                           
321     while(cur != meet){                                                                                                          
322         length ++;                                                                                                               
323         cur = cur->next;                                                                                                         
324     }                                                                                                                            
325     return length;                                                                                                               
326 }    

328 LinkList* LinkCircleEnterNode(LinkList* head)   // 求环的入口点  时间复杂度 O(n) 空间复杂度O(1)                                  
329 {                                                                                                                                
330     if(head == NULL){                                                                                                            
331         // 空链表                                                                                                                
332         return NULL;                                                                                                             
333     }                                                                                                                            
334     LinkList* meet = LinkHasCircle(head);                                                                                        
335     if(meet == NULL){                                                                                                            
336         // 不带环                                                                                                                
337         return NULL;                                                                                                             
338     }                                                                                                                            
339     LinkList* cur = head;                                                                                                        
340     while(cur != meet){                                                                                                          
341         cur = cur->next;                                                                                                         
342         meet = meet->next;                                                                                                       
343     }                                                                                                                            
344     return cur;                                                                                                                  
345 }
    无环
    有环
     
                       
11.判断两个链 表是否相交,若相交求交点(链表不带环)             
    两个链表如果相交,它们将会走到同一个终点, 分别定义两个指针从两个链表头部出发,走到尾部,相同则相交。相交求交点,计算两个链表的长度,长链表指针先走多出来的长度,然后长短链表的指针一起走,每走一步比较一次是否相等,相等时即为交点。
 
    
348 size_t LinkHasCross(LinkList* head1, LinkList* head2) //是否相交                                                                 
349 {                                                                                                                                
350     if(head1 == NULL || head2 == NULL){                                                                                          
351         // 无交点,返回0                                                                                                                
352         return 0;                                                                                                                
353     }                                                                                                                            
354     LinkList* cur1 = head1;                                                                                                      
355     LinkList* cur2 = head2;                                                                                                      
356     while(cur1->next != NULL){             // 走到链表1的尾部                                                                                      
357         cur1 = cur1->next;                                                                                                       
358     }                                                                                                                            
359     while(cur2->next != NULL){             // 走到链表2的尾部                                                                                       
360         cur2 = cur2->next;                                                                                                       
361     }                                                                                                                            
362     if(cur1 == cur2){                                                                                                            
363         return 1;                                                                                                                
364     }                                                                                                                            
365     return 0;                                                                                                                    
366 }

368 LinkList* LinkCrossNode(LinkList* head1, LinkList* head2)  // 求交点,相交返回交点地址                                                            
369 {                                                                                                                                
370     if(head1 == NULL || head2 == NULL){                                                                                          
371         return NULL;                                                                                                             
372     }                                                                                                                            
373                                                                                                                                  
374     LinkList* cur1 = head1;                                                                                                      
375     size_t size1 = 0;                                                               // 计算链表长度                                             
376     while(cur1->next != NULL){                                                                                                   
377         size1 ++;                                                                                                                
378         cur1 = cur1->next;                                                                                                       
379     }                                                                                                                            
380                                                                                                                                  
381     size_t size2 = 0;                                                                                                            
382     LinkList* cur2 = head2;                                                                                                      
383     while(cur2->next != NULL){                                                                                                   
384         size2 ++;                                                                                                                
385         cur2 = cur2->next;                                                                                                       
386     }
387                                                                                                                                  
388     cur1 = head1;                                                                                                                
389     cur2 = head2;                                                                                                                
390     if(size1 > size2){                                                                                                           
391         size_t i = 0;                                                                                                            
392         for(; i < (size1 - size2); i++){                                                                                         
393             cur1 = cur1->next;                                                                                                   
394         }                                                                                                                        
395     }else{                                                                                                                       
396         size_t i = 0;                                                                                                            
397         for(; i < (size2 - size1); i++){                                                                                         
398             cur2 = cur2->next;                                                                                                   
399         }                                                                                                                        
400     }                                                                                                                            
401     while(cur1->next != cur2->next){                                                                                             
402         cur1 = cur1->next;                                                                                                       
403         cur2 = cur2->next;                                                                                                       
404     }                                                                                                                            
405     return cur1->next;                                                                                                           
406 }  

                                              
12.判断两个链表是否相交,若相交,求交点(链表可能带环)
    思路与 11 题差不多,首先求两个链表的环入口点,(1)若都不带环,链表相交的判断和交点都如上。 (2)若一个带环,一个不带环,则肯定不相交。(3)若两个链表都带环,比较两个环入口点,① 两个环入口点相同,则两个链表相交,相交于环外,计算两个链表头部到环入口点的步数,长链表先走多出来的部分,然后长短链表一起走,相遇时即为交点。② 两个环入口点不相同,判断是否可以从一个环入口点走到另一个环入口点,可以的话,相交于环上,两个环入口点都是交点;不可以的话,不相交。
409 size_t LinkHasCross2(LinkList* head1, LinkList* head2)   // 判断相交                                                             
410 {                                                                                                                                
411     if(head1 == NULL || head2 == NULL){                                                                                          
412         return 0;                                                                                                                
413     }                                                                                                                            
414     LinkList* circle1 = LinkCircleEnterNode(head1);                     // 取两个链表的环入口点                                                         
415     LinkList* circle2 = LinkCircleEnterNode(head2);                                                                              
416     if(circle1 == NULL && circle2 == NULL){                       // 都为空,调用无环链表相交函数                                                               
417         return LinkHasCross(head1, head2);                                                                                       
418     }                                                                                                                            
419     if(circle1 == NULL || circle2 == NULL){                   // 一个无环,一个有环,不相交,返回0                                                        
420         return 0;                                                                                                                
421     }                                                                                                                            
422     if(circle1 == circle2){                                            // 相交返回1                                                          
423         return 1;                                                                                                                
424     }                                                                                                                            
425     for(; circle1 != circle2; circle1 = circle2->next){                                                                          
426         if(circle1 == circle2){                                                                                                  
427             return 1;                                                                                                            
428         }                                                                                                                        
429     }                                                                                                                            
430     return 0;                                                                                                                    
431 }

433 LinkList* LinkCrossNode2(LinkList* head1, LinkList* head2)      // 求交点                                                                 
434 {                                                                                                                                
435     if(head1 == NULL || head2 == NULL){                                                                                          
436         return NULL;                                                                                                             
437     }                                                                                                                            
438     size_t ret = LinkHasCross2(head1, head2);               // 判断是否相交                                                                     
439     // 不相交,返回空                                                                                                            
440     if(ret == 0){                                                                                                                
441         return NULL;                                                                                                             
442     }                                                                                                                            
443     // 相交分两种情况:1.环外相交,环入口点相同;2.环上相交,入口点不相同,取两个环的环入口点                                    
444     LinkList* circle1 = LinkCircleEnterNode(head1);                                                                              
445     LinkList* circle2 = LinkCircleEnterNode(head2);                                                                              
446     // 入口点相同,以入口点为终点,两个指针相同为相交点                                                                          
447     if(circle1 == circle2){                                                                                                      
448         LinkList* cur1 = head1;                                                                                                  
449         LinkList* cur2 = head2;                                                                                                  
450         size_t s1 = LinkListSize(head1, circle1);                 // 求链表头部到环入口点的步数                                                               
451         size_t s2 = LinkListSize(head2, circle2);                                                                                
452         if(s1 > s2){   
453             size_t i = 0;                                                                                                        
454             while(i < (s1 - s2)){                                                                                                
455                 cur1 = cur1->next;                                                                                               
456                 i++;                                                                                                             
457             }                                                                                                                    
458             while(cur1 != cur2){   // 相等时为相交点                                                                             
459                 cur1 = cur1->next;                                                                                               
460                 cur2 = cur2->next;                                                                                               
461             }                                                                                                                    
462             return cur1;                                                                                                         
463         }                                                                                                                        
464         size_t i = 0;                                                                                                            
465         while(i < (s2 - s1)){                                                                                                    
466             cur2 = cur2->next;                                                                                                   
467             i++;                                                                                                                 
468         }                                                                                                                        
469         while(cur2 != cur1){                                                                                                     
470             cur1 = cur1->next;                                                                                                   
471             cur2 = cur2->next;                                                                                                   
472         }
473         return cur2;                                                                                                             
474     }                                                                                                                            
475     return circle1;                                                                                                              
476 }                                                                                                                                
                                                                                                                                 
478 size_t LinkListSize(LinkList* head, LinkList* pos)                     // 辅助函数,求步数                                                          
479 {                                                                                                                                
480     if(head == NULL || pos == NULL){    // 链表到指定 pos 位置的元素个数                                                         
481         // 空链表                                                                                                                
482         return 0;                                                                                                                
483     }                                                                                                                            
484     size_t size = 1;                                                                                                             
485     LinkList* cur = head;                                                                                                        
486     while(cur->next != pos){                                                                                                     
487         size ++;                                                                                                                 
488         cur = cur->next;                                                                                                         
489     }                                                                                                                            
490     return size;                                                                                                                 
491 }
    测试条件:(3)② 链表1:a b c d g h i j ,链表2:e f g h i j,交点为 g,环入口点为 h 

13.求两个已排序单链表中相同的数据,默认升序
​    创建一个新链表,将两个链表的相同数据保存到新链表中。两个就链表已经有序,定义两个指针分别从旧链表头部开始比较,相同的话放入新链表,不同的话,较小数据指针向后移,直到一个链表为空,新链表中就保存了相同数据。
598 LinkList* UnionSet(LinkList* head1, LinkList* head2)                                                                             
599 {                                                                                                                                
600     if(head1 == NULL || head2 == NULL){                                                                                          
601         return NULL;                                                                                                             
602     }                                                                                                                            
603     LinkList* new_head = NULL;                                                                                                   
604     LinkList* new_tail = NULL;                                                                                                   
605     LinkList* cur1 = head1;                                                                                                      
606     LinkList* cur2 = head2;                                                                                                      
607     while(cur1 != NULL && cur2 != NULL){                                                                                         
608         if(cur1->data > cur2->data){                                                                                             
609             cur2 = cur2->next;                                                                                                   
610         }                                                                                                                        
611         if(cur1->data < cur2->data){                                                                                             
612             cur1 = cur1->next;                                                                                                   
613         }else{                                                                                                                   
614             LinkListType tmp = cur1->data;                                                                                       
615             if(new_head == NULL){                                                                                                
616                 new_head = new_tail = CreatNode(tmp);                                                                            
617             }else{                                                                                                               
618                 new_tail->next = CreatNode(tmp);                                                                                 
619                 new_tail = new_tail->next;                                                                                       
620             }   
621             cur1 = cur1->next;                                                                                                   
622             cur2 = cur2->next;                                                                                                   
623         }                                                                                                                        
624     }                                                                                                                            
625     return new_head;                                                                                                             
626 }  

14.复杂链表的复制,链表的每一个结点,有一个next指针指向下一个结点, 还有一个random指针指向链表中的随机结点或者NULL,返回复制后的链表  
    ​(1)方法一:创建新链表,复制旧链表的结点和 next 指针,先不管 random 指针,然后计算出旧链表每个结点 random 指针距离头结点的偏移量,根据偏移量修改新链表的 random 指针。
497 ComplexLink* CreatComplexNode(ComplexLinkListType value)             // 创建新结点                                                            
498 {                                                                                                                                
499     ComplexLink* new_node = (ComplexLink*)malloc(sizeof(ComplexLink));                                                           
500     new_node->data = value;                                                                                                      
501     new_node->next = NULL;                                                                                                       
502     new_node->random = NULL;                                                                                                     
503     return new_node;                                                                                                             
504 }

506 size_t CountSteps(ComplexLink* head, ComplexLink* pos)     // 计算结点random指针距头结点的步数                                   
507 {                                                                                                                                
508     if(head == NULL || pos == NULL){                                                                                             
509         return 0;                                                                                                                
510     }                                                                                                                            
511     size_t count = 0;                                                                                                            
512     ComplexLink*cur = head;                                                                                                      
513     while(cur != pos){                                                                                                           
514         count ++;                                                                                                              
515         cur = cur->next;                                                                                                         
516     }                                                                                                                            
517     return count;                                                                                                                
518 }

520 ComplexLink* MoveCopyRandom(ComplexLink* cur, size_t steps)     // 复制每个结点的random指针                                      
521 {                                                                                                                                
522     if(cur == NULL){                                                                                                             
523         return;                                                                                                                  
524     }                                                                                                                            
525     size_t i = 0;                                                                                                                
526     while(i < steps){                                                                                                            
527         cur = cur->next;                                                                                                         
528         i++;                                                                                                                     
529     }                                                                                                                            
530     return cur;                                                                                                                  
531 }

533 ComplexLink* ComplexLinkCopy(ComplexLink* head)                            // 复制复杂链表                                                      
534 {                                                                                                                                
535     if(head == NULL){                                                                                                            
536         return NULL;                                                                                                             
537     }                                                                                                                            
538     // 先不管random指针,拷贝原链表的结点                                                                                        
539     ComplexLink* new_head = CreatComplexNode(head->data);                                                                        
540     ComplexLink* cur = head;                                                                                                     
541     ComplexLink* new_cur = new_head;                                                                                             
542     while(cur->next != NULL){                                                                                                    
543         new_cur->next = CreatComplexNode(cur->next->data);                                                                       
544         new_cur = new_cur->next;                                                                                                 
545         cur = cur->next;                                                                                                         
546     }                                                                                                                            
547     cur = head;                                                                                                                  
548     new_cur = new_head;                                                                                                          
549     // 设置新结点的random值                                                                                                      
550     for(; cur != NULL; cur = cur->next, new_cur = new_cur->next){                                                                
551         if(cur->random == NULL){                                                                                                 
552             new_cur->random = NULL;                                                                                              
553         }else{   
554             size_t steps = CountSteps(head, cur->random);                                                                        
555             ComplexLink* ret =  MoveCopyRandom(new_head, steps);                                                                 
556             new_cur->random = ret;                                                                                               
557         }                                                                                                                        
558     }                                                                                                                            
559     return new_head;                                                                                                             
560 }

     (2)方法二:在旧链表每个结点后面插入一个一样的结点,复制 random 指针,再将插入的点拆解出来,构成新链表。
563 ComplexLink* ComplexCopy2(ComplexLink* head)                                                                                     
564 {                                                                                                                                
565     if(head == NULL){                                                                                                            
566         return NULL;                                                                                                             
567     }                                                                                                                            
568     ComplexLink* cur = head;                                                                                                     
569     for(; cur != NULL; cur = cur->next->next){                               // 在原链表上插入结点,插入后 cur 指针需要走两步                                                    
570         ComplexLink* new = CreatComplexNode(cur->data);                                                                          
571         new->next = cur->next;                                                                                                   
572         cur->next = new;                                                                                                         
573     }                                                                                                                            
574     for(cur = head; cur != NULL; cur = cur->next->next){                  //  修改新结点的 random 指针                                                       
575         ComplexLink* new_cur = cur->next;                                                                                        
576         if(cur->random == NULL){                                                                                                 
577             new_cur->random = NULL;                                                                                              
578             continue;                                                                                                            
579         }                                                                                                                        
580         new_cur->random = cur->random->next;                                                                                     
581     }
582     ComplexLink* new_head = NULL;                                                                                                
583     ComplexLink* new_tail = NULL;                                                                                                
584     for(cur = head; cur != NULL; cur = cur->next){              // 拆除新结点,组成新链表                                                                 
585         ComplexLink* to_move = cur->next;                      // 保存要拆结点,把原链表的 next 归位                                                                  
586         cur->next = to_move->next;                                                                                               
587         if(new_head == NULL){                                                                                                    
588             new_head = new_tail = to_move;                                                                                       
589         }else{                                                                                                                   
590             new_tail->next = to_move;                                                                                            
591             new_tail = new_tail->next;                                                                                           
592         }                                                                                                                        
593     }                                                                                                                            
594     return new_head;                                                                                                             
595 }                                                                                                                                





猜你喜欢

转载自blog.csdn.net/Cherubim1/article/details/79994105