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 在第二个设备上运行,那么在第一个设备上产生的任何数据结果在第二个 ...
随机推荐
- RS-232, RS-422, RS-485 Serial Communication General Concepts(转载)
前面转载的几篇文章重点介绍了UART及RS-232.在工控领域除了RS-232以外,常用的串行通信还有RS-485.本文转载的文章重点介绍了RS-232.RS-422和RS-485. Overview ...
- NYOJ 205
大数取模算法: 这个又不同于幂取模算法,对于几百万位的数字取模,直接的方法是行不通的.最好利用数论的知识 (a*b)%c = ((a%c)*b)%c ;利用这个公式我们只要从n的一次方开始不断计算,乘 ...
- Hibernate 错题分析
- oracle连接方式、创建数据库用户、忘记数据库密码、用户锁定
一.oracle六种连接方式 ①myEclipse中 打开myEclipse,window----show view----Other---输入DB点击DB browser 选中右键New.出现如下页 ...
- [No000069]Javascript中this关键字详解
Quiz 请看下面的代码,最后alert出来的是什么呢?(chrome下按F12,选择Console直接复制粘贴运行) var name = "Bob"; var nameObj ...
- Java中的instanceof关键字
instanceof是Java的一个二元操作符,和==,>,<是同一类东东.由于它是由字母组成的,所以也是Java的保留关键字.它的作用是测试它左边的对象是否是它右边的类的实例,返回boo ...
- ASP.NET Boilerplate
I want it to be a start point for all we .NET developers, so, it will be good to develop it together ...
- 基于spring-boot的rest微服务框架
周末在家研究spring-boot,参考github上的一些开源项目,整了一个rest微服务框架,取之于民,用之于民,在github上开源了,地址如下: https://github.com/yjmy ...
- FineUI小技巧(6)自定义页面回发
前言 FineUI中的绝大部分回发事件都是由控件触发了,比如按钮的点击事件,下拉列表的改变事件,表格的排序分页事件.但有时我们可能会要自己触发页面回发,这时就要知道怎么使用 JavaScript 来做 ...
- Mysql索引PRIMARY、NORMAL、UNIQUE、FULLTEXT 区别和使用场合
索引 数据库的索引就像一本书的目录,能够加快数据库的查询速度. MYSQL索引有四种PRIMARY.INDEX.UNIQUE.FULLTEXT, 其中PRIMARY.INDEX.UNIQUE是一类,F ...