C语言之复杂链表的复制(图示详解)

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C语言之复杂链表的复制(图示详解)相关的知识,希望对你有一定的参考价值。

什么是复杂链表?

复杂链表指的是一个链表有若干个结点,每个结点有一个数据域用于存放数据,还有两个指针域,其中一个指向下一个节点,还有一个随机指向当前复杂链表中的任意一个节点或者是一个空结点。今天我们要实现的就是对这样一个复杂链表复制产生一个新的复杂链表。

复杂链表的数据结构如下:

 1 typedef int DataType;        //数据域的类型
 2 
 3 //复杂链表的数据结构
 4 
 5 typedef struct ComplexNode
 6 
 7 {
 8 
 9 DataType _data ;                     // 数据
10 
11 struct ComplexNode * _next;          // 指向下个节点的指针
12 
13 struct ComplexNode * _random;        // 指向随机节点(可以是链表中的任意节点 or 空)
14 
15 }ComplexNode;

 

 技术分享

上图就是一个复杂链表的例子,那么我们应该如何实现复杂链表的复制呢?

1、首先我们应该根据已有的复杂链表创建一条新的复杂链表,但是这个新的复杂链表的所有的结点的random指针都指向空,这样是很好实现的,相当于我们创建了一条简单的单链表(newlist),我们要复制的链表不妨称之为oldlist。

 

 技术分享

 

2、接下来我们应该把新创建的这条复杂链表(newlist)与已有的复杂链表(oldlist)合并成如下的形式:

 

技术分享

 

 

在这种情况下我们已经把两条复杂链表合并成了一条链表(称之为linklist),通过对这条链表(linklist)的观察,我们可以发现合并的链表(linklist)中属于newlist的结点pnew的上一个结点pold(属于oldlist的结点)的random指针所指向的结点的next指针就应该是pnew结点的randow指针所指向的结点。

这样我们让pold和pnew指针一直往后走最后就可以实现对所有属于新创建的复杂链表(newlist)的random指针指向相应的结点的操作。构成的复杂链表如下图

 

 技术分享

在完成以上的步骤之后我们所要做的工作就很简单了,我们只要把这一条链表linklist分开成我们的newlist链表和oldlist链表就可以了。

 

技术分享

技术分享

这样我们就完美的完成了复杂链表的复制工作下面就是具体实现的代码:

 头文件complexnode.h:

 1 #ifndef __COMPLEX__NODE__H__
 2 
 3 #define __COMPLEX__NODE__H__
 4 
 5  
 6 
 7 //包含头文件
 8 
 9 #include <stdio.h>
10 
11 #include<stdlib.h>
12 
13 #include <assert.h>
14 
15  
16 
17  
18 
19 typedef int DataType;        //数据域的类型
20 
21  
22 
23 //复杂链表的数据结构
24 
25 typedef struct ComplexNode
26 
27 {
28 
29 DataType _data ;                                // 数据
30 
31 struct ComplexNode * _next;                // 指向下个节点的指针
32 
33 struct ComplexNode * _random;        // 指向随机节点(可以是链表中的任意节点 or 空)
34 
35 }ComplexNode;
36 
37  
38 
39 //创建一个复杂链表的结点
40 
41 ComplexNode * BuyComplexNode(DataType x);
42 
43  
44 
45 //打印复杂的单链表
46 
47 void Display(const ComplexNode * cplist);
48 
49  
50 
51 //复杂链表的复制
52 
53 ComplexNode * CopyComplexNode(ComplexNode * cplist);
54 
55  
56 
57 #endif//__COMPLEX__NODE__H__

