《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 array
ElemType *top; // top pointer of stack array
int 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 45
struct 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 45
struct 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 newline
if (find) // if the address is not NULL,
*find = '\0'; // place a null character there
else
while (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 films
C:\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 100
typedef 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 100
struct 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~99
return true;
else
return 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;
else
full = 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 newline
if (find) // if the address is not NULL,
*find = '\0'; // place a null character there
else
while (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 films
C:\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 queue
int processtime; // the number of consultation minutes desired
} Item;
/**/
#define MAXQUEUE 10
typedef 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 */
else
pq->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.0
bool newcustomer(double x); // is there a new customer?
Item customertime(long when); // set customer parameters
int main(void)
{
Queue line1;
Queue line2;
Item temp1; // new customer data
Item temp2;
int hours; // hours of simulation
int perhour; // average # of arrivals per hour
long cycle, cyclelimit; // loop counter, limit
long turnaways = 0; // turned away by full queue
long customers = 0; // joined the queue
long served = 0; // served during the simulation
long sum_line = 0; // cumulative line length
int wait_time1 = 0; // time until Sigmund is free
int wait_time2 = 0;
double min_per_cust; // average time between arrivals
long line_wait = 0; // cumulative time in line
InitializeQueue(&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)) // 如果都满了 走的顾客就+1
turnaways++;
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);
}
else
puts("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;
else
return 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 10
typedef 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 main
C:\Users\81228\Documents\Program\VScode C Program\chapter17\17.5>main
Enter a string, I will give you string of reverse!
ABCD
DCBA
Enter 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 1024
void 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;
}
else
answer = 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 10
typedef 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;
else
return false;
}
bool TreeIsFull(const Tree *ptree)
{
if (ptree->size == MAXITEMS)
return true;
else
return 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;
else
return 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);
else
DeleteNode(&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 */
else
AddNode(new_node, root->left); /* else process subtree*/
}
else if (ToRight(&new_node->item, &root->item))
{
if (root->right == NULL)
root->right = new_node;
else
AddNode(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;
else
return false;
}
static bool ToRight(const Item *i1, const Item *i2)
{
int comp1;
if ((comp1 = strcmp(i1->word, i2->word)) > 0) // 这也改了
return true;
else
return 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:");
else
break;
}
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!");
else
Traverse(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);
else
printf(" 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 newline
if (find) // if the address is not NULL,
*find = '\0'; // place a null character there
else
while (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 main
C:\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: 1
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:
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
q
Bye.
请按任意键继续. . .
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 3
typedef struct item
{
char petname[SLEN];
char petkind[MAXLISTS][SLEN];
int index;
} Item;
#define MAXITEMS 10
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 */
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;
else
return false;
}
bool TreeIsFull(const Tree *ptree)
{
if (ptree->size == MAXITEMS)
return true;
else
return 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);
else
DeleteNode(&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 */
else
AddNode(new_node, root->left); /* else process subtree*/
}
else if (ToRight(&new_node->item, &root->item))
{
if (root->right == NULL)
root->right = new_node;
else
AddNode(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;
else
return 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;
else
return 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; // 初始化节点的下标为0
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);
}
}
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])) // 有相同种类的返回True
return 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:");
else
break;
}
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!");
else
Traverse(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);
}
else
printf("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");
else
printf("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 newline
if (find) // if the address is not NULL,
*find = '\0'; // place a null character there
else
while (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 pets
C:\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:
dog
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:
cat
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:
amy
Please enter pet kind:
fish
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
l
Pet: AMY Kind: FISH
Pet: PETER Kind: DOG CAT
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
n
2 pets in club
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
f
Please enter name of pet you wish to find:
peter
PETER is a member.
Pet: PETER Kind: DOG CAT
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
q
Bye.
请按任意键继续. . .
C:\Users\81228\Documents\Program\VScode C Program\chapter17\17.8>