C Primer Plus第十七章编程练习答案

news2024/11/25 21:52:03

学完C语言之后,我就去阅读《C Primer Plus》这本经典的C语言书籍,对每一章的编程练习题都做了相关的解答,仅仅代表着我个人的解答思路,如有错误,请各位大佬帮忙点出!

有些题目函数定义在书本存在,这里就不提供需要的函数接口代码,测试截图也就不弄了。

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;
};
void print_reverse_list(struct film* head)
{
    if (head->next != NULL)
    {
        print_reverse_list(head->next);
    }
    printf("Movie: %s  Rating: %d\n", head->title, head->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');
        if (find)
        {
            *find = '\0';
        }
        else
        {
            while (getchar() != '\n')
                continue;
        }
    }
    return ret_val;
}
int main(void)
{
    struct film* head = NULL;
    struct film* prev, * current;
    char input[TSIZE];

    printf("Enter first movie title:\n");
    while (s_gets(input, TSIZE) != NULL && input[0] != '\0')
    {
        current = (struct film*)malloc(sizeof(struct film));
        if (head == NULL)
        {
            head = current;
        }
        else
        {
            prev->next = current;
        }
        current->next = NULL;
        strcpy(current->title, input);
        printf("Enter your rating <0-10>:\n");
        scanf("%d", &current->rating);
        while (getchar() != '\n')
            continue;
        printf("Enter next movie title (empty line to stop):\n");
        prev = current;
    }

    if (head == NULL)
    {
        printf("No data entered. ");
    }
    else
    {
        printf("Here is the movie list:\n");
    }
    current = head;
    while (current != NULL)
    {
        printf("Movie: %s  Rating: %d\n",
            current->title, current->rating);
        current = current->next;
    }
    if (head != NULL)
    {
        printf("\nHere is the list in reverse order:\n");
        print_reverse_list(head);
    }
    current = head;
    while (current != NULL)
    {
        free(current);
        current = current->next;
    }
    printf("Bye!\n");

    return 0;
}

2.假设list.h(程序清单17.3)使用下面的list定义:

typedef struct list

{ Node * head; /* 指向list的开头 */

Node * end;/* 指向list的末尾 */ } List;

重写 list.c(程序清单 17.5)中的函数以适应新的定义,并通过 films.c(程序清单 17.4)测试最终的代码。

#ifndef LIST_H_
#define LIST_H_
#include <stdbool.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

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

3.假设list.h(程序清单17.3)使用下面的list定义:

#define MAXSIZE 100

typedef struct list {

Item entries[MAXSIZE]; /* 内含项的数组 */

int items; /* list中的项数 */ } List;

重写 list.c(程序清单 17.5)中的函数以适应新的定义,并通过 films.c(程序清单 17.4)测试最终的代码。

#ifndef LIST_H_
#define LIST_H_
#include <stdbool.h>
#define TSIZE 45

struct film
{
    char title[TSIZE];
    int rating;
};

typedef struct film Item;

#define MAXSIZE 100
typedef struct list
{
    Item entries[MAXSIZE];
    int items;
} 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

#include <stdio.h>
#include <stdlib.h>
#include "list.h"

void InitializeList(List *plist)
{
    plist->items = 0;
    return;
}

bool ListIsEmpty(const List *plist)
{
    return 0 == plist->items;
}

bool ListIsFull(const List *plist)
{
    return MAXSIZE == plist->items;
}

unsigned int ListItemCount(const List *plist)
{
    return plist->items;
}

bool AddItem(Item item, List *plist)
{
    if (plist->items == MAXSIZE) //若项目数达到最大值则不可添加;
    {
        return false;
    }
    else //项目数未达到最大值则添加新项目到项目数组中并更新项的数量;
    {
        plist->entries[plist->items++] = item;
        return true;
    }
}

void Traverse(const List *plist, void (*pfun)(Item item))
{
    int i;

    for (i = 0; i < plist->items; i++)
    {
        (*pfun)(plist->entries[i]); //使pun指向的函数作用于项目数组中的每一项;
    }
    return;
}

void EmptyTheList(List *plist)
{
    plist->items = 0;
    return;
}

4.重写mall.c(程序清单17.7),用两个队列模拟两个摊位。

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "queue.h"
#define N 2
#define MIN_PER_HR 60.0

static struct
{
    Queue line;
    int hours, perhour, wait_time;
    long cycle, cyclelimit, turnaways;
    long customers, served, sum_line, line_wait;
    double min_per_cust;
} malls[N]; //模拟2个摊位;

bool newcustomer(double x)
{
    return rand() * x / RAND_MAX < 1 ? true : false;
}

Item customertime(long when)
{
    Item cust;

    cust.processtime = rand() % 3 + 1;
    cust.arrive = when;

    return cust;
}

