什么是复杂链表?

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

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

 typedef int DataType;        //数据域的类型

 //复杂链表的数据结构

 typedef struct ComplexNode

 {

 DataType _data ;                     // 数据

 struct ComplexNode * _next;          // 指向下个节点的指针

 struct ComplexNode * _random;        // 指向随机节点(可以是链表中的任意节点 or 空)

 }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:

 #ifndef __COMPLEX__NODE__H__

 #define __COMPLEX__NODE__H__

 //包含头文件

 #include <stdio.h>

 #include<stdlib.h>

 #include <assert.h>

 typedef int DataType;        //数据域的类型

 //复杂链表的数据结构

 typedef struct ComplexNode

 {

 DataType _data ;                                // 数据

 struct ComplexNode * _next;                // 指向下个节点的指针

 struct ComplexNode * _random;        // 指向随机节点(可以是链表中的任意节点 or 空)

 }ComplexNode;

 //创建一个复杂链表的结点

 ComplexNode * BuyComplexNode(DataType x);

 //打印复杂的单链表

 void Display(const ComplexNode * cplist);

 //复杂链表的复制

 ComplexNode * CopyComplexNode(ComplexNode * cplist);

 #endif//__COMPLEX__NODE__H__

具体功能实现complexnode.c

 #include "complexnode.h"

 //创建一个复杂链表的结点

 ComplexNode * BuyComplexNode(DataType x)

 {

 ComplexNode *cnode = (ComplexNode *)malloc(sizeof(ComplexNode));

 if(cnode == NULL)//创建失败

 {

 perror("BuyComplexNode()::malloc");

 return NULL;

 }

 //创建成功

 cnode->_data = x;

 cnode->_next = NULL;

 cnode->_random = NULL;

 return cnode;

 }

 //打印复杂的单链表

 void Display(const ComplexNode * cplist)

 {

 ComplexNode *pnode = cplist;

 while (pnode)

 {

 printf("%d::%d -->",pnode->_data,pnode->_random->_data);

 pnode = pnode->_next;

 }

 printf("over\n");

 }

 //复杂链表的复制

 ComplexNode * CopyComplexNode(ComplexNode * cplist)

 {

 ComplexNode * pold = NULL;

 ComplexNode * pnew = NULL;

 ComplexNode * newlist = NULL;//指向新的复杂链表的头结点的指针

 pold = cplist;

 //创建一条新的复杂链表

 while(pold != NULL)

 {

 ComplexNode * new_node = BuyComplexNode(pold->_data);

 if(newlist == NULL)//当新的复杂链表中没有结点时

 {

 newlist = new_node;

 }

 else//当新的复杂链表有结点时

 {

 ComplexNode * node = newlist;

 while(node->_next != NULL)//找到最后一个结点

 {

 node = node->_next;

 }

 node->_next = new_node;//插入新的结点

 }

 pold = pold->_next;

 }//创建新的复杂链表结束

 //合并两条复杂链表

 pold = cplist;

 pnew = newlist;

 while (pold)

 {

 ComplexNode * curold = NULL;

 ComplexNode * curnew = NULL;

 curold = pold->_next;

 curnew = pnew->_next;

 if(pold->_next == NULL)

 {

 pold->_next = pnew;

 pold = curold;

 pnew = curnew;

 break;

 }

 pold->_next = pnew;

 pnew->_next = curold;

 pold = curold;

 pnew = curnew;

 }//合并两条复杂链表结束

 //让新创建的那条复杂链表上的所有结点的random指针指向相应的结点

 pold = cplist;

 pnew = newlist;

 while (pnew)

 {

 pnew->_random = pold->_random->_next;

 pold = pnew->_next;

 if(pold == NULL)//这是pnew的_next指针已经指向空

 {

 break;

 }

 pnew = pold->_next;

 }//结束

 //分离合并后的复杂链表

 pold = cplist;

 pnew = newlist;

 while (pold)

 {

 ComplexNode * curold = NULL;

 ComplexNode * curnew = NULL;

 if(pnew->_next == NULL)//已经分离完成

 {

 pold->_next = NULL;

 pnew->_next = NULL;

 break;

 }

 curold = pold->_next->_next;

 curnew = pnew->_next->_next;

 pold->_next = curold;

 pnew->_next = curnew;

 pold = curold;

 pnew = curnew;

 }//分离合并的复杂链表结束

 return newlist;

 }

