12.3 重新编写12.7,使用头和尾指针分别以一个单独的指针传递给函数,而不是作为一个节点的一部分

#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; /*传入指向 头部和尾部节点的指针 的指针,四种情况
* 插入到表头,
* 插入到表尾,
* 插入到空表中,
* 插入到表中,前三个都需要修改headPtr或tailPtr指针
*/
int doubleLinklistInsert(Node **headPtr, Node **tailPtr, int value)
{
Node *this = *headPtr;
Node *newNode; while( this != NULL && this -> value < value){
this = this -> fwd;
} newNode = (Node *)malloc(sizeof(Node));
newNode -> value = value; if(this == NULL){
//插入到表尾,或者空表中
if(this == *headPtr){
//插入到空表
*headPtr = newNode;
*tailPtr = newNode;
newNode -> fwd = NULL;
newNode -> bwd = NULL;
}else{
//插入到表尾
newNode -> fwd = NULL;
//原来的表尾元素为当前节点的前节点
newNode -> bwd = *tailPtr;
(*tailPtr) -> fwd = newNode;
//更新尾节点指针
*tailPtr = newNode;
}
}else{
//插入到表头,或者表中
if(this == *headPtr){
//插入到表头
newNode -> bwd = NULL;
//原来的表头变成第二个节点
newNode -> fwd = *headPtr;
(*headPtr) -> bwd = newNode;
//更新表头
*headPtr = newNode;
}else{
//插入到非空表中this位置的前面
newNode -> fwd = this;
newNode -> bwd = this -> bwd;
this -> bwd -> 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 *head = &first;
Node *tail = &third; doubleLinklistInsert(&head, &tail, 35);
doubleLinklistInsert(&head, &tail, 3);
doubleLinklistInsert(&head, &tail, -10); Node *rootPtr = head;
while(rootPtr != NULL){
printf("%d\t", rootPtr -> value);
rootPtr = rootPtr -> fwd;
}
return 0;
}

  运行:

12.4 编写函数反序排列单链表所有节点。

#include <stdio.h>
#include <stdlib.h>
#define TRUE 1
#define FALSE 0 typedef struct Node {
struct Node *next;
int value;
} Linklist; Linklist *sll_reverse(Linklist *first)
{
if(first == NULL){
return NULL;
} Linklist *current = first;
Linklist *next;
Linklist *pre;
Linklist *morePre = NULL; while((next = current -> next) != NULL){
//循环移动当前指向的节点
pre = current;
current = next;
//修改前一节点的next指针为前前节点
pre -> next = morePre;
//移动前前节点morePre的指针
morePre = pre;
} //如果为单个节点之间返回
if(current == first){
return first;
}else{
//修改最后一个节点的指针,作为头指针返回原来的最后一个节点的位置
current -> next = pre;
return current;
}
} int main()
{
Linklist third = {NULL, 4};
Linklist second = {&third, 3};
Linklist first = {&second, 2};
Linklist *head = &first; head = sll_reverse(head); while (head != NULL){
printf("%d\t", head -> value);
head = head -> next;
}
return 0;
}

  运行:

12.5 编写程序,从一个单链表中删除一个节点,第一个参数为指向链表头部的指针的指针

#include <stdio.h>
#include <stdlib.h>
#define TRUE 1
#define FALSE 0 typedef struct Node {
struct Node *next;
int value;
} Linklist; //从first指向的链表中删除节点node
int sll_delete(Linklist **first, Linklist *node)
{
Linklist **ptr = first;
//Ptr为指向 next字段的 指针
while(*ptr != NULL && *ptr != node){
ptr = &((*ptr) -> next);
}
//如果没有找到
if(*ptr == NULL){
return FALSE;
}else{
//如果找到了,变更前节点指向
*ptr = (*ptr) -> next;
//释放节点内存
free(*ptr);
     return FALSE;
}
} int main()
{
Linklist third = {NULL, 3};
Linklist second = {&third, 2};
Linklist first = {&second, 1};
Linklist *headPtr = &first; Linklist *head = headPtr;
while (head != NULL){
printf("%d\t", head -> value);
head = head -> next;
}
printf("\n"); sll_delete(&headPtr, &second);
head = headPtr;
while (head != NULL){
printf("%d\t", head -> value);
head = head -> next;
}
printf("\n"); sll_delete(&headPtr, &first);
head = headPtr;
while (head != NULL){
printf("%d\t", head -> value);
head = head -> next;
}
printf("\n"); sll_delete(&headPtr, &third);
head = headPtr;
while (head != NULL){
printf("%d\t", head -> value);
head = head -> next;
}
return 0;
}

  