int main(void)
{
    int i;
    Item temp;

    srand((unsigned int)time(0));
    puts("Case Study: Sigmund Lander's Advice Booth");
    puts("Enter the number of simulation hours for the first mall:");
    scanf("%d", &malls[0].hours);
    malls[0].cyclelimit = MIN_PER_HR * malls[0].hours;

    puts("Enter the number of simulation hours for the second mall:");
    scanf("%d", &malls[1].hours);
    malls[1].cyclelimit = MIN_PER_HR * malls[1].hours;

    puts("Enter the average number of customers per hourfor the first mall:");
    scanf("%d", &malls[0].perhour);
    malls[0].min_per_cust = MIN_PER_HR / malls[0].perhour;

    puts("Enter the average number of customers per hourfor the second mall:");
    scanf("%d", &malls[1].perhour);
    malls[1].min_per_cust = MIN_PER_HR / malls[1].perhour;

    for (i = 0; i < N; i++) //使用循环来控制2个摊位;
    {
        for (malls[i].cycle = 0; malls[i].cycle < malls[i].cyclelimit; malls[i].cycle++)
        {
            if (newcustomer(malls[i].min_per_cust))
            {
                if (QueueIsFull(&malls[i].line))
                {
                    malls[i].turnaways++;
                }
                else
                {
                    malls[i].customers++;
                    temp = customertime(malls[i].cycle);
                    EnQueue(temp, &malls[i].line);
                }
            }
            if (malls[i].wait_time <= 0 && !QueueIsEmpty(&malls[i].line))
            {
                DeQueue(&temp, &malls[i].line);
                malls[i].wait_time = temp.processtime;
                malls[i].line_wait += malls[i].cycle - temp.arrive;
                malls[i].served++;
            }
            if (malls[i].wait_time > 0)
            {
                malls[i].wait_time--;
            }
            malls[i].sum_line += QueueItemCount(&malls[i].line);
        }
        if (malls[i].customers > 0)
        {
            printf("\nHere are some messages for the %s mall:\n", 0 == i ? "first" : "second");
            printf("customers accepted: %ld\n", malls[i].customers);
            printf("  customers served: %ld\n", malls[i].served);
            printf("         turnaways: %ld\n", malls[i].turnaways);
            printf("average queue size: %.2f\n",
                (double)malls[i].sum_line / malls[i].cyclelimit);
            printf(" average wait time: %.2f minutes\n",
                (double)malls[i].line_wait / malls[i].served);
        }
        else
        {
            printf("No customers for the %s mall!\n", 0 == i ? "first" : "second");
        }
        EmptyTheQueue(&malls[i].line);
    }
    puts("Bye!");

    return 0;
}

5.编写一个程序,提示用户输入一个字符串。然后该程序把该字符串的 字符逐个压入一个栈(参见复习题5),然后从栈中弹出这些字符,并显示 它们。结果显示为该字符串的逆序。

#include <stdio.h>
#include <string.h>
#include "stack.h"
#define SLEN 81
char* s_gets(char* st, int n)
{
    char* find;
    char* ret_val;

    ret_val = fgets(st, n, stdin);
    if (ret_val)
    {
        find = strchr(st, '\n');
        if (find)
        {
            *find = '\0';
        }
        else
        {
            while (getchar() != '\n')
                continue;
        }
    }
    return ret_val;
}

int main(void)
{
    int i;
    stack st;
    item ch, temp[SLEN];

    init(&st);
    printf("Please enter a string (EOF to quit):\n");
    while (s_gets(temp, SLEN) != NULL)
    {
        i = 0;
        while (temp[i] != '\0')
        {
            push(&st, temp[i++]);
        }
        printf("Reversing order:\n");
        while (!isempty(&st))
        {
            pop(&st, &ch); //顺序出栈即可得到原字符串的逆序;
            putchar(ch);
        }
        puts("\nYou can enter a string again (EOF to quit):");
    }
    puts("Done.");

    return 0;
}

#ifndef STACK_H_
#define STACK_H_
#include <stdbool.h>
#define MAXSIZE 100

typedef char item; //栈的数据类型为item类型;

typedef struct
{
    item data[MAXSIZE];
    int top;
} stack;

void init(stack *st); //栈的初始化函数;

bool isempty(stack *st); //判断栈是否为空;

bool isfull(stack *st); //判断栈是否已满;

bool push(stack *st, item val); //令元素入栈;

bool pop(stack *st, item *val); //令元素出栈;

#endif

#include <stdio.h>
#include "stack.h"

void init(stack *st)
{
    st->top = 0;
    return;
}

bool isempty(stack *st)
{
    return 0 == st->top;
}

bool isfull(stack *st)
{
    return MAXSIZE == st->top;
}

bool push(stack *st, item val)
{
    if (isfull(st))
    {
        return false;
    }
    else
    {
        st->data[st->top++] = val;
        return true;
    }
}

bool pop(stack *st, item *val)
{
    if (isempty(st))
    {
        return false;
    }
    else
    {
        *val = st->data[--st->top];
        return true;
    }
}

6.编写一个函数接受 3 个参数:一个数组名(内含已排序的整数)、该 数组的元素个数和待查找的整数。如果待查找的整数在数组中,那么该函数 返回 1;如果该数不在数组中,该函数则返回 0。用二分查找法实现。