测试代码test.c:

 #include "complexnode.h"

 //

 //复杂链表的复制。?个链表的每个节点,有?个指向next指针指向下?个节

 //点,还有?个random指针指向这个链表中的?个随机节点或者NULL,现在要

 //求实现复制这个链表,返回复制后的新链表。

 //ps: 复杂链表的结构

 void test()

 {

 ComplexNode * cplist;

 ComplexNode * copylist;

 ComplexNode * node1;

 ComplexNode * node2;

 ComplexNode * node3;

 ComplexNode * node4;

 cplist = BuyComplexNode();

 node1 = BuyComplexNode();

 node2 = BuyComplexNode();

 node3 = BuyComplexNode();

 node4 = BuyComplexNode();

 cplist->_next = node1;

 node1->_next = node2;

 node2->_next = node3;

 node3->_next = node4;

 cplist->_random = node3;

 node1->_random = node4;

 node2->_random = cplist;

 node3->_random = node1;

 node4->_random = node2;

 Display(cplist);

 copylist = CopyComplexNode(cplist);

 Display(copylist);

 }

 int main()

 {

 test();

 return ;

 }

程序的运行结果如下图:

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. 深入理解Struts2----数据校验

    在表现层的数据处理方面主要分为两种类型,一种是类型转换,这点我们上篇已经简单介绍过,另外一种则是我们本篇文章将要介绍的:数据校验.对于我们的web应用,我们经常需要和用户进行交互收集用户信息,那么无论 ...

  2. Junit 入门使用教程

    1.Junit 是什么? JUnit是一个Java语言的单元测试框架.它由Kent Beck和Erich Gamma建立,逐渐成为源于Kent Beck的sUnit的xUnit家族中最为成功的一个JU ...

  3. 微信小程序大全(下)(最新整理 建议收藏)

  4. Python之向日志输出中添加上下文信息

    除了传递给日志记录函数的参数(如msg)外,有时候我们还想在日志输出中包含一些额外的上下文信息.比如,在一个网络应用中,可能希望在日志中记录客户端的特定信息,如:远程客户端的IP地址和用户名.这里我们 ...

  5. VR全景智慧城市搭建掀起实体市场潮流

    在互联网时代的今天,用户体验至上,全景智慧城市搭建作为一个新型的科技展示技术,通过新颖的广告方式更能吸引用户眼球,足不出户,观看现场实景,达到沉浸式体验.在这样的大环境下,全景智慧城市搭建开启了VR全 ...

  6. FTP主动模式和被动模式的区别

    基础知识: FTP只通过TCP连接,没有用于FTP的UDP组件.FTP不同于其他服务的是它使用了两个端口, 一个数据端口和一个命令端口(或称为控制端口).通常21端口是命令端口,20端口是数据端口.当 ...

  7. javascript痛点之二作用域链

    1.执行环境(执行上下文) 先看段代码 var a = 10; var b = 20; function cc(){ var c = 30; alert("b="+b); } cc ...

  8. sql 中三大范式详解

     1 第一范式(1NF)    在任何一个关系数据库中,第一范式(1NF)是对关系模式的基本要求,不满足第一范式(1NF)的数据库就不是关系数据库.     所谓第一范式(1NF)是指数据库表的每一列 ...

  9. css3转盘抽奖

    做到一个活动,需要转盘抽奖,于是想到使用css3的动画效果,其中主要包含transition的动画过渡,transform的rotate的旋转效果,在这里只用到2d的旋转, 特别强调的是,因为需要和后 ...

  10. Edison与Arduino通过USB对接通信

    虽然Edison本身就装在一块Arduino扩展板上,但当要接的传感器太多了的时候一个扩展板也不够用了.因此需要再用一Arduino板扩展功能.而两者需要通信才能达到一个整体的效果,因此这里介绍如何用 ...