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 在第二个设备上运行,那么在第一个设备上产生的任何数据结果在第二个 ...
随机推荐
- Android UI组件----AppWidget控件入门详解
Widget引入 我们可以把Widget理解成放置在桌面上的小组件(挂件),有了Widget,我们可以很方便地直接在桌面上进行各种操作,例如播放音乐. 当我们长按桌面时,可以看到Widget选项,如下 ...
- Hibernate组件映射
Hibernate联合主键映射以及组件映射 在Hibernate中联合主键的形成有两种可能:一种是由多对多映射形成的,多对多映射会形成第三张表,一般来说第三张表的主键是由其他两张表的主键构成的(比如学 ...
- 第10章 Java类的三大特性之一:多态
1.Java中的多态 多态是指对象的多种形态,主要包括这两种: 1.1引用多态 a.父类的引用可以指向本类的对象b.父类的引用可以指向子类的对象举个例子:父类Anmail,子类Dog,可以使用父类An ...
- HTML 学习笔记 JavaScript(数组)
1.数组的创建 var arrayObj = new Array(); //创建一个数组var arrayObj = new Array([size]); //创建一个数组并指定长度,注意不是上限,是 ...
- jmeter(六)元件的作用域与执行顺序
jmeter是一个开源的性能测试工具,它可以通过鼠标拖拽来随意改变元件之间的顺序以及元件的父子关系,那么随着它们的顺序和所在的域不同,它们在执行的时候,也会有很多不同. jmeter的test pla ...
- C#.NET 大型企业信息化系统集成快速开发平台 4.2 版本 - 防止暴力破解密码、提高大型信息系统安全
几十万人使用的系统.覆盖全国.每天营业额上好几个亿的.若信息安全方面太薄弱了.那将会是致命的打击.甚至威胁到企业的正常运转.从国家层面到企业级别大家都在重视信息的安全.可控. 运行速度慢一点点可以忍受 ...
- AppBox升级进行时 - 如何向OrderBy传递字符串参数(Entity Framework)
AppBox 是基于 FineUI 的通用权限管理框架,包括用户管理.职称管理.部门管理.角色管理.角色权限管理等模块. Entity Framework提供的排序功能 再来回顾一下上篇文章,加载用户 ...
- 当泛型方法推断,扩展方法遇到泛型类型in/out时。。。
说到泛型方法,这个是.net 2.0的时候引入的一个重要功能,c#2.0也对此作了非常好的支持,可以不需要显试的声明泛型类型,让编译器自动推断,例如: void F<T>(T value) ...
- 什么是Jedis?
Jedis 是 Redis 官方首选的 Java 客户端开发包. 实例方法: 1 import redis.clients.jedis.* 1 2 3 Jedis jedis = new Jedis( ...
- Ubuntu 下,修改 Mac address
ifconfig // check Mac address sudo ifconfig eth0 down sudo ifconfig eth0 hw ether xx:xx:xx:xx: ...