#include <stdio.h>
#define SIZE 10
int binary_search(const int sorted[], int size, int val)
{
    int mid;
    int min = 0;
    int max = size - 1;
    int found = 0;

    while (min < max)
    {
        mid = (min + max) / 2;
        if (val < sorted[mid])
        {
            max = mid - 1;
        }
        else if (val > sorted[mid])
        {
            min = mid + 1;
        }
        else
        {
            found = 1;
            break;
        }
    }
    if (sorted[min] == val)
    {
        found = 1;
    }
    return found;
}
int main(void)
{
    int num, found;
    int nums[SIZE] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

    printf("Please enter a number for searching (q to quit): ");
    while (scanf("%d", &num) == 1)
    {
        found = binary_search(nums, SIZE, num);
        if (1 == found)
        {
            printf("%d exists in the array.\n", num);
        }
        else
        {
            printf("%d doesn't exist in the array.\n", num);
        }
        printf("You can enter again (q to quit): ");
    }
    puts("Done.");

    return 0;
}

7.编写一个程序,打开和读取一个文本文件,并统计文件中每个单词出 现的次数。用改进的二叉查找树储存单词及其出现的次数。程序在读入文件 后,会提供一个有3个选项的菜单。第1个选项是列出所有的单词和出现的次 数。第2个选项是让用户输入一个单词,程序报告该单词在文件中出现的次 数。第3个选项是退出。

#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include "tree.h"
#define SLEN 81
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');
        if (find)
        {
            *find = '\0';
        }
        else
        {
            while (getchar() != '\n')
                continue;
        }
    }
    return ret_val;
}

int menu(void)
{
    int ch;

    puts("==============================================");
    puts("           Word counting program");
    puts("Enter the letter corresponding to your choice:");
    puts("     s) show word list      f) find a word");
    puts("     q) quit");
    puts("==============================================");
    printf("Please you choose: ");
    while (ch = get_first(), NULL == strchr("sfq", ch))
    {
        printf("Please enter s, f or q: ");
    }
    return ch;
}

void showwords(const Tree* pt)
{
    if (TreeIsEmpty(pt)) //使用二叉树存储的单词若为空则表示无单词;
    {
        puts("No words in this text.");
    }
    else
    {
        Traverse(pt, print_all_items);
    }
    return;
}

void findword(const Tree* pt)
{
    char word[SLEN];
    Item entry;
    const Item* pi;

    if (TreeIsEmpty(pt))
    {
        puts("No words in this text.");
        return;
    }
    printf("Please enter a word: ");
    scanf("%80s", word);
    eatline();
    strcpy(entry.wrd, word);      //把word数组中的单词复制到二叉树的项目中;
    pi = WhereInTree(&entry, pt); //寻找单词在二叉树中的位置;
    if (NULL == pi)
    {
        printf("Word %s doesn't exist in this text.\n", word);
    }
    else
    {
        printf("Word %s appeared %d times in this text.\n", word, pi->count);
    }
    return;
}

void print_all_items(Item item)
{
    printf("Word %s appeared %d times totally in this text.\n", item.wrd, item.count);
    return;
}

int get_first(void)
{
    int ch;

    do
    {
        ch = tolower(getchar());
    } while (isspace(ch));
    eatline();
    return ch;
}

void eatline(void)
{
    while (getchar() != '\n')
        continue;
    return;
}

int main(void)
{
    Tree wordcount;
    FILE* fp;
    char filename[SLEN];
    char word[SLEN];
    Item entry;
    char choice;

    printf("Please enter a filename: ");
    s_gets(filename, SLEN);

    if ((fp = fopen(filename, "r")) == NULL)
    {
        fprintf(stderr, "Can't open file %s\n", filename);
        exit(EXIT_FAILURE);
    }
    InitializeTree(&wordcount); //初始化一个二叉树;
    while (fscanf(fp, "%80s", word) == 1 && !TreeIsFull(&wordcount))
    {
        strcpy(entry.wrd, word);
        AddItem(&entry, &wordcount);
    }
    while ((choice = menu()) != 'q')
    {
        switch (choice)
        {
        case 's':
        {
            showwords(&wordcount);
            break;
        }
        case 'f':
        {
            findword(&wordcount);
            break;
        }
        }
        printf("\n\n\n\n\n\n\n\n\n\n");
    }
    DeleteAll(&wordcount);
    if (fclose(fp) != 0)
    {
        fprintf(stderr, "Can't close file %s\n", filename);
    }
    puts("Done.");

    return 0;
}

#ifndef _TREE_H_
#define _TREE_H_
#include <stdbool.h>
#define SLEN 81

typedef struct item
{
    char wrd[SLEN];
    int count;
} Item;

#define MAXITEMS 100
typedef struct node
{
    Item item;
    struct node *left;
    struct node *right;
} Node;

typedef struct tree
{
    Node *root;
    int size;
} Tree;

void InitializeTree(Tree *ptree);

bool TreeIsEmpty(const Tree *ptree);

bool TreeIsFull(const Tree *ptree);

int TreeItemCount(const Tree *ptree);

bool AddItem(const Item *pi, Tree *ptree);

bool InTree(const Item *pi, const Tree *ptree);

bool DeleteItem(const Item *pi, Tree *ptree);

void Traverse(const Tree *ptree, void (*pfun)(Item item));

void DeleteAll(Tree *ptree);

const Item *WhereInTree(const Item *pi, const Tree *ptree);

#endif


