C和指针 第十二章 使用结构和指针 双链表和语句提炼
双链表中每个节点包含指向当前和之后节点的指针,插入节点到双链表中需要考虑四种情况:
1、插入到链表头部
2、插入到链表尾部
3、插入到空链表中
4、插入到链表内部
#include <stdio.h>
#include <stdlib.h>
#define TRUE 1
#define FALSE 0 //指针fwd指向前一个节点,bwd指向后一个节点
typedef struct NODE {
struct NODE *fwd;
struct NODE *bwd;
int value;
} Node; //插入value到双链表中,rootPtr为指向节点的指针
int doubleLinklistInsert(Node *rootPtr, int value)
{
Node *this;
Node *next;
Node *newNode; for(this = rootPtr; (next = this -> fwd) != NULL; this = next){
//如果节点值已经存在
if(next -> value == value){
return FALSE;
}
//找到插入位置
if(next -> value > value){
break;
}
} //分配内存
newNode = (Node *)malloc(sizeof(Node));
if(newNode == NULL){
return FALSE;
} newNode -> value = value; /*插入节点一共四种情况
1.插入到头部
2.插入到尾部
3.插入到中间
4.插入到空链表中
*/
//如果插入到头部部或者内部
if(next != NULL){
//插入到内部
if(this != rootPtr){
newNode -> fwd = next;
newNode -> bwd = this;
this -> fwd = newNode;
next -> bwd = newNode;
}else{
//插入到头部,newNode的bwd为NULL
newNode -> fwd = next;
newNode -> bwd = NULL;
rootPtr -> fwd = newNode;
next -> bwd = newNode;
}
}else{
//插入到尾部或者空表中
if(this != rootPtr){
//插入到尾部,修改根指针的bwd和fwd
newNode -> fwd = NULL;
newNode -> bwd = this;
this -> fwd = newNode;
rootPtr -> bwd = newNode;
}else{
//插入到空链表中
newNode -> fwd = NULL;
newNode -> bwd = NULL;
this -> fwd = newNode;
this -> bwd = newNode;
}
} return TRUE;
} int main()
{
Node third;
Node second;
Node first; third = (Node){NULL, &second, 4};
second = (Node){&third, &first, 2};
first = (Node){&second, NULL, 1}; Node root = {&first, &third, -1};
Node *rootPtr = &root; doubleLinklistInsert(rootPtr, 35);
doubleLinklistInsert(rootPtr, -10);
doubleLinklistInsert(rootPtr, 3); rootPtr = &root;
while((rootPtr = rootPtr -> fwd) != NULL){
printf("%d\t", rootPtr -> value);
}
return 0;
}
运行:

优化:
1.语句提炼
对于下面的代码可以从if语句中,提取出共同的部分。
if(x = 3){
i = 1;
something;
}else{
i = 1;
something different;
}
将共同的i=1,提取出if语句
i = 1;
if(x = 3){
something;
}else{
something different;
}
代码提炼:提取共同项
if(next != NULL){
newNode -> fwd = next;
next -> bwd = newNode;
//插入到内部
if(this != rootPtr){
newNode -> bwd = this;
this -> fwd = newNode;
}else{
//插入到头部,newNode的bwd为NULL
newNode -> bwd = NULL;
rootPtr -> fwd = newNode;
}
}else{
//插入到尾部或者空表中
newNode -> fwd = NULL;
this -> fwd = newNode;
if(this != rootPtr){
//插入到尾部,修改根指针的bwd和fwd
newNode -> bwd = this;
rootPtr -> bwd = newNode;
}else{
//插入到空链表中
newNode -> bwd = NULL;
this -> bwd = newNode;
}
}
对于下面的情况
if(field!= NULL){
pointer = field;
}else{
pointer=NULL;
}
//第二种情况field等于NULL,所以上面条件语句可以写成
pointer =field;
要找出看起来虽然不一样,但逻辑上是相同的代码,进行简化,这里第二个else中this此时是等于rootPtr的,所以相同, this转换成rootPtr,然后提取出。提取之后两个条件语句中都有:
if(this != rootPtr){
//插入到尾部,修改根指针的bwd和fwd
newNode -> bwd = this;
this -> fwd = newNode;
}else{
//插入到空链表中
newNode -> bwd = NULL;
rootPtr -> fwd = newNode;
}
提取出来:
if(this != rootPtr){
//插入到尾部,修改根指针的bwd和fwd
newNode -> bwd = this;
this -> fwd = newNode;
}else{
//插入到空链表中
newNode -> bwd = NULL;
rootPtr -> fwd = newNode;
}
if(next != NULL){
newNode -> fwd = next;
next -> bwd = newNode;
//插入到内部
}else{
//插入到尾部或者空表中
newNode -> fwd = NULL;
rootPtr -> bwd = newNode;
}
下面的第二个else中的next是NULL,所以NULL可以转换一下,继续提取出来:
newNode -> fwd = next;
if(next != NULL){
next -> bwd = newNode;
}else{
rootPtr -> bwd = newNode;
} if(this != rootPtr){
newNode -> bwd = this;
this -> fwd = newNode;
}else{
newNode -> bwd = NULL;
rootPtr -> fwd = newNode;
}
提取出来,最终简化版:
#include <stdio.h>
#include <stdlib.h>
#define TRUE 1
#define FALSE 0 //指针fwd指向前一个节点,bwd指向后一个节点
typedef struct NODE {
struct NODE *fwd;
struct NODE *bwd;
int value;
} Node; //插入value到双链表中,rootPtr为指向节点的指针
int doubleLinklistInsert(Node *rootPtr, int value)
{
Node *this;
Node *next;
Node *newNode; for(this = rootPtr; (next = this -> fwd) != NULL; this = next){
//如果节点值已经存在
if(next -> value == value){
return FALSE;
}
//找到插入位置
if(next -> value > value){
break;
}
} //分配内存
newNode = (Node *)malloc(sizeof(Node));
if(newNode == NULL){
return FALSE;
} newNode -> value = value; /*插入节点一共四种情况
1.插入到头部
2.插入到尾部
3.插入到中间
4.插入到空链表中
*/
//如果插入到头部部或者内部 newNode -> fwd = next;
if(next != NULL){
next -> bwd = newNode;
}else{
rootPtr -> bwd = newNode;
} if(this != rootPtr){
newNode -> bwd = this;
this -> fwd = newNode;
}else{
newNode -> bwd = NULL;
rootPtr -> fwd = newNode;
} return TRUE;
} int main()
{
Node third;
Node second;
Node first; third = (Node){NULL, &second, 4};
second = (Node){&third, &first, 2};
first = (Node){&second, NULL, 1}; Node root = {&first, &third, -1};
Node *rootPtr = &root; doubleLinklistInsert(rootPtr, 35);
doubleLinklistInsert(rootPtr, -10);
doubleLinklistInsert(rootPtr, 3); rootPtr = &root;
while((rootPtr = rootPtr -> fwd) != NULL){
printf("%d\t", rootPtr -> value);
}
return 0;
}
运行:

