什么是复杂链表?

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

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

  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. #include <stdio.h>
  8.  
  9. #include<stdlib.h>
  10.  
  11. #include <assert.h>
  12.  
  13. typedef int DataType; //数据域的类型
  14.  
  15. //复杂链表的数据结构
  16.  
  17. typedef struct ComplexNode
  18.  
  19. {
  20.  
  21. DataType _data ; // 数据
  22.  
  23. struct ComplexNode * _next; // 指向下个节点的指针
  24.  
  25. struct ComplexNode * _random; // 指向随机节点(可以是链表中的任意节点 or 空)
  26.  
  27. }ComplexNode;
  28.  
  29. //创建一个复杂链表的结点
  30.  
  31. ComplexNode * BuyComplexNode(DataType x);
  32.  
  33. //打印复杂的单链表
  34.  
  35. void Display(const ComplexNode * cplist);
  36.  
  37. //复杂链表的复制
  38.  
  39. ComplexNode * CopyComplexNode(ComplexNode * cplist);
  40.  
  41. #endif//__COMPLEX__NODE__H__

具体功能实现complexnode.c

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

测试代码test.c:

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

程序的运行结果如下图:

C语言之复杂链表的复制(图示详解)的更多相关文章

  1. IntelliJ IDEA 快捷键说明大全(中英对照、带图示详解)

    因为觉得网络上的 idea 快捷键不够详尽,所以特别编写了此篇文章,方便大家使用 idea O(∩_∩)O~ 其中的英文说明来自于 idea 的官网资料,中文说明主要来自于自己的领会和理解,英文说明只 ...

  2. php对象复制、clone、浅复制与深复制实例详解

    php对象复制.clone.浅复制与深复制实例详解 一.用clone(克隆)来复制对象$obj1 = new Object();$obj2 = clone $obj1;clone方法会触发对象里定义的 ...

  3. (转)python中调用R语言通过rpy2 进行交互安装配置详解

    python中调用R语言通过rpy2 进行交互安装配置详解(R_USER.R_HOME配置) 2018年11月08日 10:00:11 luqin_ 阅读数:753   python中调用R语言通过r ...

  4. C语言对文件的操作函数用法详解2

    fopen(打开文件) 相关函数 open,fclose 表头文件 #include<stdio.h> 定义函数 FILE * fopen(const char * path,const  ...

  5. C语言对文件的操作函数用法详解1

    在ANSIC中,对文件的操作分为两种方式,即: 流式文件操作 I/O文件操作 一.流式文件操作 这种方式的文件操作有一个重要的结构FILE,FILE在stdio.h中定义如下: typedef str ...

  6. 问题:oracle select into;结果:oracle SELECT INTO 和 INSERT INTO SELECT 两种表复制语句详解

    oracle SELECT INTO 和 INSERT INTO SELECT 两种表复制语句详解 (2011-07-08 08:59:47) 转载▼ 标签: it 分类: oracle 我们经常会遇 ...

  7. C语言--enum,typedef enum 枚举类型详解

    原文:http://z515256164.blog.163.com/blog/static/32443029201192182854300/ 有改动 C语言详解 - 枚举类型 注:以下全部代码的执行环 ...

  8. HTTP协议图示详解

    一.概念 协议是指计算机通信网络中两台计算机之间进行通信所必须共同遵守的规定或规则,超文本传输协议(HTTP)是一种通信协议,它允许将超文本标记语言(HTML)文档从Web服务器传送到客户端的浏览器. ...

  9. Redis 复制过程详解

    Redis 的复制功能分为同步( sync )和命令传播( command propagate )两个步骤: 同步用于将从服务器的数据库状态更新至主服务器当前所处的数据库状态. 命令传播则用于在主服务 ...

随机推荐

  1. PHP平台CMS系统Drupal小试身手----安装教程

    最近一直在研究基于Asp.Net MVC的CMS---Orchard,忽然新血来潮,看看多年不看的PHP平台的CMS,那好,就拿Drupal试试身手吧. 第一大招: 环境配置 + 安装. 1.环境配置 ...

  2. xml注释快捷键

    eclipse中编辑Java或C/C++文件时,注释的快捷键均为 "CTRL + / ",编辑xml文件时,该快捷键无效. eclipse XML 注释:CTRL + SHIFT ...

  3. 腾讯云万象优图每个账户提供50G的图片存储(支持黄图检测)

    文章由GIT博客迁移过来 程序下载地址(源码也在):点我下载 设计说明 10月20号晚上,准备写这么一个程序. 腾讯云万象优图每个账户提供50G的图片存储(支持黄图检测) 可以在截图之后,直接点击上传 ...

  4. Java反射机制剖析(四)-深度剖析动态代理原理及总结

    动态代理类原理(示例代码参见java反射机制剖析(三)) a)  理解上面的动态代理示例流程 a)  理解上面的动态代理示例流程 b)  代理接口实现类源代码剖析 咱们一起来剖析一下代理实现类($Pr ...

  5. APP为什么需要着陆页

    小编APP运营团队一直认为,虽然大多数的用户会在App Store或安卓应用商店中搜寻我们的应用,但也有许多用户会通过传统的PC端搜索来寻找答案.而且在APP营销中,为了更好的将用户转换为下载或购买, ...

  6. JMETER 不同线程组 变量值 的参数传递

    线程组 1   在线程组1中使用__setProperty函数设置jmeter属性值(此值为全局变量值),将所需变量值如${token}设置为jmeter属性值,即newtoken,示例: 1.添加- ...

  7. 【T-SQL】系列文章全文目录(2017-06-02更新)

    本系列[T-SQL]主要是针对T-SQL的总结. T-SQL基础 [T-SQL基础]01.单表查询-几道sql查询题 [T-SQL基础]02.联接查询 [T-SQL基础]03.子查询 [T-SQL基础 ...

  8. VR上天了!全景商业化落地了!——VR全景智慧城市

    几年前,VR创业公司SpaceVR就启动了旨在将宇航员视觉体验带给普通人的虚拟现实(VR)项目.SpaceVR计划将VR相机卫星送入太空,并将相机拍摄到的太空视频发送回地球,从而让VR用户身临其境地看 ...

  9. 以太坊的crypto模块--以太坊源码学习

    以太坊的crypto模块 该模块分为两个部分一个是实现sha3,一个是实现secp256k1(这也是比特币中使用的签名算法). 需要说明的是secp256k1有两种实现方式,一种是依赖libsecp2 ...

  10. Spring学习(16)--- 基于Java类的配置Bean 之 基于泛型的自动装配(spring4新增)

    例子: 定义泛型Store package javabased; public interface Store<T> { } 两个实现类StringStore,IntegerStore p ...