#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>
#include "tree.h"

typedef struct pair
{
    Node *parent;
    Node *child;
} Pair;

static Node *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(Node *new_node, Node *root);
static void InOrder(const Node *root, void (*pfun)(Item item));
static Pair SeekItem(const Item *pi, const Tree *ptree);
static void DeleteNode(Node **ptr);
static void DeleteAllNodes(Node *ptr);

void InitializeTree(Tree *ptree)
{
    ptree->root = NULL;
    ptree->size = 0;
    return;
}

bool TreeIsEmpty(const Tree *ptree)
{
    return NULL == ptree->root;
}

bool TreeIsFull(const Tree *ptree)
{
    return MAXITEMS == ptree->size;
}

int TreeItemCount(const Tree *ptree)
{
    return ptree->size;
}

bool AddItem(const Item *pi, Tree *ptree)
{
    Node *new_node;
    Pair seek;

    if (TreeIsFull(ptree))
    {
        fprintf(stderr, "No memory available!\n");
        return false;
    }
    if ((seek = SeekItem(pi, ptree)).child != NULL)
    {
        seek.child->item.count++;
        return true;
    }
    new_node = MakeNode(pi);
    if (new_node == NULL)
    {
        fprintf(stderr, "Memory allocation failed!\n");
        exit(EXIT_FAILURE);
    }
    ptree->size++;
    if (ptree->root == NULL)
    {
        ptree->root = new_node;
    }
    else
    {
        AddNode(new_node, ptree->root);
    }
    return true;
}

bool InTree(const Item *pi, const Tree *ptree)
{
    return (SeekItem(pi, ptree).child == NULL) ? false : true;
}

const Item *WhereInTree(const Item *pi, const Tree *ptree)
{
    Node *pn;

    pn = SeekItem(pi, ptree).child;
    return NULL == pn ? NULL : &(pn->item);
}

bool DeleteItem(const Item *pi, Tree *ptree)
{
    Pair look;
    look = SeekItem(pi, ptree);

    if (look.child == NULL)
    {
        return false;
    }
    if (look.child->item.count > 0)
    {
        look.child->item.count--;
    }
    else
    {
        if (look.parent == NULL)
        {
            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);
    }
    return;
}

void DeleteAll(Tree *ptree)
{
    if (ptree != NULL)
    {
        DeleteAllNodes(ptree->root);
    }
    ptree->root = NULL;
    ptree->size = 0;
    return;
}

static void InOrder(const Node *root, void (*pfun)(Item item))
{
    if (root != NULL)
    {
        InOrder(root->left, pfun);
        (*pfun)(root->item);
        InOrder(root->right, pfun);
    }
    return;
}

static void DeleteAllNodes(Node *root)
{
    Node *pright;

    if (root != NULL)
    {
        pright = root->right;
        DeleteAllNodes(root->left);
        free(root);
        DeleteAllNodes(pright);
    }
    return;
}

static void AddNode(Node *new_node, Node *root)
{
    if (ToLeft(&new_node->item, &root->item))
    {
        if (root->left == NULL)
        {
            root->left = new_node;
        }
        else
        {
            AddNode(new_node, root->left);
        }
    }
    else if (ToRight(&new_node->item, &root->item))
    {
        if (root->right == NULL)
        {
            root->right = new_node;
        }
        else
        {
            AddNode(new_node, root->right);
        }
    }
    else
    {
        fprintf(stderr, "Can't add repetitive item!\n");
        exit(EXIT_FAILURE);
    }
    return;
}

static bool ToLeft(const Item *i1, const Item *i2)
{
    return strcmp(i1->wrd, i2->wrd) < 0 ? true : false;
}

static bool ToRight(const Item *i1, const Item *i2)
{
    return strcmp(i1->wrd, i2->wrd) > 0 ? true : false;
}

static Node *MakeNode(const Item *pi)
{
    Node *new_node;

    new_node = (Node *)malloc(sizeof(Node));
    if (new_node != NULL)
    {
        new_node->item = *pi;
        new_node->item.count = 1;
        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;
    }
    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
        {
            break;
        }
    }
    return look;
}

static void DeleteNode(Node **ptr)
{
    Node *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
    {
        for (temp = (*ptr)->left; temp->right != NULL; temp = temp->right)
        {
            continue;
        }
        temp->right = (*ptr)->right;
        temp = *ptr;
        *ptr = (*ptr)->left;
        free(temp);
    }
    return;
}

8.修改宠物俱乐部程序,把所有同名的宠物都储存在同一个节点中。当 用户选择查找宠物时,程序应询问用户该宠物的名字,然后列出该名字的所 有宠物(及其种类)。

#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include "tree.h"

int 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')
            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)
    {
        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);
        my_malloc(&temp); //分配内存至项目中的指针域;
        puts("Please enter pet kind:");
        s_gets(temp.many_petkinds->petkind, SLEN);
        uppercase(temp.petname);
        uppercase(temp.many_petkinds->petkind);
        AddItem(&temp, pt);
        free(temp.many_petkinds);
    }
    return;
}

void showpets(const Tree* pt)
{
    if (TreeIsEmpty(pt))
    {
        puts("No entries!");
    }
    else
    {
        Traverse(pt, printitem);
    }
    return;
}