具体功能实现complexnode.c

  1 #include "complexnode.h"
  2 
  3  
  4 
  5 //创建一个复杂链表的结点
  6 
  7 ComplexNode * BuyComplexNode(DataType x)
  8 
  9 {
 10 
 11 ComplexNode *cnode = (ComplexNode *)malloc(sizeof(ComplexNode));
 12 
 13 if(cnode == NULL)//创建失败
 14 
 15 {
 16 
 17 perror("BuyComplexNode()::malloc");
 18 
 19 return NULL;
 20 
 21 }
 22 
 23 //创建成功
 24 
 25 cnode->_data = x;
 26 
 27 cnode->_next = NULL;
 28 
 29 cnode->_random = NULL;
 30 
 31 return cnode;
 32 
 33 }
 34 
 35  
 36 
 37 //打印复杂的单链表
 38 
 39 void Display(const ComplexNode * cplist)
 40 
 41 {
 42 
 43 ComplexNode *pnode = cplist;
 44 
 45 while (pnode)
 46 
 47 {
 48 
 49 printf("%d::%d -->",pnode->_data,pnode->_random->_data);
 50 
 51 pnode = pnode->_next;
 52 
 53 }
 54 
 55 printf("over\\n");
 56 
 57  
 58 
 59 }
 60 
 61  
 62 
 63 //复杂链表的复制
 64 
 65 ComplexNode * CopyComplexNode(ComplexNode * cplist)
 66 
 67 {
 68 
 69  
 70 
 71 ComplexNode * pold = NULL;
 72 
 73 ComplexNode * pnew = NULL;
 74 
 75 ComplexNode * newlist = NULL;//指向新的复杂链表的头结点的指针
 76 
 77 pold = cplist;
 78 
 79 //创建一条新的复杂链表
 80 
 81 while(pold != NULL)
 82 
 83 {
 84 
 85 ComplexNode * new_node = BuyComplexNode(pold->_data);
 86 
 87 if(newlist == NULL)//当新的复杂链表中没有结点时
 88 
 89 {
 90 
 91 newlist = new_node;
 92 
 93 }
 94 
 95 else//当新的复杂链表有结点时
 96 
 97 {
 98 
 99 ComplexNode * node = newlist;
100 
101 while(node->_next != NULL)//找到最后一个结点
102 
103 {
104 
105 node = node->_next;
106 
107 }
108 
109 node->_next = new_node;//插入新的结点
110 
111 }
112 
113 pold = pold->_next;
114 
115  
116 
117 }//创建新的复杂链表结束
118 
119  
120 
121 //合并两条复杂链表
122 
123 pold = cplist;
124 
125 pnew = newlist;
126 
127 while (pold)
128 
129 {
130 
131 ComplexNode * curold = NULL;
132 
133 ComplexNode * curnew = NULL;
134 
135 curold = pold->_next;
136 
137 curnew = pnew->_next;
138 
139 if(pold->_next == NULL)
140 
141 {
142 
143 pold->_next = pnew;
144 
145 pold = curold;
146 
147 pnew = curnew;
148 
149 break;
150 
151 }
152 
153 pold->_next = pnew;
154 
155 pnew->_next = curold;
156 
157 pold = curold;
158 
159 pnew = curnew;
160 
161 }//合并两条复杂链表结束
162 
163  
164 
165 //让新创建的那条复杂链表上的所有结点的random指针指向相应的结点
166 
167 pold = cplist;
168 
169 pnew = newlist;
170 
171 while (pnew)
172 
173 {
174 
175 pnew->_random = pold->_random->_next;
176 
177 pold = pnew->_next;
178 
179 if(pold == NULL)//这是pnew的_next指针已经指向空
180 
181 {
182 
183 break;
184 
185 }
186 
187 pnew = pold->_next;
188 
189 }//结束
190 
191  
192 
193 //分离合并后的复杂链表
194 
195 pold = cplist;
196 
197 pnew = newlist;
198 
199 while (pold)
200 
201 {
202 
203 ComplexNode * curold = NULL;
204 
205 ComplexNode * curnew = NULL;
206 
207 if(pnew->_next == NULL)//已经分离完成
208 
209 {
210 
211 pold->_next = NULL;
212 
213 pnew->_next = NULL;
214 
215 break;
216 
217  
218 
219 }
220 
221 curold = pold->_next->_next;
222 
223 curnew = pnew->_next->_next;
224 
225  
226 
227 pold->_next = curold;
228 
229 pnew->_next = curnew;
230 
231 pold = curold;
232 
233 pnew = curnew;
234 
235 }//分离合并的复杂链表结束
236 
237  
238 
239 return newlist;
240 
241 }

 

测试代码test.c:

 1 #include "complexnode.h"
 2 
 3 //
 4 
 5 //复杂链表的复制。?个链表的每个节点,有?个指向next指针指向下?个节
 6 
 7 //点,还有?个random指针指向这个链表中的?个随机节点或者NULL,现在要
 8 
 9 //求实现复制这个链表,返回复制后的新链表。
10 
11 //ps: 复杂链表的结构
12 
13  
14 
15  
16 
17  
18 
19 void test()
20 
21 {
22 
23 ComplexNode * cplist;
24 
25 ComplexNode * copylist;
26 
27 ComplexNode * node1;
28 
29 ComplexNode * node2;
30 
31 ComplexNode * node3;
32 
33 ComplexNode * node4;
34 
35 cplist = BuyComplexNode(1);
36 
37 node1 = BuyComplexNode(2);
38 
39 node2 = BuyComplexNode(3);
40 
41 node3 = BuyComplexNode(4);
42 
43 node4 = BuyComplexNode(5);
44 
45 cplist->_next = node1;
46 
47 node1->_next = node2;
48 
49 node2->_next = node3;
50 
51 node3->_next = node4;
52 
53 cplist->_random = node3;
54 
55 node1->_random = node4;
56 
57 node2->_random = cplist;
58 
59 node3->_random = node1;
60 
61 node4->_random = node2;
62 
63 Display(cplist);
64 
65 copylist = CopyComplexNode(cplist);
66 
67 Display(copylist);
68 
69  
70 
71 }
72 
73 int main()
74 
75 {
76 
77 test();
78 
79 return 0;
80 
81 }

 

程序的运行结果如下图:

 技术分享

 

 

以上是关于C语言之复杂链表的复制(图示详解)的主要内容,如果未能解决你的问题,请参考以下文章

数据结构之超硬核热门复杂度数组链表OJ题2W+文字+图片详解

剑指offer(四十八)之复杂链表的复制

复杂链表的复制-剑指Offer

C语言反转单向链表的代码

剑指offer之复杂链表的复制

Java 剑指offer(35) 复杂链表的复制