C语言之复杂链表的复制(图示详解)
什么是复杂链表?
复杂链表指的是一个链表有若干个结点,每个结点有一个数据域用于存放数据,还有两个指针域,其中一个指向下一个节点,还有一个随机指向当前复杂链表中的任意一个节点或者是一个空结点。今天我们要实现的就是对这样一个复杂链表复制产生一个新的复杂链表。
复杂链表的数据结构如下:
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语言之复杂链表的复制(图示详解)的更多相关文章
- IntelliJ IDEA 快捷键说明大全(中英对照、带图示详解)
因为觉得网络上的 idea 快捷键不够详尽,所以特别编写了此篇文章,方便大家使用 idea O(∩_∩)O~ 其中的英文说明来自于 idea 的官网资料,中文说明主要来自于自己的领会和理解,英文说明只 ...
- php对象复制、clone、浅复制与深复制实例详解
php对象复制.clone.浅复制与深复制实例详解 一.用clone(克隆)来复制对象$obj1 = new Object();$obj2 = clone $obj1;clone方法会触发对象里定义的 ...
- (转)python中调用R语言通过rpy2 进行交互安装配置详解
python中调用R语言通过rpy2 进行交互安装配置详解(R_USER.R_HOME配置) 2018年11月08日 10:00:11 luqin_ 阅读数:753 python中调用R语言通过r ...
- C语言对文件的操作函数用法详解2
fopen(打开文件) 相关函数 open,fclose 表头文件 #include<stdio.h> 定义函数 FILE * fopen(const char * path,const ...
- C语言对文件的操作函数用法详解1
在ANSIC中,对文件的操作分为两种方式,即: 流式文件操作 I/O文件操作 一.流式文件操作 这种方式的文件操作有一个重要的结构FILE,FILE在stdio.h中定义如下: typedef str ...
- 问题:oracle select into;结果:oracle SELECT INTO 和 INSERT INTO SELECT 两种表复制语句详解
oracle SELECT INTO 和 INSERT INTO SELECT 两种表复制语句详解 (2011-07-08 08:59:47) 转载▼ 标签: it 分类: oracle 我们经常会遇 ...
- C语言--enum,typedef enum 枚举类型详解
原文:http://z515256164.blog.163.com/blog/static/32443029201192182854300/ 有改动 C语言详解 - 枚举类型 注:以下全部代码的执行环 ...
- HTTP协议图示详解
一.概念 协议是指计算机通信网络中两台计算机之间进行通信所必须共同遵守的规定或规则,超文本传输协议(HTTP)是一种通信协议,它允许将超文本标记语言(HTML)文档从Web服务器传送到客户端的浏览器. ...
- Redis 复制过程详解
Redis 的复制功能分为同步( sync )和命令传播( command propagate )两个步骤: 同步用于将从服务器的数据库状态更新至主服务器当前所处的数据库状态. 命令传播则用于在主服务 ...
随机推荐
- Java读取ini配置
本文转载地址: http://www.cnblogs.com/Jermaine/archive/2010/10/24/1859673.html 不够通用,呵呵. 读取ini的配置的格式如下 ...
- $.when()方法翻译
地址:http://api.jquery.com/jQuery.when/ jQuery.when( deferreds ),returns Promise 正文 Description: Provi ...
- php原生curl接口的请求
/** * @desc 接口请求处理 * @date 2017/5/19 11:39 * @param [$url请求的接口地址,$way为false为get请求,true为post请求] * @au ...
- zabbix监控redis
导入监控模板 点击[configuration]-->[templates]-->[import],导入xml监控模板. 配置客户端key 在被监控的主机上,新建/etc/zabbix/z ...
- cef3和duilib简单仿有道词典学习
由于最近换工作的原因,也没啥事,就简单学习了一下cef3和duilib,楼主之前是做MFC框架下的windows开发的,对界面库和新的客户端开发模式也有所了解,现在的大部分客户端都是基本的客户端框架下 ...
- React-Native集成到已有项目中的总结
安装Python 从官网下载并安装python 2.7.x(3.x版本不行) 安装node.js 从官网下载node.js的官方V6.X.X版本或更高版本.安装完成后检测是否安装成功:node -v ...
- .Net开发的两个小技巧
一.@符号的妙用 1.可以作为保留关键字的标识符 C#规范当中,不允许使用保留关键字(class.bool等)当作普通的标识符来命名,这时候@符号作用就体现 出来了,可以通过@符号前缀把这些保留关键字 ...
- A comparison of local caches (2) 【本地缓存之比较 (2)】
接上一篇: A comparison of local caches (1) [本地缓存之比较 (1)] This article will compare the asynchronous loca ...
- Spring学习(8)--- @Autowired注解(一)
可以将@Autowired注解为“传统”的setter方法 package com.mypackage; import org.springframework.beans.factory.annota ...
- JavaScript实现图片拖拽、粘贴上传
前些日子为老婆做了一个web管理商品的工具,因为商品的图片比较多并且还需要剪裁图,为了上传图片方便加了一个拖拽.粘贴上传的功能. 我已经把代码整理出来放到GitHub上了,有兴趣的朋友可以下来玩玩. ...