通过提炼语句,消除if语句中的重复语句。
C和指针 第十二章 使用结构和指针 双链表和语句提炼的更多相关文章
- C和指针 第十二章 使用结构和指针
链表是一种常用的数据结构,每个节点通过链或者指针链接在一起,程序通过间接指针访问链表中的节点. typedef struct Node { //指向下一个节点的指针 struct Node *next ...
- C和指针 第十二章 结构体 习题
12.3 重新编写12.7,使用头和尾指针分别以一个单独的指针传递给函数,而不是作为一个节点的一部分 #include <stdio.h> #include <stdlib.h> ...
- C和指针 第十二章 结构体 整体赋值 error: expected expression
定义结构体后整体赋值时发生错误 typedef struct NODE { struct NODE *fwd; struct NODE *bwd; int value; } Node; //声明变量 ...
- 《Linux命令行与shell脚本编程大全》第十二章 使用结构化命令
许多程序要就对shell脚本中的命令施加一些逻辑控制流程. 结构化命令允许你改变程序执行的顺序.不一定是依次进行的 12.1 使用if-then语句 如下格式: if command then ...
- C和指针 (pointers on C)——第十二章:利用结构和指针
第十二章 利用结构和指针 这章就是链表.先单链表,后双向链表. 总结: 单链表是一种使用指针来存储值的数据结构.链表中的每一个节点包括一个字段,用于指向链表的下一个节点. 有一个独立的根指针指向链表的 ...
- perl5 第十二章 Perl5中的引用/指针
第十二章 Perl5中的引用/指针 by flamephoenix 一.引用简介二.使用引用三.使用反斜线(\)操作符四.引用和数组五.多维数组六.子程序的引用 子程序模板七.数组与子程序八.文件句 ...
- [CSAPP笔记][第十二章并发编程]
第十二章 并发编程 如果逻辑控制流在时间上是重叠,那么它们就是并发的(concurrent).这种常见的现象称为并发(concurrency). 硬件异常处理程序,进程和Unix信号处理程序都是大家熟 ...
- C primer plus 第五版十二章习题
看完C prime plus(第五版)第十二章,随带完成了后面的习题. 1.不使用全局变量,重写程序清单12.4的程序. 先贴出12.4的程序,方便对照: /* global.c --- 使用外部变量 ...
- 《OpenCL异构并行编程实战》补充笔记散点,第五至十二章
▶ 第五章,OpenCL 的并发与执行模型 ● 内存对象与上下文相关而不是与设备相关.设备在不同设备之间的移动如下,如果 kernel 在第二个设备上运行,那么在第一个设备上产生的任何数据结果在第二个 ...
随机推荐
- FTP协议
1. FTP协议 什么是FTP呢?FTP 是 TCP/IP 协议组中的协议之一,是英文File Transfer Protocol的缩写. 该协议是Internet文件传送的基础,它由一系列规格说明文 ...
- SQLMAP大全
转自:http://blog.csdn.net/zsf1235/article/details/50974194 本人小白,初次认识sqlmap,很多都是转载资料,只是学习研究一下! 练习的网站可以用 ...
- jquery easyui 1.4.1 验证时tooltip 的位置调整
现象是在表单中如果显示两列控件,右边的控件是combo,combobox 等右边有按钮的,宽度为100%时,验证不通过的tooltip 显示位置不准确如下图所示 打开 jquery.easyui-1. ...
- ReactNative新手学习之路01-创建项目开始
新手学习之路01-创建项目开始 小菜鸟准备学习RN开发,决定写下自己的学习历程,方便其他也想要学习RN的人,后期会持续更新写下自己所有学习经历,一步步从菜鸟成长成业内高手.开发环境准备,本文默认环境已 ...
- 创意十足的web布局及交互设计
富有灵感和创意的设计与一般设计的区别在于,它不那么容易被想到和实现,一旦它被实现,一个非常有趣并且迷人的网站就诞生了. 网站几乎每天都能见到,但是不是每一个网站你都会说“真希望我也能想到过!” 设计者 ...
- IE浏览器中Image对象onload失效的解决办法
作为WEB设计者,为了在网页展示上加强用户体验,经常会利用图象载入显示状态方法,这自然需要Image对象的onload事件. 在firefox浏览器下完成开发后,可是在IE浏览器中进行调试总不能被调用 ...
- 机器学习&数据挖掘笔记_16(常见面试之机器学习算法思想简单梳理)
前言: 找工作时(IT行业),除了常见的软件开发以外,机器学习岗位也可以当作是一个选择,不少计算机方向的研究生都会接触这个,如果你的研究方向是机器学习/数据挖掘之类,且又对其非常感兴趣的话,可以考虑考 ...
- 淘宝WAP版小BUG分析
前几天发现的一个淘宝WAP版的小BUG,就是用桌面版chrome看的时候产品评价中的图片显示不出来,都是图裂了. 这是什么原因呢?图片为什么会显示不出来呢?淘宝的技术人员.测试人员不可能没发现啊.开启 ...
- 什么是Jedis?
Jedis 是 Redis 官方首选的 Java 客户端开发包. 实例方法: 1 import redis.clients.jedis.* 1 2 3 Jedis jedis = new Jedis( ...
- logback 配置详解
一:根节点<configuration>包含的属性: scan: 当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true. scanPeriod: 设置监测配置文 ...