void printitem(Item item)
{
    if (1 == item.pets_count) //只有一个同名宠物的情况;
    {
        printf("Pet: %-19s  Kind: %-19s\n", item.petname,
            item.many_petkinds->petkind);
    }
    else //结点中包含有多个同名不同种宠物的情况;
    {
        print_all_pets(item);
    }
    return;
}

void findpet(const Tree* pt)
{
    Item temp;

    if (TreeIsEmpty(pt))
    {
        puts("No entries!");
        return;
    }
    puts("Please enter name of pet you wish to find:");
    s_gets(temp.petname, SLEN);
    uppercase(temp.petname);
    if (InTree(&temp, pt))
    {
        printf("All kinds of the %s pets:\n", temp.petname);
        my_traverse(pt->root, print_same_pets, temp.petname);
        //若是此宠物存在于俱乐部中则打印所有相同种类的宠物;
    }
    else
    {
        printf("%s is not a member.\n", temp.petname);
    }
    return;
}

void droppet(Tree* pt)
{
    Item temp;

    if (TreeIsEmpty(pt))
    {
        puts("No entries!");
        return;
    }
    puts("Please enter name of pet you wish to delete:");
    s_gets(temp.petname, SLEN);
    my_malloc(&temp); //分配内存至项目中的指针域;
    puts("Please enter pet kind:");
    s_gets(temp.many_petkinds->petkind, SLEN);
    uppercase(temp.petname);
    uppercase(temp.many_petkinds->petkind);
    printf("%s the %s ", temp.petname, temp.many_petkinds->petkind);
    if (DeleteItem(&temp, pt))
    {
        printf("is dropped from the club.\n");
    }
    else
    {
        printf("is not a member.\n");
    }
    free(temp.many_petkinds);
    return;
}

void uppercase(char* str)
{
    while (*str)
    {
        *str = toupper(*str);
        str++;
    }
    return;
}

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');
        if (find)
        {
            *find = '\0';
        }
        else
        {
            while (getchar() != '\n')
                continue;
        }
    }
    return ret_val;
}

void print_all_pets(Item item)
{
    Kind* temp = item.many_petkinds;

    while (temp != NULL)
    {
        printf("Pet: %-19s  Kind: %-19s\n", item.petname,
            temp->petkind);
        temp = temp->next;
    }
    return;
}

void my_malloc(Item* item)
{
    if ((item->many_petkinds = (Kind*)malloc(sizeof(Kind))) == NULL)
    {
        fprintf(stderr, "Memory allocation failed!\n");
        exit(EXIT_FAILURE);
    }
    return;
}

void print_same_pets(Item item, const char* str)
{
    Kind* temp = item.many_petkinds;

    while (temp != NULL)
    {
        if (0 == strcmp(item.petname, str)) //打印名字相同的不同种类的宠物;
        {
            printf("Pet: %-19s  Kind: %-19s\n", item.petname,
                temp->petkind);
        }
        temp = temp->next;
    }
    return;
}

void my_traverse(const Trnode* root, void (*pfun)(Item item, const char* temp), const char* str)
{
    if (root != NULL)
    {
        my_traverse(root->left, pfun, str);
        (*pfun)(root->item, str);
        my_traverse(root->right, pfun, str);
    }
    return;
}

void pets_count(int* count, int* temp)
{
    *count -= *temp;
    *temp += *count;
    return;
}
int main(void)
{
    Tree pets;
    int choice;
    int count, temp;
    count = temp = 0;

    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':
        {
            count = TreeItemCount(&pets);
            pets_count(&count, &temp);
            printf("%d pets in club\n", count);
            break;
        }
        case 'd':
        {
            droppet(&pets);
            break;
        }
        default:
        {
            puts("Switching error");
        }
        }
    }
    DeleteAll(&pets);
    puts("Bye.");

    return 0;
}

#ifndef _TREE_H_
#define _TREE_H_
#include <stdbool.h>

#define SLEN 20

typedef struct kind
{
    char petkind[SLEN];
    struct kind *next;
} Kind;
//在二叉树接口中添加列表保存同名不同类的宠物;

typedef struct item
{
    char petname[SLEN];
    Kind *many_petkinds;
    int pets_count;
} Item;

#define MAXITEMS 10

typedef struct trnode
{
    Item item;
    struct trnode *left;
    struct trnode *right;
} Trnode;

typedef struct tree
{
    Trnode *root;
    int size;
} Tree;

void InitializeTree(Tree *ptree);

bool TreeIsEmpty(const Tree *ptree);

bool TreeIsFull(const Tree *ptree);

int TreeItemCount(const Tree *ptree);

bool AddItem(const Item *pi, Tree *ptree);

bool InTree(const Item *pi, const Tree *ptree);

bool DeleteItem(const Item *pi, Tree *ptree);

void Traverse(const Tree *ptree, void (*pfun)(Item item));

void DeleteAll(Tree *ptree);

#endif

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "tree.h"

typedef struct pair
{
    Trnode *parent;
    Trnode *child;
} Pair;

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 int all_pets_numbers(const Trnode *root);

