《C Primer Plus》第17章复习题与编程练习
《C Primer Plus》第17章复习题与编程练习
- 复习题
-
- 1. 定义一种数据类型涉及哪些内容?
- 2. 为什么程序清单17.2只能沿一个方向遍历链表?如何修改struct film定义才能沿两个方向遍历链表?
- 3. 什么是ADT?
- 4. QueueIsEmpty()函数接受一个指向queue结构的指针作为参数,但是也可以将其编写成接受一个queue结构作为参数。这两种各有什么优缺点?
- 5. 栈(stack)是链表系列的另一种数据形式。在栈中,只能在链表的一端添加和删除项,项被“压入”栈和“弹出”栈。因此,栈是一种LIFO结构。
- 6. 在一个含有3个项的分类列表中,判断一个特定项是否在该列表中,用顺序查找和二叉查找方法分别需要最多多少次?当列表中有1023个项时分别是多少次?65535个项时分别是多少次?
- 7. 假设一个程序用本章介绍的算法构造了一个储存单词的二叉查找树。假设根据下面所列的顺序输入单词,请画出每种情况的树:
- 8. 考虑复习题7构造的二叉树,根据本章的算法,删除单词food之后,各树是什么样子?
- 编程练习
-
- 1. 双向遍历链表
- 2. 有头尾指针的List
- 3. 数组List
- 4. 重写mall.c
- 5. 栈
- 6. 折半搜索
- 7. 统计文件中每个单词出现的次数
- 8. 修改宠物俱乐部程序
复习题
1. 定义一种数据类型涉及哪些内容?
答:
定义一种数据类型涉及以下内容:
- 一个值的集合,表示该数据类型可以表示的数据范围和形式。
- 一组操作,表示该数据类型可以进行的运算和处理。
- 一个存储空间,表示该数据类型在内存中占用的字节数。
例如,C语言中有基本数据类型(如int、float、char等)和构造数据类型(如数组、结构、指针等)。你也可以用typedef或#define来自定义数据类型,给已有的数据类型起一个别名。
2. 为什么程序清单17.2只能沿一个方向遍历链表?如何修改struct film定义才能沿两个方向遍历链表?
答:
程序清单17.2只能沿一个方向遍历链表,因为它使用的是单向链表,每个结点只有一个指向下一个结点的指针。如果要沿两个方向遍历链表,就需要使用双向链表,每个结点有两个指针,分别指向前一个结点和后一个结点。
要修改struct film定义为双向链表,可以在结构体中增加一个指向前一个结点的指针prev,并在创建、插入、删除等操作时维护好这个指针。
3. 什么是ADT?
答:
ADT是抽象数据类型的缩写,它是一种数学模型,用来定义数据类型的行为(语义),而不是具体的实现细节。ADT指定了数据类型可能的值、可能对数据进行的操作,以及这些操作的效果。ADT可以让用户不必关心数据类型是如何实现的,只需要知道它能做什么。
4. QueueIsEmpty()函数接受一个指向queue结构的指针作为参数,但是也可以将其编写成接受一个queue结构作为参数。这两种各有什么优缺点?
答:
接受一个指向queue结构的指针作为参数的优点是:传递指针可以节省内存空间,因为不需要复制整个queue结构;传递指针也可以让函数修改原始数据,如果需要的话。
接受一个指向queue结构的指针作为参数的缺点是:传递指针可能导致悬挂指针或空指针错误,如果传入的参数不合法或被释放;传递指针也可能破坏数据封装性,如果函数不小心修改了原始数据。
接受一个queue结构作为参数的优点是:传递结构可以保护原始数据不被修改,因为函数只对副本进行操作;传递结构也可以避免悬挂指针或空指针错误,因为函数总是接收到有效的数据。
接受一个queue结构作为参数的缺点是:传递结构可能浪费内存空间和时间,因为需要复制整个queue结构;传递结构也可能导致信息丢失,如果队列中包含了动态分配的内存或其他资源。
5. 栈(stack)是链表系列的另一种数据形式。在栈中,只能在链表的一端添加和删除项,项被“压入”栈和“弹出”栈。因此,栈是一种LIFO结构。
a. 设计一个栈ADT
b. 为栈设计一个C编程接口,例如stack.h文件
答:
a.
一个栈ADT可以定义如下:
栈是一种存储元素的集合,其中元素按照LIFO(后进先出)的顺序被添加和删除。
栈有一个顶部(top),也称为栈顶(stack top),表示最近添加到栈中的元素。
栈有一个容量(capacity),表示栈可以存储的最大元素个数。
栈有以下基本操作:
- 创建(create):创建一个空的或指定容量的新栈。
- 销毁(destroy):释放一个已存在的栈所占用的内存空间。
- 判空(is_empty):检查一个已存在的栈是否为空。
- 判满(is_full):检查一个已存在的栈是否已满。
- 压入(push):将一个新元素添加到一个已存在且未满的栈的顶部。
- 弹出(pop):将一个已存在且非空的栈的顶部元素移除并返回。
- 取顶(peek):返回一个已存在且非空的栈的顶部元素,但不移除它。
b.
为了实现一个C编程接口,例如stack.h头文件,我们需要定义以下内容:
- 标准库头文件和宏定义
- 元素类型和错误代码
- 栈结构体
- 函数原型
实现:
// stack.h// include standard library headers and define macros
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#define STACK_INIT_SIZE 10 // initial stack capacity
#define STACK_INCR_SIZE 5 // increment stack capacity// define element type and error codes
typedef int ElemType; // change this if needed
typedef enum {OK,ERROR,OVERFLOW,UNDERFLOW
} Status;// define stack structure
typedef struct {ElemType *base; // base pointer of stack arrayElemType *top; // top pointer of stack arrayint capacity; // current capacity of stack array
} Stack;// declare function prototypes
Status create_stack(Stack *s); // create an empty stack with initial capacity
Status destroy_stack(Stack *s); // destroy an existing stack and free memory space
bool is_empty(Stack s); // check if an existing stack is empty
bool is_full(Stack s); // check if an existing stack is full
Status push(Stack *s, ElemType e); // push a new element to the top of an existing and not full stack
Status pop(Stack *s, ElemType *e); // pop the top element from an existing and not empty stack and return it
Status peek(Stack s, ElemType *e); // peek the top element from an existing and not empty stack and return it
6. 在一个含有3个项的分类列表中,判断一个特定项是否在该列表中,用顺序查找和二叉查找方法分别需要最多多少次?当列表中有1023个项时分别是多少次?65535个项时分别是多少次?
答:
顺序查找(sequential search)是一种从头到尾逐个比较元素的查找方法,最坏情况下需要比较n次,其中n是列表的长度。
二叉查找(binary search)是一种每次将列表分成两半并比较中间元素的查找方法,最坏情况下需要比较log2(n+1)次,其中n是列表的长度。
因此,在一个含有3个项的分类列表中,用顺序查找和二叉查找方法分别需要最多3次和2次;当列表中有1023个项时分别需要最多1023次和10次;当列表中有65535个项时分别需要最多65535次和16次。
7. 假设一个程序用本章介绍的算法构造了一个储存单词的二叉查找树。假设根据下面所列的顺序输入单词,请画出每种情况的树:
a.nice food roam dodge gate office wave
b.wave roam office nice gate food dodge
c.food dodge roam wave office gate nice
d.nice roam office food wave gate dodge
答:
8. 考虑复习题7构造的二叉树,根据本章的算法,删除单词food之后,各树是什么样子?
答:
编程练习
1. 双向遍历链表
修改程序清单17.2,使其既能以正序又能以逆序显示电影列表。一种方法修改链表定义以使链表能被双向遍历;另一种方法是使用递归。
代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>#define TSIZE 45struct film
{char title[TSIZE];int rating;struct film *next;struct film *pre;
};void positive(struct film *p); // 正序显示
void reversed(struct film *p); // 逆序显示
void recursion(struct film *p); // 逆序递归显示int main()
{struct film *head = NULL; // 指向链表头结点的指针,始终指向头结点保持不变struct film *current; // 动态内存分配的地址。struct film *prev; // 尾结点,可变,每次用来更新结构体内指针变量的值和自身的值。char input[TSIZE];puts("Enter first movie title: ");while (gets(input) != NULL && input[0] != '\\0'){if ((current = (struct film *)malloc(sizeof(struct film))) == NULL){printf("Failed to malloc memory\\n");exit(EXIT_FAILURE);}if (head == NULL){head = current;current->pre = NULL;}else{prev->next = current;current->pre = prev;}current->next = NULL;strcpy(current->title, input);puts("Enter your rating <0-10>: ");scanf("%d", ¤t->rating);while (getchar() != '\\n')continue;puts("Enter next movie title (empty line to stop): ");prev = current;}if (head == NULL)printf("No data entered. ");else{printf("Here is the movie list: \\n");positive(head);printf("\\n");printf("Here is the movie list: \\n");reversed(prev);printf("\\n");printf("Here is the movie list: \\n");recursion(head);}printf("Bye!\\n");system("pause");return 0;
}void positive(struct film *p)
{while (p != NULL){printf("Movie: %s Rating: %d\\n", p->title, p->rating);p = p->next;}
}void reversed(struct film *p)
{while (p != NULL){printf("Movie: %s Rating: %d\\n", p->title, p->rating);p = p->pre;}
}void recursion(struct film *p)
{if (p->next != NULL)recursion(p->next);printf("Movie: %s Rating: %d\\n", p->title, p->rating);
}
运行结果:
2. 有头尾指针的List
假设list.h(程序清单17.3)如下定义列表:
typedef struct list
{Node * nead; /*指向列表首*/Node * end; /*指向列表尾*/
}List;
根据这个定义,重写list.c(程序清单17.5)函数,并用films3.c(程序清单17.4)测试结果代码。
代码:
list.h:
#ifndef LIST_H_
#define LIST_H_#define TSIZE 45struct film
{char title[TSIZE];int rating;
};typedef struct film Item;typedef struct node
{Item item;struct node *next;
} Node;typedef struct list
{Node *head;Node *end;
} List;void InitializeList(List *plist);
bool ListIsEmpty(const List *plist);
bool ListIsFull(const List *plist);
unsigned int ListItemCount(const List *plist);
bool AddItem(Item item, List *plist);
void Traverse(const List *plist, void (*pfun)(Item item));
void EmptyTheList(List *plist);#endif
list.c:
#include <stdio.h>
#include <stdlib.h>
#include "list.h"static void CopyToNode(Item item, Node *pnode);void InitializeList(List *plist)
{(*plist).head = NULL;(*plist).end = NULL;return;
}bool ListIsEmpty(const List *plist)
{return NULL == (*plist).head;
}bool ListIsFull(const List *plist)
{Node *pt;bool full;pt = (Node *)malloc(sizeof(Node));if (pt == NULL){full = true;}else{full = false;}free(pt);return full;
}unsigned int ListItemCount(const List *plist)
{unsigned int count = 0;Node *pnode = (*plist).head; // 使指针指向首结点;while (pnode != NULL){++count;pnode = pnode->next;}return count;
}bool AddItem(Item item, List *plist)
{Node *pnew;Node *scan = (*plist).head;pnew = (Node *)malloc(sizeof(Node));if (pnew == NULL){return false;}CopyToNode(item, pnew);pnew->next = NULL;if (scan == NULL) // 若是首结点则使头尾双指针同时指向此结点;{(*plist).head = pnew;(*plist).end = pnew;}else{(*plist).end->next = pnew; // 尾结点指针域指向新结点;(*plist).end = pnew; // 新结点成为尾结点;}return true;
}void Traverse(const List *plist, void (*pfun)(Item item))
{Node *pnode = (*plist).head;while (pnode != NULL){(*pfun)(pnode->item);pnode = pnode->next;}return;
}void EmptyTheList(List *plist)
{Node *psave;while ((*plist).head != NULL){psave = (*plist).head->next;free((*plist).head);(*plist).head = psave;}return;
}static void CopyToNode(Item item, Node *pnode)
{pnode->item = item;return;
}
films.cpp:
/* films3.c -- using an ADT-style linked list */
/* compile with list.c */
#include <stdio.h>
#include <stdlib.h> /* prototype for exit() */
#include <string.h>
#include "list.h" /* defines List, Item */void showmovies(Item item);
char *s_gets(char *st, int n);int main()
{List movies;Item temp;/* initialize */InitializeList(&movies);if (ListIsFull(&movies)){fprintf(stderr, "No memory available! Bye!\\n");exit(1);}/* gather and store */puts("Enter first movie title:");while (s_gets(temp.title, TSIZE) != NULL && temp.title[0] != '\\0'){puts("Enter your rating <0-10>:");scanf("%d", &temp.rating);while (getchar() != '\\n')continue;if (AddItem(temp, &movies) == false){fprintf(stderr, "Problem allocating memory\\n");break;}if (ListIsFull(&movies)){puts("The list is now full.");break;}puts("Enter next movie title (empty line to stop):");}/* display */if (ListIsEmpty(&movies))printf("No data entered. ");else{printf("Here is the movie list:\\n");Traverse(&movies, showmovies);}printf("You entered %d movies.\\n", ListItemCount(&movies));/* clean up */EmptyTheList(&movies);printf("Bye!\\n");system("pause");return 0;
}void showmovies(Item item)
{printf("Movie: %s Rating: %d\\n", item.title,item.rating);
}char *s_gets(char *st, int n)
{char *ret_val;char *find;ret_val = fgets(st, n, stdin);if (ret_val){find = strchr(st, '\\n'); // look for newlineif (find) // if the address is not NULL,*find = '\\0'; // place a null character thereelsewhile (getchar() != '\\n')continue; // dispose of rest of line}return ret_val;
}
运行结果:
C:\\Users\\81228\\Documents\\Program\\VScode C Program\\chapter17\\17.2>g++ list.c films.cpp -o filmsC:\\Users\\81228\\Documents\\Program\\VScode C Program\\chapter17\\17.2>films
Enter first movie title:
A
Enter your rating <0-10>:
1
Enter next movie title (empty line to stop):
B
Enter your rating <0-10>:
2
Enter next movie title (empty line to stop):
C
Enter your rating <0-10>:
3
Enter next movie title (empty line to stop):Here is the movie list:
Movie: A Rating: 1
Movie: B Rating: 2
Movie: C Rating: 3
You entered 3 movies.
Bye!
请按任意键继续. . .
3. 数组List
假设list.h(程序清单17.3)如下定义列表:
#define MAXZIZE 100typedef struct list
{Item entries[MAXAIZE]; /*项目数组*/int items; /*列表中项目的个数*/
}List;
根据这个定义,重写list.c(程序清单17.5)函数,并用films3.c(程序清单17.4)测试结果代码
代码:
list.h:
/* list.h -- header file for a simple list type */
#ifndef LIST_H_
#define LIST_H_
#include <stdbool.h> /* C99 feature *//* program-specific declarations */#define TSIZE 45 /* size of array to hold title */
#define MAXSIZE 100struct film
{char title[TSIZE];int rating;
};/* general type definitions */typedef struct film Item;typedef struct node
{Item item;struct node *next;
} Node;typedef struct list
{Item entries[MAXSIZE];int items;
} List;/* function prototypes *//* operation: initialize a list */
/* preconditions: plist points to a list */
/* postconditions: the list is initialized to empty */
void InitializeList(List *plist);/* operation: determine if list is empty */
/* plist points to an initialized list */
/* postconditions: function returns True if list is empty */
/* and returns False otherwise */
bool ListIsEmpty(const List *plist);/* operation: determine if list is full */
/* plist points to an initialized list */
/* postconditions: function returns True if list is full */
/* and returns False otherwise */
bool ListIsFull(const List *plist);/* operation: determine number of items in list */
/* plist points to an initialized list */
/* postconditions: function returns number of items in list */
unsigned int ListItemCount(const List *plist);/* operation: add item to end of list */
/* preconditions: item is an item to be added to list */
/* plist points to an initialized list */
/* postconditions: if possible, function adds item to end */
/* of list and returns True; otherwise the */
/* function returns False */
bool AddItem(Item item, List *plist);/* operation: apply a function to each item in list */
/* plist points to an initialized list */
/* pfun points to a function that takes an */
/* Item argument and has no return value */
/* postcondition: the function pointed to by pfun is */
/* executed once for each item in the list */
void Traverse(const List *plist, void (*pfun)(Item item));/* operation: free allocated memory, if any */
/* plist points to an initialized list */
/* postconditions: any memory allocated for the list is freed */
/* and the list is set to empty */
void EmptyTheList(List *plist);#endif
list.c:
/* list.c -- functions supporting list operations */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "list.h"/* local function prototype */
static void CopyToNode(Item item, Node *pnode);
static void CopyToItem(Item item, Item *entries, int n);/* interface functions */
/* set the list to empty */
void InitializeList(List *plist)
{plist->entries[MAXSIZE] = {0};plist->items = 0;
}/* returns true if list is empty */
bool ListIsEmpty(const List *plist)
{if (plist->items == 0) // 直接借用items当下标 所以为0~99return true;elsereturn false;
}/* returns true if list is full */
bool ListIsFull(const List *plist)
{Node *pt;bool full;pt = (Node *)malloc(sizeof(Node));if (pt == NULL)full = true;elsefull = false;free(pt);return full;
}/* returns number of nodes */
unsigned int ListItemCount(const List *plist)
{// unsigned int count = 0;// Node * pnode = *plist; /* set to start of list *///// while (pnode != NULL)// {// ++count;// pnode = pnode->next; /* set to next node */// }return plist->items; // 一句到位
}/* creates node to hold item and adds it to the end of */
/* the list pointed to by plist (slow implementation) */
bool AddItem(Item item, List *plist)
{// Node * pnew;// Node * scan = *plist;// pnew = (Node *) malloc(sizeof(Node));// if (pnew == NULL)// return false; /* quit function on failure */// CopyToNode(item, pnew);// pnew->next = NULL;// if (scan == NULL) /* empty list, so place */// *plist = pnew; /* pnew at head of list */// else// {// while (scan->next != NULL)// scan = scan->next; /* find end of list */// scan->next = pnew; /* add pnew to end */// }if (plist->items >= MAXSIZE)return false;CopyToItem(item, plist->entries, plist->items);plist->items++;return true;
}/* visit each node and execute function pointed to by pfun */
void Traverse(const List *plist, void (*pfun)(Item item))
{// Node * pnode = *plist; /* set to start of list *///// while (pnode != NULL)// {// (*pfun)(pnode->item); /* apply function to item */// pnode = pnode->next; /* advance to next item */// }int i;for (i = 0; i < plist->items; i++)(*pfun)(plist->entries[i]);
}/* free memory allocated by malloc() */
/* set list pointer to NULL */
void EmptyTheList(List *plist)
{// Node * psave;//// while (*plist != NULL)// {// psave = (*plist)->next; /* save address of next node */// free(*plist); /* free current node */// *plist = psave; /* advance to next node */// }plist->entries[MAXSIZE] = {0};plist->items = 0;
}/* local function definition */
/* copies an item into a node */
static void CopyToNode(Item item, Node *pnode)
{pnode->item = item; /* structure copy */
}static void CopyToItem(Item item, Item *entries, int n)
{strcpy(entries[n].title, item.title);entries[n].rating = item.rating;
}
films.cpp:
/* films3.c -- using an ADT-style linked list */
/* compile with list.c */
#include <stdio.h>
#include <stdlib.h> /* prototype for exit() */
#include <string.h>
#include "list.h" /* defines List, Item */void showmovies(Item item);
char *s_gets(char *st, int n);int main()
{List movies;Item temp;/* initialize */InitializeList(&movies);if (ListIsFull(&movies)){fprintf(stderr, "No memory available! Bye!\\n");exit(1);}/* gather and store */puts("Enter first movie title:");while (s_gets(temp.title, TSIZE) != NULL && temp.title[0] != '\\0'){puts("Enter your rating <0-10>:");scanf("%d", &temp.rating);while (getchar() != '\\n')continue;if (AddItem(temp, &movies) == false){fprintf(stderr, "Problem allocating memory\\n");break;}if (ListIsFull(&movies)){puts("The list is now full.");break;}puts("Enter next movie title (empty line to stop):");}/* display */if (ListIsEmpty(&movies))printf("No data entered. ");else{printf("Here is the movie list:\\n");Traverse(&movies, showmovies);}printf("You entered %d movies.\\n", ListItemCount(&movies));/* clean up */EmptyTheList(&movies);printf("Bye!\\n");system("pause");return 0;
}void showmovies(Item item)
{printf("Movie: %s Rating: %d\\n", item.title,item.rating);
}char *s_gets(char *st, int n)
{char *ret_val;char *find;ret_val = fgets(st, n, stdin);if (ret_val){find = strchr(st, '\\n'); // look for newlineif (find) // if the address is not NULL,*find = '\\0'; // place a null character thereelsewhile (getchar() != '\\n')continue; // dispose of rest of line}return ret_val;
}
运行结果:
C:\\Users\\81228\\Documents\\Program\\VScode C Program\\chapter17\\17.3>g++ list.c films.cpp -o filmsC:\\Users\\81228\\Documents\\Program\\VScode C Program\\chapter17\\17.3>films
Enter first movie title:
A
Enter your rating <0-10>:
1
Enter next movie title (empty line to stop):
B
Enter your rating <0-10>:
2
Enter next movie title (empty line to stop):
C
Enter your rating <0-10>:
3
Enter next movie title (empty line to stop):
D
Enter your rating <0-10>:
4
Enter next movie title (empty line to stop):Here is the movie list:
Movie: A Rating: 1
Movie: B Rating: 2
Movie: C Rating: 3
Movie: D Rating: 4
You entered 4 movies.
Bye!
请按任意键继续. . .
4. 重写mall.c
重写mall.c(程序清单17.9),使其用两个队列模拟两个摊位。
代码:
queue.h:
/* queue.h -- interface for a queue */
#ifndef _QUEUE_H_
#define _QUEUE_H_
#include <stdbool.h>// INSERT ITEM TYPE HERE
// FOR EXAMPLE,
// typedef int Item; // for use_q.c
// OR typedef struct item {int gumption; int charisma;} Item;
// OR (for mall.c)
//
typedef struct item
{long arrive; // the time when a customer joins the queueint processtime; // the number of consultation minutes desired
} Item;
//#define MAXQUEUE 10typedef struct node
{Item item;struct node *next;
} Node;typedef struct queue
{Node *front; /* pointer to front of queue */Node *rear; /* pointer to rear of queue */int items; /* number of items in queue */
} Queue;/* operation: initialize the queue */
/* precondition: pq points to a queue */
/* postcondition: queue is initialized to being empty */
void InitializeQueue(Queue *pq);/* operation: check if queue is full */
/* precondition: pq points to previously initialized queue */
/* postcondition: returns True if queue is full, else False */
bool QueueIsFull(const Queue *pq);/* operation: check if queue is empty */
/* precondition: pq points to previously initialized queue */
/* postcondition: returns True if queue is empty, else False */
bool QueueIsEmpty(const Queue *pq);/* operation: determine number of items in queue */
/* precondition: pq points to previously initialized queue */
/* postcondition: returns number of items in queue */
int QueueItemCount(const Queue *pq);/* operation: add item to rear of queue */
/* precondition: pq points to previously initialized queue */
/* item is to be placed at rear of queue */
/* postcondition: if queue is not empty, item is placed at */
/* rear of queue and function returns */
/* True; otherwise, queue is unchanged and */
/* function returns False */
bool EnQueue(Item item, Queue *pq);/* operation: remove item from front of queue */
/* precondition: pq points to previously initialized queue */
/* postcondition: if queue is not empty, item at head of */
/* queue is copied to *pitem and deleted from */
/* queue, and function returns True; if the */
/* operation empties the queue, the queue is */
/* reset to empty. If the queue is empty to */
/* begin with, queue is unchanged and the */
/* function returns False */
bool DeQueue(Item *pitem, Queue *pq);/* operation: empty the queue */
/* precondition: pq points to previously initialized queue */
/* postconditions: the queue is empty */
void EmptyTheQueue(Queue *pq);#endif
queue.c:
/* queue.c -- the Queue type implementation*/
#include <stdio.h>
#include <stdlib.h>
#include "queue.h"/* local functions */
static void CopyToNode(Item item, Node *pn);
static void CopyToItem(Node *pn, Item *pi);void InitializeQueue(Queue *pq)
{pq->front = pq->rear = NULL;pq->items = 0;
}bool QueueIsFull(const Queue *pq)
{return pq->items == MAXQUEUE;
}bool QueueIsEmpty(const Queue *pq)
{return pq->items == 0;
}int QueueItemCount(const Queue *pq)
{return pq->items;
}bool EnQueue(Item item, Queue *pq)
{Node *pnew;if (QueueIsFull(pq))return false;pnew = (Node *)malloc(sizeof(Node));if (pnew == NULL){fprintf(stderr, "Unable to allocate memory!\\n");exit(1);}CopyToNode(item, pnew);pnew->next = NULL;if (QueueIsEmpty(pq))pq->front = pnew; /* item goes to front */elsepq->rear->next = pnew; /* link at end of queue */pq->rear = pnew; /* record location of end */pq->items++; /* one more item in queue */return true;
}bool DeQueue(Item *pitem, Queue *pq)
{Node *pt;if (QueueIsEmpty(pq))return false;CopyToItem(pq->front, pitem);pt = pq->front;pq->front = pq->front->next;free(pt);pq->items--;if (pq->items == 0)pq->rear = NULL;return true;
}/* empty the queue */
void EmptyTheQueue(Queue *pq)
{Item dummy;while (!QueueIsEmpty(pq))DeQueue(&dummy, pq);
}/* Local functions */static void CopyToNode(Item item, Node *pn)
{pn->item = item;
}static void CopyToItem(Node *pn, Item *pi)
{*pi = pn->item;
}
mall.c:
// mall.c -- use the Queue interface
// compile with queue.c
#include <stdio.h>
#include <stdlib.h> // for rand() and srand()
#include <time.h> // for time()
#include "queue.h" // change Item typedef
#define MIN_PER_HR 60.0bool newcustomer(double x); // is there a new customer?
Item customertime(long when); // set customer parametersint main(void)
{Queue line1;Queue line2;Item temp1; // new customer dataItem temp2;int hours; // hours of simulationint perhour; // average # of arrivals per hourlong cycle, cyclelimit; // loop counter, limitlong turnaways = 0; // turned away by full queuelong customers = 0; // joined the queuelong served = 0; // served during the simulationlong sum_line = 0; // cumulative line lengthint wait_time1 = 0; // time until Sigmund is freeint wait_time2 = 0;double min_per_cust; // average time between arrivalslong line_wait = 0; // cumulative time in lineInitializeQueue(&line1);InitializeQueue(&line2);srand((unsigned int)time(0)); // random initializing of rand()puts("Case Study: Sigmund Lander's Advice Booth");puts("Enter the number of simulation hours:");scanf("%d", &hours);cyclelimit = MIN_PER_HR * hours;puts("Enter the average number of customers per hour:");scanf("%d", &perhour);min_per_cust = MIN_PER_HR / perhour;for (cycle = 0; cycle < cyclelimit; cycle++){if (newcustomer(min_per_cust)) // 新顾客来了{if (QueueIsFull(&line1) && QueueIsFull(&line2)) // 如果都满了 走的顾客就+1turnaways++;else // 肯定都没满 或者一个满了{customers++;if (QueueIsFull(&line1)) // line1满了加line2{temp2 = customertime(cycle); // 创建客户数据EnQueue(temp2, &line2);}else{temp1 = customertime(cycle); // 创建客户数据EnQueue(temp1, &line1);}}}if (wait_time1 <= 0 && !QueueIsEmpty(&line1)){DeQueue(&temp1, &line1);wait_time1 = temp1.processtime; // 设置接下来的咨询时间line_wait += cycle - temp1.arrive; // 计算总的 到来时间-咨询时间之前served++; // 咨询人数加一}if (wait_time2 <= 0 && !QueueIsEmpty(&line2)){DeQueue(&temp2, &line2);wait_time2 = temp2.processtime;line_wait += cycle - temp2.arrive;served++;}if (wait_time1 > 0)wait_time1--;if (wait_time2 > 0)wait_time2--;sum_line += QueueItemCount(&line1);sum_line += QueueItemCount(&line2);}if (customers > 0){printf("customers accepted: %ld\\n", customers);printf(" customers served: %ld\\n", served);printf(" turnaways: %ld\\n", turnaways);printf("average queue size: %.2f\\n",(double)sum_line / cyclelimit);printf(" average wait time: %.2f minutes\\n",(double)line_wait / served);}elseputs("No customers!");EmptyTheQueue(&line1);EmptyTheQueue(&line2);puts("Bye!");system("pause");return 0;
}// x = average time, in minutes, between customers
// return value is true if customer shows up this minute
bool newcustomer(double x)
{if (rand() * x / RAND_MAX < 1)return true;elsereturn false;
}// when is the time at which the customer arrives
// function returns an Item structure with the arrival time
// set to when and the processing time set to a random value
// in the range 1 - 3
Item customertime(long when)
{Item cust;cust.processtime = rand() % 3 + 1;cust.arrive = when;return cust;
}
运行结果:
5. 栈
编写一个程序,让您输入一个字符串。该程序将此字符串中的字符逐个地压入一个栈(请参见复习题5),然后弹出这些字符并显示。结果是将字符串按逆序显示。
代码:
stack.h:
#ifndef STACK_H_
#define STACK_H_#include <stdbool.h>#define MAXSTACK 10typedef char Item;
typedef struct stack
{int top;Item items[MAXSTACK];
} Stack;/*操作: 初始化栈 */
/*前提条件: ps指向一个栈 */
/*后置条件: 该栈初始化为空 */
void InitializeStack(Stack *ps);/*操作: 检查栈是否已满 */
/*前提条件: ps指向之前已被初始化的栈 */
/*后置条件: 如果栈已经满,该函数返回true */
bool FullStack(const Stack *ps);/*操作: 检查栈是否为空 */
/*前提条件: ps指向之前已被初始化的栈 */
/*后置条件: 如果栈为空,该函数放回ture;否者,返回false */
bool EmptyStack(const Stack *ps);/*操作: 把项压入栈顶 */
/*前提条件: ps指向之前已被初始化的栈 */
/* items是待压入栈顶的项 */
/*后置条件: 如果栈不满,把item放在栈顶,该函数返回true; */
/* 否则,栈不变,该函数返回false */
bool Push(Item item, Stack *ps);/*操作: 从栈顶删除项 */
/*前提条件: ps指向之前已被初始化的栈 */
/*后置条件: 如果栈不为空,把item拷贝到*pitem */
/* 删除栈顶的item,该函数返回true */
/* 如果该操作后栈中没有项,则重置该项为空 */
/* 如果删除操作之前栈为空,栈不变,该函数返回false */
bool Pop(Item *pitem, Stack *ps);#endif
stack.c:
#include <stdio.h>
#include "stack.h"static void ToBeTrueIndex(int *index);void InitializeStack(Stack *ps)
{ps->top = 0;ps->items[MAXSTACK] = {0};
}bool FullStack(const Stack *ps)
{return ps->top == MAXSTACK - 1;
}bool EmptyStack(const Stack *ps)
{return ps->top == 0;
}bool Push(Item item, Stack *ps)
{if (FullStack(ps)) // 如果栈已满返回错误return false;ps->items[ps->top] = item; // 放入栈顶ps->top++; // 压栈return true;
}bool Pop(Item *pitem, Stack *ps)
{if (FullStack(ps))return false;ToBeTrueIndex(&ps->top);*pitem = ps->items[ps->top]; // 抬栈// ps->top--; //调整栈顶if (ps->top == 0) // 如果栈全面被抬完就初始化栈InitializeStack(ps);return true;
}static void ToBeTrueIndex(int *index)
{--(*index); // 指向栈顶数据
}
main.cpp:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "stack.h"int main()
{Item temp[MAXSTACK];Stack box;int i;Item t; // 应该为字符 不应该是指针printf("Enter a string, I will give you string of reverse\\n");while (scanf("%s", temp)){InitializeStack(&box); // 初始化栈for (i = 0; i < strlen(temp); i++) // 将字符压栈Push(temp[i], &box);for (i = 0; i < strlen(temp); i++) // 将字符弹栈{Pop(&t, &box);printf("%c", t);}puts("\\n");printf("Enter a string, I will give you string of reverse(enter ^C to quit)\\n");}printf("Bye!");system("pause");return 0;
}
运行结果:
C:\\Users\\81228\\Documents\\Program\\VScode C Program\\chapter17\\17.5>g++ stack.c main.cpp -o mainC:\\Users\\81228\\Documents\\Program\\VScode C Program\\chapter17\\17.5>main
Enter a string, I will give you string of reverse!
ABCD
DCBAEnter a string, I will give you string of reverse!(enter ^C to quit)
DC^C
C:\\Users\\81228\\Documents\\Program\\VScode C Program\\chapter17\\17.5>
6. 折半搜索
写一个接受3个参数的函数。这3个参数为:存有已排序的整数的数组名,数组元素个数和要查找的整数。如果该整数在数组中,函数返回1;否则返回0。函数用折半搜索法实现。
代码:
#include <stdio.h>
#include <stdlib.h>
#include <math.h> //for pow()#define MAX 1024void Init_Array(int *arr, int n);
int Binary_Search(int *target, int n, int key);int main()
{int data[MAX];int num;Init_Array(data, MAX);printf("Enter a number, I'll tell you if it's in the array(enter q to quit): ");while (scanf("%d", &num) == 1){printf("%d\\n", Binary_Search(data, MAX, num));printf("Try again: ");}printf("Bye!\\n");system("pause");return 0;
}void Init_Array(int *arr, int n)
{for (int i = 0; i < n; i++){arr[i] = i;}
}int Binary_Search(int *target, int n, int key)
{int i;int index;int min = 0, max = n;int step = 0;int answer = 0;while (pow(2, step) < n) // 判断是多少2^n - 1以内step++;index = n / 2; // 到中间的位置for (i = 0; i < step; i++){if (key < target[index]){max = index;index = (min + index) / 2;}else if (key > target[index]){min = index;index = (index + max) / 2;}elseanswer = 1;}return answer;
}
运行结果:
7. 统计文件中每个单词出现的次数
编写一个程序,能打开、读入一个文本文件并统计文件中每个单词出现的次数。用改进的二叉搜索树存储单词及出现的次数。程序读入文件后,会提供一个有三个选项的菜单。第一个选项为列出所有的单词连同其出现的次数。第二个选项为让您输入一个单词,程序报告该单词在文件中出现的次数。第三个选项为退出。
代码:
tree.h:
/* tree.h -- binary search tree */
/* no duplicate items are allowed in this tree */
#ifndef _TREE_H_
#define _TREE_H_#include <stdbool.h>/* redefine Item as appropriate */#define SLEN 20
#define MAXITEMS 10typedef struct item
{char word[SLEN];int frequency;
} Item;typedef struct trnode
{Item item;struct trnode *left; /* pointer to right branch */struct trnode *right; /* pointer to left branch */
} Trnode;typedef struct tree
{Trnode *root; /* pointer to root of tree */int size; /* number of items in tree */
} Tree;/* function prototypes *//* operation: initialize a tree to empty */
/* preconditions: ptree points to a tree */
/* postconditions: the tree is initialized to empty */
void InitializeTree(Tree *ptree);/* operation: determine if tree is empty */
/* preconditions: ptree points to a tree */
/* postconditions: function returns true if tree is */
/* empty and returns false otherwise */
bool TreeIsEmpty(const Tree *ptree);/* operation: determine if tree is full */
/* preconditions: ptree points to a tree */
/* postconditions: function returns true if tree is */
/* full and returns false otherwise */
bool TreeIsFull(const Tree *ptree);/* operation: determine number of items in tree */
/* preconditions: ptree points to a tree */
/* postconditions: function returns number of items in */
/* tree */
int TreeItemCount(const Tree *ptree);/* operation: add an item to a tree */
/* preconditions: pi is address of item to be added */
/* ptree points to an initialized tree */
/* postconditions: if possible, function adds item to */
/* tree and returns true; otherwise, */
/* the function returns false */
bool AddItem(const Item *pi, Tree *ptree);/* operation: find an item in a tree */
/* preconditions: pi points to an item */
/* ptree points to an initialized tree */
/* postconditions: function returns true if item is in */
/* tree and returns false otherwise */
int InTree(const Item *pi, const Tree *ptree);/* operation: delete an item from a tree */
/* preconditions: pi is address of item to be deleted */
/* ptree points to an initialized tree */
/* postconditions: if possible, function deletes item */
/* from tree and returns true; */
/* otherwise the function returns false*/
bool DeleteItem(const Item *pi, Tree *ptree);/* operation: apply a function to each item in */
/* the tree */
/* preconditions: ptree points to a tree */
/* pfun points to a function that takes*/
/* an Item argument and has no return */
/* value */
/* postcondition: the function pointed to by pfun is */
/* executed once for each item in tree */
void Traverse(const Tree *ptree, void (*pfun)(Item item));/* operation: delete everything from a tree */
/* preconditions: ptree points to an initialized tree */
/* postconditions: tree is empty */
void DeleteAll(Tree *ptree);#endif
tree.c:
/* tree.c -- tree support functions */
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include "tree.h"/* local data type */
typedef struct pair
{Trnode *parent;Trnode *child;
} Pair;/* protototypes for local functions */
static Trnode *MakeNode(const Item *pi);
static bool ToLeft(const Item *i1, const Item *i2);
static bool ToRight(const Item *i1, const Item *i2);
static void AddNode(Trnode *new_node, Trnode *root);
static void InOrder(const Trnode *root, void (*pfun)(Item item));
static Pair SeekItem(const Item *pi, const Tree *ptree);
static void DeleteNode(Trnode **ptr);
static void DeleteAllNodes(Trnode *ptr);/* function definitions */
void InitializeTree(Tree *ptree)
{ptree->root = NULL;ptree->size = 0;
}bool TreeIsEmpty(const Tree *ptree)
{if (ptree->root == NULL)return true;elsereturn false;
}bool TreeIsFull(const Tree *ptree)
{if (ptree->size == MAXITEMS)return true;elsereturn false;
}int TreeItemCount(const Tree *ptree)
{return ptree->size;
}bool AddItem(const Item *pi, Tree *ptree)
{Trnode *new_node;Trnode *like;if (TreeIsFull(ptree)){fprintf(stderr, "Tree is full\\n");return false; /* early return */}if ((like = SeekItem(pi, ptree).child) != NULL) // 找到相同的{// printf("Attempted to add duplicate item\\n");// return false; /* early return */like->item.frequency++;return true; /* successful return */}new_node = MakeNode(pi); /* points to new node */if (new_node == NULL){fprintf(stderr, "Couldn't create node\\n");return false; /* early return */}/* succeeded in creating a new node */ptree->size++;if (ptree->root == NULL) /* case 1: tree is empty */ptree->root = new_node; /* new node is tree root */else /* case 2: not empty */AddNode(new_node, ptree->root); /* add node to tree */return true; /* successful return */
}int InTree(const Item *pi, const Tree *ptree)
{Trnode *temp;if ((temp = SeekItem(pi, ptree).child) == NULL)return 0;elsereturn temp->item.frequency;
}bool DeleteItem(const Item *pi, Tree *ptree)
{Pair look;look = SeekItem(pi, ptree);if (look.child == NULL)return false;if (look.parent == NULL) /* delete root item */DeleteNode(&ptree->root);else if (look.parent->left == look.child)DeleteNode(&look.parent->left);elseDeleteNode(&look.parent->right);ptree->size--;return true;
}void Traverse(const Tree *ptree, void (*pfun)(Item item))
{if (ptree != NULL)InOrder(ptree->root, pfun);
}void DeleteAll(Tree *ptree)
{if (ptree != NULL)DeleteAllNodes(ptree->root);ptree->root = NULL;ptree->size = 0;
}/* local functions */
static void InOrder(const Trnode *root, void (*pfun)(Item item))
{if (root != NULL){InOrder(root->left, pfun);(*pfun)(root->item);InOrder(root->right, pfun);}
}static void DeleteAllNodes(Trnode *root)
{Trnode *pright;if (root != NULL){pright = root->right;DeleteAllNodes(root->left);free(root);DeleteAllNodes(pright);}
}static void AddNode(Trnode *new_node, Trnode *root)
{if (ToLeft(&new_node->item, &root->item)){if (root->left == NULL) /* empty subtree */root->left = new_node; /* so add node here */elseAddNode(new_node, root->left); /* else process subtree*/}else if (ToRight(&new_node->item, &root->item)){if (root->right == NULL)root->right = new_node;elseAddNode(new_node, root->right);}else /* should be no duplicates */{// if ( !strcmp(new_node->item.word, root->item.word) ) 按理来说执行不到这// root->item.n++; //相同的单词 次数加一}
}static bool ToLeft(const Item *i1, const Item *i2)
{int comp1;if ((comp1 = strcmp(i1->word, i2->word)) < 0) // 这改了return true;elsereturn false;
}static bool ToRight(const Item *i1, const Item *i2)
{int comp1;if ((comp1 = strcmp(i1->word, i2->word)) > 0) // 这也改了return true;elsereturn false;
}static Trnode *MakeNode(const Item *pi)
{Trnode *new_node;new_node = (Trnode *)malloc(sizeof(Trnode));if (new_node != NULL){new_node->item = *pi;new_node->left = NULL;new_node->right = NULL;}return new_node;
}static Pair SeekItem(const Item *pi, const Tree *ptree)
{Pair look;look.parent = NULL;look.child = ptree->root;if (look.child == NULL)return look; /* early return */while (look.child != NULL){if (ToLeft(pi, &(look.child->item))){look.parent = look.child;look.child = look.child->left;}else if (ToRight(pi, &(look.child->item))){look.parent = look.child;look.child = look.child->right;}else /* must be same if not to left or right */break; /* look.child is address of node with item */}return look; /* successful return */
}static void DeleteNode(Trnode **ptr)
/* ptr is address of parent member pointing to target node */
{Trnode *temp;if ((*ptr)->left == NULL){temp = *ptr;*ptr = (*ptr)->right;free(temp);}else if ((*ptr)->right == NULL){temp = *ptr;*ptr = (*ptr)->left;free(temp);}else /* deleted node has two children */{/* find where to reattach right subtree */for (temp = (*ptr)->left; temp->right != NULL;temp = temp->right)continue;temp->right = (*ptr)->right;temp = *ptr;*ptr = (*ptr)->left;free(temp);}
}
main.cpp:
/* petclub.c -- use a binary search tree */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "tree.h"char menu(void);
void addpet(Tree *pt, Item *temp);
void droppet(Tree *pt);
void showpets(const Tree *pt);
void findpet(const Tree *pt);
void printitem(Item item);
void uppercase(char *str);
char *s_gets(char *st, int n);int main()
{Tree pets;char choice;Item temp;FILE *fp;if ((fp = fopen("words.txt", "r")) == NULL) // 判断是否能打开{printf("Can't open words.txt\\n");exit(EXIT_FAILURE);}InitializeTree(&pets); // 初始化树while (fscanf(fp, "%s", temp.word) != EOF) // 读入二叉树{// printf("%s\\n", temp.word);addpet(&pets, &temp);}while ((choice = menu()) != 'q'){switch (choice){case 'l':showpets(&pets);break;case 'f':findpet(&pets);break;default:puts("Switching error");}puts("\\n");}DeleteAll(&pets);puts("\\nBye.");system("pause");return 0;
}char menu(void)
{int ch;puts("Nerfville Pet Club Membership Program");puts("Enter the letter corresponding to your choice:");puts("l) show list of pets f) find pets");puts("q) quit");while ((ch = getchar()) != EOF){while (getchar() != '\\n') /* discard rest of line */continue;ch = tolower(ch);if (strchr("lfq", ch) == NULL)puts("Please enter an l, f or q:");elsebreak;}if (ch == EOF) /* make EOF cause program to quit */ch = 'q';return ch;
}void addpet(Tree *pt, Item *temp)
{if (TreeIsFull(pt))puts("No room in the club!");else{uppercase(temp->word);temp->frequency = 1;AddItem(temp, pt);}
}void showpets(const Tree *pt)
{if (TreeIsEmpty(pt))puts("No entries!");elseTraverse(pt, printitem);
}void printitem(Item item)
{printf("Word: %-19s frequency: %-19d\\n", item.word,item.frequency);
}void findpet(const Tree *pt)
{Item temp;int frequency;if (TreeIsEmpty(pt)){puts("No entries!");return; /* quit function if tree is empty */}puts("Please enter word you wish to find:");s_gets(temp.word, SLEN);uppercase(temp.word);temp.frequency = 0;printf("%s", temp.word);if (frequency = InTree(&temp, pt))printf(" is a member %d of frequency.\\n", frequency);elseprintf(" is not a member.\\n");
}void uppercase(char *str)
{while (*str){*str = toupper(*str);str++;}
}
char *s_gets(char *st, int n)
{char *ret_val;char *find;ret_val = fgets(st, n, stdin);if (ret_val){find = strchr(st, '\\n'); // look for newlineif (find) // if the address is not NULL,*find = '\\0'; // place a null character thereelsewhile (getchar() != '\\n')continue; // dispose of rest of line}return ret_val;
}
words.txt:
butcher
cook
host
spy
master
cover
change
button
运行结果:
C:\\Users\\81228\\Documents\\Program\\VScode C Program\\chapter17\\17.7>g++ tree.c main.cpp -o mainC:\\Users\\81228\\Documents\\Program\\VScode C Program\\chapter17\\17.7>main
Nerfville Pet Club Membership Program
Enter the letter corresponding to your choice:
l) show list of pets f) find pets
q) quit
l
Word: BUTCHER frequency: 1
Word: BUTTON frequency: 1
Word: CHANGE frequency: 1
Word: COOK frequency: 1
Word: COVER frequency: 1
Word: HOST frequency: 1
Word: MASTER frequency: 1
Word: SPY frequency: 1Nerfville Pet Club Membership Program
Enter the letter corresponding to your choice:
l) show list of pets f) find pets
q) quit
f
Please enter word you wish to find:
cook
COOK is a member 1 of frequency.Nerfville Pet Club Membership Program
Enter the letter corresponding to your choice:
l) show list of pets f) find pets
q) quit
f
Please enter word you wish to find:
asas
ASAS is not a member.Nerfville Pet Club Membership Program
Enter the letter corresponding to your choice:
l) show list of pets f) find pets
q) quit
qBye.
请按任意键继续. . . C:\\Users\\81228\\Documents\\Program\\VScode C Program\\chapter17\\17.7>
8. 修改宠物俱乐部程序
修改宠物俱乐部程序,使所有同名的宠物存储在相同节点中的一个列表中。当用户选择查找一个宠物时,程序要求用户给出宠物名,而后列出所有具有此名字的宠物(连同它们的种类)。
代码:
tree.h:
/* tree.h -- binary search tree */
/* no duplicate items are allowed in this tree */
#ifndef _TREE_H_
#define _TREE_H_#include <stdbool.h>/* redefine Item as appropriate */
#define SLEN 20
#define MAXLISTS 3typedef struct item
{char petname[SLEN];char petkind[MAXLISTS][SLEN];int index;
} Item;#define MAXITEMS 10typedef struct trnode
{Item item;struct trnode *left; /* pointer to right branch */struct trnode *right; /* pointer to left branch */
} Trnode;typedef struct tree
{Trnode *root; /* pointer to root of tree */int size; /* number of items in tree */
} Tree;/* function prototypes *//* operation: initialize a tree to empty */
/* preconditions: ptree points to a tree */
/* postconditions: the tree is initialized to empty */
void InitializeTree(Tree *ptree);/* operation: determine if tree is empty */
/* preconditions: ptree points to a tree */
/* postconditions: function returns true if tree is */
/* empty and returns false otherwise */
bool TreeIsEmpty(const Tree *ptree);/* operation: determine if tree is full */
/* preconditions: ptree points to a tree */
/* postconditions: function returns true if tree is */
/* full and returns false otherwise */
bool TreeIsFull(const Tree *ptree);/* operation: determine number of items in tree */
/* preconditions: ptree points to a tree */
/* postconditions: function returns number of items in */
/* tree */
int TreeItemCount(const Tree *ptree);/* operation: add an item to a tree */
/* preconditions: pi is address of item to be added */
/* ptree points to an initialized tree */
/* postconditions: if possible, function adds item to */
/* tree and returns true; otherwise, */
/* the function returns false */
bool AddItem(const Item *pi, Tree *ptree);/* operation: find an item in a tree */
/* preconditions: pi points to an item */
/* ptree points to an initialized tree */
/* postconditions: function returns true if item is in */
/* tree and returns false otherwise */
bool InTree(const Item *pi, const Tree *ptree);/* operation: delete an item from a tree */
/* preconditions: pi is address of item to be deleted */
/* ptree points to an initialized tree */
/* postconditions: if possible, function deletes item */
/* from tree and returns true; */
/* otherwise the function returns false*/
bool DeleteItem(const Item *pi, Tree *ptree);/* operation: apply a function to each item in */
/* the tree */
/* preconditions: ptree points to a tree */
/* pfun points to a function that takes*/
/* an Item argument and has no return */
/* value */
/* postcondition: the function pointed to by pfun is */
/* executed once for each item in tree */
void Traverse(const Tree *ptree, void (*pfun)(Item item));/* operation: delete everything from a tree */
/* preconditions: ptree points to an initialized tree */
/* postconditions: tree is empty */
void DeleteAll(Tree *ptree);/* operation: 打印特定宠物的信息 */
/* preconditions: 接受一个待打印的项和初始化后的树 */
/* postconditions: 打印该宠物的信息 */
void SpecialPet(const Item *pi, const Tree *ptree);#endif
tree.c:
/* tree.c -- tree support functions */
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include "tree.h"/* local data type */
typedef struct pair
{Trnode *parent;Trnode *child;
} Pair;/* protototypes for local functions */
static Trnode *MakeNode(const Item *pi);
static bool ToLeft(const Item *i1, const Item *i2);
static bool ToRight(const Item *i1, const Item *i2);
static void AddNode(Trnode *new_node, Trnode *root);
static void InOrder(const Trnode *root, void (*pfun)(Item item));
static Pair SeekItem(const Item *pi, const Tree *ptree);
static void DeleteNode(Trnode **ptr);
static void DeleteAllNodes(Trnode *ptr);
static bool TestSame(const Item *i1, const Item *i2);
static void ToBeTrueIndex(Item *item);/* function definitions */
void InitializeTree(Tree *ptree)
{ptree->root = NULL;ptree->size = 0;
}bool TreeIsEmpty(const Tree *ptree)
{if (ptree->root == NULL)return true;elsereturn false;
}bool TreeIsFull(const Tree *ptree)
{if (ptree->size == MAXITEMS)return true;elsereturn false;
}int TreeItemCount(const Tree *ptree)
{return ptree->size;
}bool AddItem(const Item *pi, Tree *ptree)
{Trnode *new_node;Trnode *temp;if (TreeIsFull(ptree)){fprintf(stderr, "Tree is full\\n");return false; /* early return */}if ((temp = SeekItem(pi, ptree).child) != NULL) // 传回来的可能是名字相同 也可能是名字种类都相同{if (TestSame(pi, &temp->item) && (temp->item.index >= MAXLISTS)) // 如果种类也相同 就返回错误{fprintf(stderr, "Attempted to add duplicate item\\n");return false; /* early return */}else // 只是名字相同{ToBeTrueIndex(&temp->item);strcpy(temp->item.petkind[temp->item.index], pi->petkind[0]);// printf("%s:%s\\n", temp->item.petname, temp->item.petkind[0]);// printf("%s:%s\\n", temp->item.petname, temp->item.petkind[1]);return true;}}new_node = MakeNode(pi); /* points to new node */if (new_node == NULL){fprintf(stderr, "Couldn't create node\\n");return false; /* early return */}/* succeeded in creating a new node */ptree->size++;if (ptree->root == NULL) /* case 1: tree is empty */ptree->root = new_node; /* new node is tree root */else /* case 2: not empty */AddNode(new_node, ptree->root); /* add node to tree */return true; /* successful return */
}bool InTree(const Item *pi, const Tree *ptree)
{return (SeekItem(pi, ptree).child == NULL) ? false : true;
}bool DeleteItem(const Item *pi, Tree *ptree)
{Pair look;look = SeekItem(pi, ptree);if (look.child == NULL)return false;if (look.parent == NULL) /* delete root item */DeleteNode(&ptree->root);else if (look.parent->left == look.child)DeleteNode(&look.parent->left);elseDeleteNode(&look.parent->right);ptree->size--;return true;
}void Traverse(const Tree *ptree, void (*pfun)(Item item))
{if (ptree != NULL)InOrder(ptree->root, pfun);
}void DeleteAll(Tree *ptree)
{if (ptree != NULL)DeleteAllNodes(ptree->root);ptree->root = NULL;ptree->size = 0;
}// 有点纠结这算是接口还是内部函数 但感觉肯定不算内部函数
void SpecialPet(const Item *pi, const Tree *ptree)
{Trnode *temp;int i;temp = SeekItem(pi, ptree).child;printf("Pet: %-19s Kind:", temp->item.petname);for (i = 0; i <= temp->item.index; i++)printf(" %s", temp->item.petkind[i]);printf("\\n");
}/* local functions */
static void InOrder(const Trnode *root, void (*pfun)(Item item))
{if (root != NULL){InOrder(root->left, pfun);(*pfun)(root->item);InOrder(root->right, pfun);}
}static void DeleteAllNodes(Trnode *root)
{Trnode *pright;if (root != NULL){pright = root->right;DeleteAllNodes(root->left);free(root);DeleteAllNodes(pright);}
}static void AddNode(Trnode *new_node, Trnode *root)
{if (ToLeft(&new_node->item, &root->item)){if (root->left == NULL) /* empty subtree */root->left = new_node; /* so add node here */elseAddNode(new_node, root->left); /* else process subtree*/}else if (ToRight(&new_node->item, &root->item)){if (root->right == NULL)root->right = new_node;elseAddNode(new_node, root->right);}else /* should be no duplicates */{fprintf(stderr, "location error in AddNode()\\n");exit(1);}
}static bool ToLeft(const Item *i1, const Item *i2)
{int comp1;if ((comp1 = strcmp(i1->petname, i2->petname)) < 0)return true;// else if (comp1 == 0 && //不用比较种类// strcmp(i1->petkind, i2->petkind) < 0 )// return true;elsereturn false;
}static bool ToRight(const Item *i1, const Item *i2)
{int comp1;if ((comp1 = strcmp(i1->petname, i2->petname)) > 0)return true;// else if (comp1 == 0 && //不用比较种类// strcmp(i1->petkind, i2->petkind) > 0 )// return true;elsereturn false;
}static Trnode *MakeNode(const Item *pi)
{Trnode *new_node;new_node = (Trnode *)malloc(sizeof(Trnode));if (new_node != NULL){new_node->item = *pi;new_node->left = NULL;new_node->right = NULL;}new_node->item.index = 0; // 初始化节点的下标为0return new_node;
}static Pair SeekItem(const Item *pi, const Tree *ptree)
{Pair look;look.parent = NULL;look.child = ptree->root;if (look.child == NULL)return look; /* early return */while (look.child != NULL){if (ToLeft(pi, &(look.child->item))){look.parent = look.child;look.child = look.child->left;}else if (ToRight(pi, &(look.child->item))){look.parent = look.child;look.child = look.child->right;}else /* must be same if not to left or right */break; /* look.child is address of node with item */}return look; /* successful return */
}static void DeleteNode(Trnode **ptr)
/* ptr is address of parent member pointing to target node */
{Trnode *temp;if ((*ptr)->left == NULL){temp = *ptr;*ptr = (*ptr)->right;free(temp);}else if ((*ptr)->right == NULL){temp = *ptr;*ptr = (*ptr)->left;free(temp);}else /* deleted node has two children */{/* find where to reattach right subtree */for (temp = (*ptr)->left; temp->right != NULL;temp = temp->right)continue;temp->right = (*ptr)->right;temp = *ptr;*ptr = (*ptr)->left;free(temp);}
}static bool TestSame(const Item *i1, const Item *i2)
{int i;for (i = 0; i <= i2->index; i++)if (!strcmp(i1->petkind[0], i2->petkind[i])) // 有相同种类的返回Truereturn true;return false;
}static void ToBeTrueIndex(Item *item)
{++(item->index); // 指向下一个 下标
}
pets.c:
/* petclub.c -- use a binary search tree */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "tree.h"char menu(void);
void addpet(Tree *pt);
void droppet(Tree *pt);
void showpets(const Tree *pt);
void findpet(const Tree *pt);
void printitem(Item item);
void uppercase(char *str);
char *s_gets(char *st, int n);int main(void)
{Tree pets;char choice;InitializeTree(&pets);while ((choice = menu()) != 'q'){switch (choice){case 'a':addpet(&pets);break;case 'l':showpets(&pets);break;case 'f':findpet(&pets);break;case 'n':printf("%d pets in club\\n",TreeItemCount(&pets));break;case 'd':droppet(&pets);break;default:puts("Switching error");}puts("\\n");}DeleteAll(&pets);puts("Bye.");system("pause");return 0;
}char menu(void)
{int ch;puts("Nerfville Pet Club Membership Program");puts("Enter the letter corresponding to your choice:");puts("a) add a pet l) show list of pets");puts("n) number of pets f) find pets");puts("d) delete a pet q) quit");while ((ch = getchar()) != EOF){while (getchar() != '\\n') /* discard rest of line */continue;ch = tolower(ch);if (strchr("alrfndq", ch) == NULL)puts("Please enter an a, l, f, n, d, or q:");elsebreak;}if (ch == EOF) /* make EOF cause program to quit */ch = 'q';return ch;
}void addpet(Tree *pt)
{Item temp;if (TreeIsFull(pt))puts("No room in the club!");else{puts("Please enter name of pet:");s_gets(temp.petname, SLEN);puts("Please enter pet kind:");s_gets(temp.petkind[0], SLEN);uppercase(temp.petname);uppercase(temp.petkind[0]);AddItem(&temp, pt);}
}void showpets(const Tree *pt)
{if (TreeIsEmpty(pt))puts("No entries!");elseTraverse(pt, printitem);
}void printitem(Item item)
{int i;printf("Pet: %-19s Kind:", item.petname);for (i = 0; i <= item.index; i++)printf(" %s", item.petkind[i]);printf("\\n");
}void findpet(const Tree *pt)
{Item temp;if (TreeIsEmpty(pt)){puts("No entries!");return; /* quit function if tree is empty */}puts("Please enter name of pet you wish to find:");s_gets(temp.petname, SLEN);uppercase(temp.petname);printf("%s ", temp.petname);if (InTree(&temp, pt)){printf("is a member.\\n");SpecialPet(&temp, pt);}elseprintf("is not a member.\\n");
}void droppet(Tree *pt)
{Item temp;if (TreeIsEmpty(pt)){puts("No entries!");return; /* quit function if tree is empty */}puts("Please enter name of pet you wish to delete:");s_gets(temp.petname, SLEN);uppercase(temp.petname);printf("%s ", temp.petname);if (DeleteItem(&temp, pt))printf("is dropped from the club.\\n");elseprintf("is not a member.\\n");
}void uppercase(char *str)
{while (*str){*str = toupper(*str);str++;}
}
char *s_gets(char *st, int n)
{char *ret_val;char *find;ret_val = fgets(st, n, stdin);if (ret_val){find = strchr(st, '\\n'); // look for newlineif (find) // if the address is not NULL,*find = '\\0'; // place a null character thereelsewhile (getchar() != '\\n')continue; // dispose of rest of line}return ret_val;
}
运行结果:
C:\\Users\\81228\\Documents\\Program\\VScode C Program\\chapter17\\17.8>g++ tree.c pets.c -o petsC:\\Users\\81228\\Documents\\Program\\VScode C Program\\chapter17\\17.8>pets
Nerfville Pet Club Membership Program
Enter the letter corresponding to your choice:
a) add a pet l) show list of pets
n) number of pets f) find pets
d) delete a pet q) quit
a
Please enter name of pet:
peter
Please enter pet kind:
dogNerfville Pet Club Membership Program
Enter the letter corresponding to your choice:
a) add a pet l) show list of pets
n) number of pets f) find pets
d) delete a pet q) quit
a
Please enter name of pet:
peter
Please enter pet kind:
catNerfville Pet Club Membership Program
Enter the letter corresponding to your choice:
a) add a pet l) show list of pets
n) number of pets f) find pets
d) delete a pet q) quit
a
Please enter name of pet:
amy
Please enter pet kind:
fishNerfville Pet Club Membership Program
Enter the letter corresponding to your choice:
a) add a pet l) show list of pets
n) number of pets f) find pets
d) delete a pet q) quit
l
Pet: AMY Kind: FISH
Pet: PETER Kind: DOG CATNerfville Pet Club Membership Program
Enter the letter corresponding to your choice:
a) add a pet l) show list of pets
n) number of pets f) find pets
d) delete a pet q) quit
n
2 pets in clubNerfville Pet Club Membership Program
Enter the letter corresponding to your choice:
a) add a pet l) show list of pets
n) number of pets f) find pets
d) delete a pet q) quit
f
Please enter name of pet you wish to find:
peter
PETER is a member.
Pet: PETER Kind: DOG CATNerfville Pet Club Membership Program
Enter the letter corresponding to your choice:
a) add a pet l) show list of pets
n) number of pets f) find pets
d) delete a pet q) quit
q
Bye.
请按任意键继续. . . C:\\Users\\81228\\Documents\\Program\\VScode C Program\\chapter17\\17.8>