什么是复杂链表?

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

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

 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. NancyFx 2.0的开源框架的使用-CustomModule(自定义模块)

    NancyFx框架的自定义模块 新建一个空的Web项目 然后通过NuGet库安装下面的包 Nancy Nancy.Hosting.Aspnet 然后添加Models,Module,Views三个文件夹 ...

  2. 几张图带你轻轻松松了解小程序和APP的区别

    微信"小程序"的公测一开放,立即在朋友圈刷屏无数,仿佛人人都在互联网圈.但是因为微信限制,程序还不能发布使用,所以也极少人看到真正的小程序是怎么样的. 小程序驿站专注微信小程序的开 ...

  3. jsp的自定义标签 控制jsp内容显示

    引入方式示例 <%@ taglib prefix="fns" uri="/WEB-INF/tlds/fns.tld" %> tld文件 <?x ...

  4. 编写原生Node.js模块

    导语:当Javascript的性能需要优化,或者需要增强Javascript能力的时候,就需要依赖native模块来实现了. 应用场景 日常工作中,我们经常需要将原生的Node.js模块做为依赖并在项 ...

  5. php中的数组遍历的几种方式

    [(重点)数组循环遍历的四种方式]   1.使用for循环遍历数组     conut($arr);用于统计数组元素的个数.     for循环只能用于遍历,纯索引数组!!!!     如果存在关联数 ...

  6. hdu3715

    hdu3715 题意 给出一个递归的伪代码,当 x[a[dep]] + x[b[dep]] != c[dep],就向下递归,给出a,b,c数组的值 问 dep 最大多少.其中 0 <= c[i] ...

  7. 最新Hadoop Shell完全讲解

    本文为原创博客,转载请注明出处:http://www.cnblogs.com/MrFee/p/4683953.html    1.appendToFile   功能:将一个或多个源文件系统的内容追加至 ...

  8. [IR] String Matching

    BWT KMP Boyer-Moore BWT [IR] BWT+MTF+AC 中已经介绍了BWT (Burrows–Wheeler_transform)数据转换算法, 这种变换方式不仅方便压缩,同时 ...

  9. c++ const char *[] or char [][]

    ]={"hello","world"}; ]={"hello"};char (*ch3)[6]= ch1; std::cout<< ...

  10. sublime text 快捷收集

    1. 文件快速导航: 这是sublime上面很好用的功能之一,ctrl+p可以调出窗口,菜单上的解释是gotoanythings ,确实如其所言,调出窗口后,直接输入关键字,可以在已打开的项目文件夹中 ...