void InitializeTree(Tree *ptree)
{
    ptree->root = NULL;
    ptree->size = 0;
    return;
}

bool TreeIsEmpty(const Tree *ptree)
{
    return NULL == ptree->root;
}

bool TreeIsFull(const Tree *ptree)
{
    return MAXITEMS == ptree->size;
}

int TreeItemCount(const Tree *ptree)
{
    return all_pets_numbers(ptree->root); //获取俱乐部中所有宠物的数量;
}

bool AddItem(const Item *pi, Tree *ptree)
{
    Trnode *find;
    Trnode *new_node;

    if (TreeIsFull(ptree))
    {
        fprintf(stderr, "Tree is full\n");
        return false;
    }
    if ((find = SeekItem(pi, ptree).child) != NULL)
    {
        Kind *temp;
        Kind *node;
        for (temp = find->item.many_petkinds; temp != NULL; temp = temp->next)
        {
            if (strcmp(pi->many_petkinds->petkind, temp->petkind) == 0)
            {
                break;
            }
        }
        if (temp != NULL) //若temp为NULL则说明用户输入的宠物名字和种类与俱乐部中宠物相重复,故无法添加;
        {
            fprintf(stderr, "Can't add duplicate item!\n");
            return false;
        }
        else
        {
            if ((node = (Kind *)malloc(sizeof(Kind))) == NULL)
            {
                fprintf(stderr, "Memory allocation failed!\n");
                return false;
            }
            else
            {
                strcpy(node->petkind, pi->many_petkinds->petkind);
                node->next = NULL;
                for (temp = find->item.many_petkinds; temp->next != NULL; temp = temp->next)
                {
                    continue;
                }
                temp->next = node;
                find->item.pets_count++;
                return true;
            }
        }
    }
    new_node = MakeNode(pi);
    if (new_node == NULL)
    {
        fprintf(stderr, "Couldn't create node.\n");
        return false;
    }
    ptree->size++;
    if (ptree->root == NULL)
    {
        ptree->root = new_node;
    }
    else
    {
        AddNode(new_node, ptree->root);
    }
    return true;
}

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.child->item.pets_count != 1) //结点中有多个同名不同类的宠物;
    {
        //↓使用链表顺序遍历找到符合用户输入的宠物;
        Kind *prior;
        Kind *current;
        for (prior = current = look.child->item.many_petkinds; current != NULL; current = current->next)
        {
            if (strcmp(current->petkind, pi->many_petkinds->petkind) == 0)
            {
                break;
            }
            prior = current;
        }
        if (current != NULL) //找到用户输入种类的宠物;
        {
            prior->next = current->next;
            free(current);
            look.child->item.pets_count--;
            return true;
        }
        else
        {
            return false;
        }
    }
    else
    {
        //↓若用户输入的宠物只有一种且俱乐部中存在此种宠物则删除整个结点;
        if (0 == strcmp(look.child->item.many_petkinds->petkind, pi->many_petkinds->petkind))
        {
            if (look.parent == NULL)
            {
                DeleteNode(&ptree->root);
            }
            else if (look.parent->left == look.child)
            {
                DeleteNode(&look.parent->left);
            }
            else
            {
                DeleteNode(&look.parent->right);
            }
            ptree->size--;
            return true;
        }
        else //若用户输入的宠物种类不存在则返回false;
        {
            return false;
        }
    }
}

void Traverse(const Tree *ptree, void (*pfun)(Item item))
{
    if (ptree != NULL)
    {
        InOrder(ptree->root, pfun);
    }
    return;
}

void DeleteAll(Tree *ptree)
{
    if (ptree != NULL)
    {
        DeleteAllNodes(ptree->root);
    }
    ptree->root = NULL;
    ptree->size = 0;
    return;
}

static void InOrder(const Trnode *root, void (*pfun)(Item item))
{
    if (root != NULL)
    {
        InOrder(root->left, pfun);
        (*pfun)(root->item);
        InOrder(root->right, pfun);
    }
    return;
}

static void DeleteAllNodes(Trnode *root)
{
    Trnode *pright;

    if (root != NULL)
    {
        pright = root->right;
        DeleteAllNodes(root->left);
        Kind *temp;
        while (root->item.many_petkinds != NULL)
        {
            temp = root->item.many_petkinds->next;
            free(root->item.many_petkinds);
            root->item.many_petkinds = temp;
        }
        free(root);
        DeleteAllNodes(pright);
    }
    return;
}

static void AddNode(Trnode *new_node, Trnode *root)
{
    if (ToLeft(&new_node->item, &root->item))
    {
        if (root->left == NULL)
        {
            root->left = new_node;
        }
        else
        {
            AddNode(new_node, root->left);
        }
    }
    else if (ToRight(&new_node->item, &root->item))
    {
        if (root->right == NULL)
        {
            root->right = new_node;
        }
        else
        {
            AddNode(new_node, root->right);
        }
    }
    else
    {
        fprintf(stderr, "location error in AddNode()\n");
        exit(1);
    }
    return;
}

static bool ToLeft(const Item *i1, const Item *i2)
{
    return strcmp(i1->petname, i2->petname) < 0 ? true : false;
}

