什么是复杂链表?

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

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

 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. arm处理器

    arm处理器 arm处理器相关 1.体系架构定义了指令集(ISA)和基于这一体系结构下处理器的编程模型. arm卖的是架构或者已经设计好的公版ip核 卖给苹果高通的是架构,需要苹果高通通过架构设计自己 ...

  2. select多用户之间通信

    查看记录:10/20   今天又重新看了一下程序,觉得ListenKeyboard这个函数写的很好.利用select监听键盘,成功的解决了 必须输入才会刷新消息的问题.这样等待15秒后也可刷新消息,效 ...

  3. 深入学习webpack(一)

    深入学习webpack(一) 模块化的相关库和工具已经很多了,包括require.js.sea.js和一些工程化工具webpack.gulp.grant.那么我们该如何选择呢? 其实,我们只需要掌握了 ...

  4. php jquery+ajax写批量删除

      为了美观,我还是引入了bootstrap的模态框,我引入的是自己的数据库 library中的一张表 名为:maninfo表 是一张个人信息表  表的加载我就不写了,比较简单,  大概写一下需要的按 ...

  5. 关于jQuery插件imgAreaSelect基础讲解

    关于ImgAreaSelect,  是一jQuery插件,它支持用户通过鼠标拖曳选择图片的一部分,如图片拖曳.图片编辑等~~来具体看一下 1.先下载imgAreaSelect插件 下载地址: 英文:h ...

  6. .Net Core应用搭建的分布式邮件系统设计

    本篇分享的是由NetCore搭建的分布式邮件系统,主要采用NetCore的Api和控制台应用程序,由于此系统属于公司的所以这里只能分享设计图和一些单纯不设计业务的类或方法: 为什么要在公司中首例采用N ...

  7. 创建发布自己的npm包

    我们基于nodejs平台上面的npm上,可以随意下载很多npm安装包.那我们如何创建自己的npm包呢?很简单,废话少说,开始做~ 开始做之前nodejs默认是要安装的,怎么安装自行百度其他教程. 首先 ...

  8. 简单的用jQuery做遮罩效果

    <!DOCTYPE html><html><head lang="en"> <meta charset="UTF-8" ...

  9. PF2.1版本总结,在设计过程中遇到的问题以及技术分享

    在距离上一次的版本发布已经过去4个月的时间,因为个人的能力以及时间有限,所以这次的版本会推迟这么久.可是无论怎样,PF2.1带着自身的完善总算不负所望推出.在这次的版本调整中让我深有体会到了程序设计中 ...

  10. glmnetUtils: quality of life enhancements for elastic net regression with glmnet

    The glmnetUtils package provides a collection of tools to streamline the process of fitting elastic ...