什么是复杂链表?

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

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

 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. Brief introduction to Cassandra 【Cassandra简介】

    From wikipedia  https://en.wikipedia.org/wiki/CAP_theorem In theoretical computer science, the CAP t ...

  2. angular页面缓存与页面刷新

      angularJS学习笔记:页面缓存与页面刷新 遇到的问题 现在存在这样一个问题,登录前与登录成功后是同一个页面,只不过通过ngIf来控制哪部分显示,图像信息如下: 所以,整体工作不是很难,无非就 ...

  3. SpringMVC中的java.lang.ClassNotFoundException: org.aspectj.weaver.BCException 调试过程记录

    报错原因 上文本描述 java.lang.NoClassDefFoundError: org/aspectj/weaver/BCException at java.lang.Class.getDecl ...

  4. 【shell脚本实例】shell脚本统计单词频率、出现次数最多的n个单词

    1. 统计的对象words.txt,每个单词占一行(从简考虑了~) zjd@ubuntu:~/test$ cat word.txt used this count mysql count this u ...

  5. 消息:SQL Server 2017(vNext)的第三个公开的CTP(社区技术预览版)发布了

    今天看到了一个新闻,跟大家分享一下,有兴趣的可以去尝试一下. SQL Server 2017 CTP3于5月23日发布了,详细版本号是6.7.55.0. 大家可以去安装试试.在下载页面,目前是SQL  ...

  6. 使用PostProcessBuild设定Unity产生的Xcode Project

    简单来说就是unity提供一套api去修改xcode项目工程配置以及修改plist文件内容(当unity build结束后, 会自动回调OnPostProcessBuild). 以下是一些用到的配置处 ...

  7. Asynchronous and Distributed Programming in R with the Future Package

    Every now and again someone comes along and writes an R package that I consider to be a 'game change ...

  8. Eclipse debug 调试快捷键

    F3  跳到光标所在的类或方法(按Ctrl+鼠标左键同样可以实现这一功能) F5  进到函数的内部 F6  单步调试 F7  从函数中退出 F8  调到下一个断点(不能使用时应该是和有道词典的快捷键冲 ...

  9. Ant + Jenkies +Tomcat 自动构建部署Web项目

    前言:博主资历尚浅,很多东西都还在刚起步学习的阶段,这几天开发任务比较轻,就在自己window系统下,模拟部署远程服务器,利用Jenkies + Ant + Tomcat 搭建了一个自动发布部署的环境 ...

  10. Eclipse导入项目常见问题----facet版本问题04

    问题如下: 解决办法 右击项目,找到最下面的properties,在搜索facet jdk版本问题(有个红色感叹号)01:http://blog.csdn.net/baidu_37107022/art ...