static bool ToRight(const Item *i1, const Item *i2)
{
    return strcmp(i1->petname, i2->petname) > 0 ? true : false;
}

static Trnode *MakeNode(const Item *pi)
{
    Kind *temp;
    Trnode *new_node;

    if ((new_node = (Trnode *)malloc(sizeof(Trnode))) == NULL)
    {
        fprintf(stderr, "Memory allocation failed!\n");
        exit(EXIT_FAILURE);
    }
    if ((temp = (Kind *)malloc(sizeof(Kind))) == NULL)
    {
        fprintf(stderr, "Memory allocation failed!\n");
        exit(EXIT_FAILURE);
    }
    strcpy(new_node->item.petname, pi->petname);
    strcpy(temp->petkind, pi->many_petkinds->petkind);
    temp->next = NULL;
    new_node->item.many_petkinds = temp;
    new_node->item.pets_count = 1;
    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;
    }
    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
        {
            break;
        }
    }
    return look;
}

static void DeleteNode(Trnode **ptr)
{
    Kind *tp;
    Trnode *temp;

    if ((*ptr)->left == NULL)
    {
        temp = *ptr;
        *ptr = (*ptr)->right;
    }
    else if ((*ptr)->right == NULL)
    {
        temp = *ptr;
        *ptr = (*ptr)->left;
    }
    else
    {
        for (temp = (*ptr)->left; temp->right != NULL; temp = temp->right)
        {
            continue;
        }
        temp->right = (*ptr)->right;
        temp = *ptr;
        *ptr = (*ptr)->left;
    }
    while (temp->item.many_petkinds != NULL)
    {
        tp = temp->item.many_petkinds->next;
        free(temp->item.many_petkinds);
        temp->item.many_petkinds = tp;
    }
    free(temp);
    return;
}

