《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 
#include 
#include 
#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

答:

《C Primer Plus》第17章复习题与编程练习_第1张图片

8. 考虑复习题7构造的二叉树,根据本章的算法,删除单词food之后,各树是什么样子?

答:

《C Primer Plus》第17章复习题与编程练习_第2张图片

编程练习

1. 双向遍历链表

修改程序清单17.2,使其既能以正序又能以逆序显示电影列表。一种方法修改链表定义以使链表能被双向遍历;另一种方法是使用递归。

代码:

#include 
#include 
#include 

#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", &current->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);
}

运行结果:

《C Primer Plus》第17章复习题与编程练习_第3张图片

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 
#include 
#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 
#include  /* prototype for exit() */
#include 
#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  /* 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 
#include 
#include 
#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 
#include  /* prototype for exit() */
#include 
#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 

// 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 
#include 
#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 
#include  // for rand() and srand()
#include    // 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;
}

运行结果:

《C Primer Plus》第17章复习题与编程练习_第4张图片

5. 栈

编写一个程序,让您输入一个字符串。该程序将此字符串中的字符逐个地压入一个栈(请参见复习题5),然后弹出这些字符并显示。结果是将字符串按逆序显示。

代码:

stack.h:

#ifndef STACK_H_
#define STACK_H_

#include 

#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 
#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 
#include 
#include 
#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 
#include 
#include  //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;
}

运行结果:

《C Primer Plus》第17章复习题与编程练习_第5张图片

7. 统计文件中每个单词出现的次数

编写一个程序,能打开、读入一个文本文件并统计文件中每个单词出现的次数。用改进的二叉搜索树存储单词及出现的次数。程序读入文件后,会提供一个有三个选项的菜单。第一个选项为列出所有的单词连同其出现的次数。第二个选项为让您输入一个单词,程序报告该单词在文件中出现的次数。第三个选项为退出。

代码:

tree.h:

/* tree.h -- binary search tree                          */
/*           no duplicate items are allowed in this tree */
#ifndef _TREE_H_
#define _TREE_H_

#include 

/* 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 
#include 
#include 
#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 
#include 
#include 
#include 
#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 

/* 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 
#include 
#include 
#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 
#include 
#include 
#include 
#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>  

你可能感兴趣的:(C,Primer,Plus,c语言,链表,数据结构,C,Primer,Plus)