运行:

12.6 双链表中移除节点,第一个参数为指向链表头部的指针,

#include <stdio.h>
#include <stdlib.h>
#define TRUE 1
#define FALSE 0 typedef struct Node {
struct Node *next;
int value;
} Linklist; //从first指向的链表中删除节点node
int sll_delete(Linklist *first, Linklist *node)
{
Linklist *pre = NULL;
Linklist *cur = first; while(cur != NULL && cur != node){
pre = cur;
cur = cur -> next;
} //如果没有找到
if(cur == NULL){
return FALSE;
}else if(cur == first){
//此时first是传值传入,只可以修改头指针指向的值,修改为第二个节点
*first = *(cur -> next);
free(node);
return TRUE;
}else{
pre -> next = cur -> next;
free(node);
return TRUE;
}
} int main()
{
Linklist third = {NULL, 3};
Linklist second = {&third, 2};
Linklist first = {&second, 1};
Linklist *headPtr = &first; Linklist *head = headPtr;
while (head != NULL){
printf("%d\t", head -> value);
head = head -> next;
}
printf("\n"); sll_delete(headPtr, &second);
head = headPtr;
while (head != NULL){
printf("%d\t", head -> value);
head = head -> next;
}
printf("\n"); sll_delete(headPtr, &first);
while (headPtr != NULL){
printf("%d\t", headPtr -> value);
headPtr = headPtr -> next;
}
printf("\n"); sll_delete(headPtr, &third);
head = headPtr;
while (head != NULL){
printf("%d\t", head -> value);
head = head -> next;
}
printf("\n");
return 0;
}

运行:

12.7 建立单词索引表

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define TRUE 1
#define FALSE 0
#define EXIST 1
#define NOEXIST 0
typedef struct Wordlist {
struct Wordlist *nextWord;
char *word;
} wordlist; typedef struct Alphalist {
struct Alphalist *nextAlpha;
//单个单词链表的指针
wordlist * wlPtr;
char alpha;
} alphalist; int isExist(wordlist *listPtr, char *string)
{
wordlist *current = listPtr; while(current != NULL){
if(strcmp(string, current -> word) == 0){
return EXIST;
}
current = current -> nextWord;
} return NOEXIST;
} int wordInsert(wordlist **listPtr, char *string)
{
wordlist **current = listPtr;
wordlist *new;
char *temp; while(*current != NULL){
//按字符排序进行插入
if(strcmp(string, (*current) -> word) < 0){
//生成new节点,插入到current之前,current为指向nextWord字段的指针
new = (wordlist *)malloc(sizeof(wordlist));
temp = (char *)malloc(strlen(string));
if(temp == NULL){
return FALSE;
}
strcpy(temp, string);
new -> word = temp;
//new指向 *current
new -> nextWord = *current;
//更新 *current为当前插入点
*current = new;
return TRUE;
}
//循环到下一点
current = &(*current) -> nextWord;
}
//循环玩整个列表后,还未找到,则末尾追加上
temp = (char *)malloc(strlen(string));
if(temp == NULL){
return FALSE;
}
strcpy(temp, string);
new = (wordlist *)malloc(sizeof(wordlist));
new -> word = temp;
new -> nextWord = NULL;
*current = new; return TRUE;
} int WordAlphaListInsert(alphalist *ptr, char *string)
{
char headCh = string[0];
alphalist *current = ptr;
wordlist *wl;
wordlist **rootPtr;
char *temp; //通过首字符查找wordlist
while (current -> alpha != headCh){
current = current -> nextAlpha;
} //已经存在
if(isExist(current -> wlPtr, string) == EXIST){
return FALSE;
}else{
//如果wordlist为NULL空,则创建初始单词链表
if(current -> wlPtr == NULL){
wl = (wordlist *)malloc(sizeof(wordlist));
//第一个节点,nextword为NULL
wl -> nextWord = NULL;
//申请内存拷贝字符串
temp = (char *)malloc(strlen(string));
if(temp == NULL){
return FALSE;
}
strcpy(temp, string);
wl ->word = temp;
current -> wlPtr = wl;
}else{
//如果有单词表,则插入单词
rootPtr = &(current -> wlPtr);
wordInsert(rootPtr, string);
}
return TRUE;
}
} //打印链表内容
void printList(alphalist *list)
{
alphalist *currentAl = list;
wordlist *currentWl;
while (currentAl != NULL){
printf("%c:\n", currentAl -> alpha);
currentWl = currentAl -> wlPtr;
while (currentWl != NULL){
printf("%s \t", currentWl -> word);
currentWl = currentWl -> nextWord;
}
printf("\n-----------------------\n");
currentAl = currentAl -> nextAlpha;
}
} int main()
{
char z;
alphalist *pre = NULL;
alphalist *current; //创建字母和单词列表
for(z = 122; z > 96; z--){
current = (alphalist *)malloc(sizeof(alphalist));
current -> alpha = z;
current -> wlPtr = NULL;
current -> nextAlpha = pre;
pre = current;
}
//插入单词
WordAlphaListInsert(current, "yang");
WordAlphaListInsert(current, "xun");
WordAlphaListInsert(current, "xan");
WordAlphaListInsert(current, "xzn");
WordAlphaListInsert(current, "wu");
WordAlphaListInsert(current, "ya");
WordAlphaListInsert(current, "yz");
printList(current); return 0;
}

运行:

C和指针 第十二章 结构体 习题的更多相关文章

  1. C和指针 第十二章 结构体 整体赋值 error: expected expression

    定义结构体后整体赋值时发生错误 typedef struct NODE { struct NODE *fwd; struct NODE *bwd; int value; } Node; //声明变量 ...

  2. C语言程序设计(十二) 结构体和共用体

    第十二章 结构体和共用体 当需要表示复杂对象时,仅使用几个基本数据类型显然是不够的 根本的解决方法是允许用户自定义数据类型 构造数据类型(复合数据类型)允许用户根据实际需要利用已有的基本数据类型来构造 ...

  3. C和指针 第十二章 使用结构和指针

    链表是一种常用的数据结构,每个节点通过链或者指针链接在一起,程序通过间接指针访问链表中的节点. typedef struct Node { //指向下一个节点的指针 struct Node *next ...

  4. C和指针 第十二章 使用结构和指针 双链表和语句提炼

    双链表中每个节点包含指向当前和之后节点的指针,插入节点到双链表中需要考虑四种情况: 1.插入到链表头部 2.插入到链表尾部 3.插入到空链表中 4.插入到链表内部 #include <stdio ...

  5. C和指针 (pointers on C)——第十二章:利用结构和指针

    第十二章 利用结构和指针 这章就是链表.先单链表,后双向链表. 总结: 单链表是一种使用指针来存储值的数据结构.链表中的每一个节点包括一个字段,用于指向链表的下一个节点. 有一个独立的根指针指向链表的 ...

  6. perl5 第十二章 Perl5中的引用/指针

    第十二章 Perl5中的引用/指针 by flamephoenix 一.引用简介二.使用引用三.使用反斜线(\)操作符四.引用和数组五.多维数组六.子程序的引用  子程序模板七.数组与子程序八.文件句 ...

  7. [CSAPP笔记][第十二章并发编程]

    第十二章 并发编程 如果逻辑控制流在时间上是重叠,那么它们就是并发的(concurrent).这种常见的现象称为并发(concurrency). 硬件异常处理程序,进程和Unix信号处理程序都是大家熟 ...

  8. 《OpenCL异构并行编程实战》补充笔记散点,第五至十二章

    ▶ 第五章,OpenCL 的并发与执行模型 ● 内存对象与上下文相关而不是与设备相关.设备在不同设备之间的移动如下,如果 kernel 在第二个设备上运行,那么在第一个设备上产生的任何数据结果在第二个 ...

  9. PRML读书会第十二章 Continuous Latent Variables(PCA,Principal Component Analysis,PPCA,核PCA,Autoencoder,非线性流形)

    主讲人 戴玮 (新浪微博: @戴玮_CASIA) Wilbur_中博(1954123) 20:00:49 我今天讲PRML的第十二章,连续隐变量.既然有连续隐变量,一定也有离散隐变量,那么离散隐变量是 ...

随机推荐

  1. js/jquery/html前端开发常用到代码片段

    1.IE条件注释 条件注释简介 IE中的条件注释(Conditional comments)对IE的版本和IE非IE有优秀的区分能力,是WEB设计中常用的hack方法.条件注释只能用于IE5以上,IE ...

  2. php 时间加减

    <?php date_default_timezone_set('PRC'); //默认时区 echo "今天:",date("Y-m-d",time() ...

  3. codevs 2924 数独挑战

    2924 数独挑战 http://codevs.cn/problem/2924/ 题目描述 Description "芬兰数学家因卡拉,花费3个月时间设计出了世界上迄今难度最大的数独游戏,而 ...

  4. codevs 2594 解药还是毒药

    2594 解药还是毒药 http://codevs.cn/problem/2594/ 题目描述 Description Smart研制出对付各种症状的解药,可是他一个不小心,每种药都小小地配错了一点原 ...

  5. Redis从入门到精通之一:序篇

    Redis一直是我想好好研究的组件,但是之前受限于工作场景,没有真正意义的使用过.但是目前工作中,Redis作为主要的缓存组件来缓冲服务器的压力.所以,本序列主要结合实际工作中遇到的各种Redis的设 ...

  6. Promiscuous Mode

      简介 Monitor mode 与 promiscuous mode 比较 这是在网卡上的的两个特殊的模式,简而言之,都是将网卡的过滤器关闭. Monitor mode 这是我们常常提到的snif ...

  7. 详解 Android Activity 生命周期

    从以下几个方面详细说一下Activity的生命周期: 1.回到主屏幕再打开和退出程序的时候. 2.屏幕旋转的时候. 3.打开其它的Activity的情况. 4.打开一个Layou透明的Activity ...

  8. Mongodb学习笔记四(Mongodb聚合函数)

    第四章 Mongodb聚合函数 插入 测试数据 ;j<;j++){ for(var i=1;i<3;i++){ var person={ Name:"jack"+i, ...

  9. C#基础系列——Attribute特性使用

    前言:上篇 C#基础系列——反射笔记 总结了下反射得基础用法,这章我们来看看C#的另一个基础技术——特性. 1.什么是特性:就博主的理解,特性就是在类的类名称.属性.方法等上面加一个标记,使这些类.属 ...

  10. safehandle 和析构函数

    safehandle 是一种析构机制,她和析构函数有什么分别. 首先要理解析构函数.析构函数在.net中是没有顺序的,因此你不能假定另一个对象的析构函数在你之后运行,哪怕它是你的成员!如果你的成员也有 ...