static int all_pets_numbers(const Trnode *root)
{
    static int count = 0;

    if (root != NULL)
    {
        all_pets_numbers(root->left);
        count += root->item.pets_count; //使用递归累加所有结点中的同名不同类的宠物数量;
        all_pets_numbers(root->right);
    }
    return count;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/598898.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

路径规划算法:基于鸽群优化的路径规划算法- 附代码

路径规划算法&#xff1a;基于鸽群优化的路径规划算法- 附代码 文章目录 路径规划算法&#xff1a;基于鸽群优化的路径规划算法- 附代码1.算法原理1.1 环境设定1.2 约束条件1.3 适应度函数 2.算法结果3.MATLAB代码4.参考文献 摘要&#xff1a;本文主要介绍利用智能优化算法鸽群…

Python编程面试题及答案(20例)

以下是一些常见的Python编程面试题以及它们的答案&#xff1a; 1.解释Python中的 GIL&#xff08;全局解释器锁&#xff09;是什么&#xff0c;它对多线程编程有什么影响&#xff1f; 答案&#xff1a;GIL是Python解释器中的一个机制&#xff0c;它确保在任何给定时间只有一个…

超详细Redis入门教程——Redis 主从集群(上)

前言 本文小新为大家带来 Redis 主从集群 相关知识&#xff0c;具体内容包括主从集群搭建&#xff08;包括&#xff1a;伪集群搭建与配置&#xff0c;分级管理&#xff0c;容灾冷处理&#xff09;&#xff0c;主从集群搭建&#xff08;包括&#xff1a;主从复制原理&#xff0c…

MySQL数据库从入门到精通学习第7天(表数据的增、删、改操作)

表数据的增、删、改操作 使用INSERT...VALUES语句插入数据修改数据删除数据 使用INSERT…VALUES语句插入数据 语法&#xff1a; INSERT [INTO] 数据表名[(字段名...)] VALUES ({值 | DEFAULT},...),()...; [INTO] 数据表名&#xff1a;可选项&#xff0c;用于指定被操作的数…

手把手教你rtsp流媒体分析(引导篇,欢迎订阅专栏)

系列音视频开发 文章目录 系列音视频开发前言一、RTSP是什么&#xff1f;二、RTP是什么&#xff1f;三、RTCP是什么&#xff1f;四、RTSP 源码学习五、H265 RTSP流总结 前言 在安防行业中&#xff0c;onvif协议与gb协议是两种标准&#xff0c;gb是国内安防行业的标准&#xff…

Go Web下gin框架使用(二)

〇、gin 路由 Gin是一个用于构建Web应用程序的Go语言框架&#xff0c;它具有简单、快速、灵活的特点。在Gin中&#xff0c;可以使用路由来定义URL和处理程序之间的映射关系。 r : gin.Default()// 访问 /index 这个路由// 获取信息r.GET("/index", func(c *gin.Con…

康耐视In-Sight2800相机的使用

In-Sight2800相机注册分类程序 一、登录相机 二、图像导入 IS相机支持拍摄图像和从文件中导入图像 如选择从文件中导入图像&#xff0c;文件夹选择位置在页面左下方&#xff0c;如下图 三、注册分类器 在检查模块注册分类器&#xff0c;注册图像需要一张一张去学习&#x…

儿童节到了,我用HTML和CSS画了一个小朋友

文章目录 前言一、关于HTML和CSS二、开始编码2.1 在HTML正文中配置好元素2.2 开始写各个元素的CSS2.3 效果图展示 总结 前言 官方告知我今天参加活动会得勋章&#xff0c;于是想了半天&#xff0c;总得创作一点东西&#xff0c;于是翻出来多年前的箱底技术&#xff0c;用CSSHT…

Kubernetes集群架构与组件介绍

个人博客 一、集群架构 二、主要组件 1.kubelet 该组件运行在每个Kubernetes节点上&#xff0c;用于管理节点。用来接收、处理、上报kube-apiserver组件下发的任务。 主要负责所在节点上的Pod资源对象的管理&#xff0c;例如Pod资源对象的创建、修改、监控、删除、驱逐及Pod…

内网安全:初探隧道技术

目录 防火墙必备知识 域控-防火墙组策略对象同步 域控 - 防火墙组策略不出网上线 MSF上线 CS - ICMP上线 注意&#xff1a;隧道技术是后渗透手段&#xff0c;是在已经取得权限后的手段 域控-组策略同步 防火墙必备知识 学习防火墙的目标是知道了解防火墙的一些常见配置…

ChatGPT应用助推跨境电商发展,低代码凭啥不行?!

随着互联网信息技术的不断发展&#xff0c;随之衍生的诸多产业也在蓬勃发展&#xff0c;而跨境电商就是互联网信息技术发展下的典型产物。 如何定义&#xff1f; 跨境电商指的是通过互联网销售商品或服务&#xff0c;跨越国家或地区边界&#xff0c;实现国际贸易的一种商业模式…

Linux 实操篇-实用指令

Linux 实操篇-实用指令 指定运行级别 基本介绍 运行级别说明&#xff1a; 0 &#xff1a;关机 1 &#xff1a;单用户【找回丢失密码】 2&#xff1a;多用户状态没有网络服务 3&#xff1a;多用户状态有网络服务 4&#xff1a;系统未使用保留给用户 5&#xff1a;图形界…

开发移动端官网总结_Vue2.x

目录 1、自定义加载中效果 2、HTML页面注入环境变量 / 加载CDN和本地库 3、在 Vue 中使用 wow.js 4、过渡路由 5、全局监听当前设备&#xff0c;切换PC端和移动端 6、移动端常用初始化样式 7、官网默认入口文件 8、回到顶部滑动过渡效果&#xff08;显示与隐藏、滑动置…

由于找不到vcruntime140_1.dll无法继续执行此代码的三个解决方法

vcruntime140_1.dll是Microsoft Visual C Redistributable for Visual Studio的一部分&#xff0c;它是一个DLL文件&#xff0c;包含用于运行Microsoft Visual C创建的应用程序所需的Microsoft Visual C组件的代码和数据。这个DLL通常会随着应用程序安装到Windows系统中。如果这…

Dart语法学习

最近在学习flutter相关方面的知识&#xff0c;里面用到了Dart语言&#xff0c;于是写下这篇博客记录学习的一门过程。如果你有其他编程语言的经验&#xff08;尤其是Java和JavaScript&#xff09;&#xff0c;可以很快的上手Dart语言&#xff0c;Dart 在设计时应该是同时借鉴了…

Spring Cloud Alibaba - Nacos源码分析

目录 一、源码 1、为什么要分析源码 2、看源码的方法 二、Nacos服务注册与发现源码剖析 1、Nacos核心功能点 2、Nacos服务端/客户端原理 2.1、nacos-example 2.2、Nacos-Client测试类 3、项目中实例客户端注册 一、源码 1、为什么要分析源码 1. 提升技术功底&#x…

Golang内存泄露场景与定位方式

个人博客 一、产生原因 Golang有自动垃圾回收机制&#xff0c;但是仍然可能会出现内存泄漏的情况。以下是Golang内存泄漏的常见可能原因&#xff1a; 循环引用&#xff1a;如果两个或多个对象相互引用&#xff0c;且没有其他对象引用它们&#xff0c;那么它们就会被垃圾回收机…

【计算机网络实验】BGP和OSPF协议仿真实验

实验内容  BGP和OSPF协议仿真实验 实验目的 &#xff08;1&#xff09;学习BGP协议的配置方法&#xff1b; &#xff08;2&#xff09;验证BGP协议的工作原理&#xff1b; &#xff08;3&#xff09;掌握网络自治系统的划分方法&#xff1b; &#xff08;4&#xff09;验证…

3分钟快速了解—App自动化测试是怎么实现H5测试的?

移动端 app 自动化框架很多&#xff0c;但是有一些框架因为不支持混合应用测试&#xff0c;一直没有完全流行。比较典型的是经典的 Python 框架 uiautomator2, 这个框架简单好用&#xff0c;没有 appium 那样复杂的 api 调用&#xff0c;受到不少 python 自动化工程师的青睐。 …

C++《stack和queue的一些OJ题目》

本文主要讲解C中stack和queue的一些OJ题目 文章目录 1、[最小栈](https://leetcode.cn/problems/min-stack/)2、[栈的压入、弹出序列](https://www.nowcoder.com/practice/d77d11405cc7470d82554cb392585106?tpId13&&tqId11174&rp1&ru/activity/oj&qru/ta…