C Primer Plus第六版第十七章编程题目与参考答案⭐

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);
char *s_gets(char *st, int n);

int main(void)
{
    struct film *head = NULL;
    struct film *prev, *current;
    char input[TSIZE];

    puts("Enter first movie title:");
    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);
        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");
    }
    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;
}

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

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

typedef struct list
{
	Node * head; /*指向list的开头*/
	Node * end;  /*指向list的末尾*/
} List;

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

/*films.c*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "list.h"

void showmovies(Item item);
char *s_gets(char *st, int n);

int main(void)
{
    List movies;
    Item temp;

    InitializeList(&movies);
    if (ListIsFull(&movies))
    {
        fprintf(stderr, "No memory available! Bye!\n");
        exit(1);
    }
    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):");
    }
    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));
    EmptyTheList(&movies);
    printf("Bye!\n");

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

/*第17章编程练习第2题的list.h*/
/*
#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
*/
/*--------------------------------------------------*/

/*第17章编程练习第2题的list.c*/
/*
#include <stdio.h>
#include <stdlib.h>
#include "list.h"

static void CopyToNode(Item item, Node *pnode);

void InitializeList(List *plist)
{
    (*plist).head = NULL;
    (*plist).end = NULL;
    return;
}

bool ListIsEmpty(const List *plist)
{
    return (*plist).head == NULL ? true : false;
}

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)测试最终的代码。

/*第17章编程练习第3题的films.c*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "list.h"

void showmovies(Item item);
char *s_gets(char *st, int n);

int main(void)
{
    List movies;
    Item temp;

    InitializeList(&movies);
    if (ListIsFull(&movies))
    {
        fprintf(stderr, "No memory available! Bye!\n");
        exit(1);
    }
    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):");
    }
    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));
    EmptyTheList(&movies);
    printf("Bye!\n");

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

/*第17章编程练习第3题的list.h*/
/*
#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
*/
/*--------------------------------------------------*/

/*第17章编程练习第3题的list.c*/
/*
#include <stdio.h>
#include <stdlib.h>
#include "list.h"

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

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

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

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),用两个队列模拟两个摊位。

/*第17章编程练习第4题的mall.c*/
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "queue.h"
#define MIN_PER_HR 60.0
#define N 2

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];

bool newcustomer(double x);
Item customertime(long when);

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

    for (i = 0; i < N; i++) //初始化2个摊位中的一些数据;
    {
        malls[i].turnaways = 0;
        malls[i].customers = 0;
        malls[i].served = 0;
        malls[i].sum_line = 0;
        malls[i].wait_time = 0;
        malls[i].line_wait = 0;
        InitializeQueue(&malls[i].line);
    }
    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;
}

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

/*第17章编程练习第4题的queue.h*/
/*
#ifndef _QUEUE_H_
#define _QUEUE_H_
#include <stdbool.h>

typedef struct item
{
    long arrive;
    int processtime;
} Item;

#define MAXQUEUE 10

typedef struct node
{
    Item item;
    struct node *next;
} Node;

typedef struct queue
{
    Node *front;
    Node *rear;
    int items;
} Queue;

void InitializeQueue(Queue *pq);

bool QueueIsFull(const Queue *pq);

bool QueueIsEmpty(const Queue *pq);

int QueueItemCount(const Queue *pq);

bool EnQueue(Item item, Queue *pq);

bool DeQueue(Item *pitem, Queue *pq);

void EmptyTheQueue(Queue *pq);

#endif
*/
/*--------------------------------------------------*/

/*第17章编程练习第4题的queue.c*/
/*
#include <stdio.h>
#include <stdlib.h>
#include "queue.h"

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

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;
    }
    else
    {
        pq->rear->next = pnew;
    }
    pq->rear = pnew;
    pq->items++;
    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;
}

void EmptyTheQueue(Queue *pq)
{
    Item dummy;
    while (!QueueIsEmpty(pq))
    {
        DeQueue(&dummy, pq);
    }
    return;
}

static void CopyToNode(Item item, Node *pn)
{
    pn->item = item;
    return;
}

static void CopyToItem(Node *pn, Item *pi)
{
    *pi = pn->item;
    return;
}
*/
/*--------------------------------------------------*/

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

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#define LEN 21

typedef struct stack_node
{
    char ch;
    struct stack_node *next;
} Stack;

Stack *Init_Stack(void);             //初始化一个栈头结点;
bool Stack_Empty(Stack *mystack);    //判断栈是否为空;
bool Push(Stack *mystack, char val); //压入一个字符进栈中;
bool Pop(Stack *mystack, char *val); //从栈中弹出一个字符;
char *s_gets(char *st, int n);

int main(void)
{
    int i;
    char ch, temp[LEN];
    Stack *mystacks = NULL;

    mystacks = Init_Stack(); //使空栈指向一个头结点便于操作;
    printf("请您输入一串字符串(不大于%d个字符):\n", LEN - 1);
    while (s_gets(temp, LEN) && temp[0] != '\0')
    {
        i = 0;
        while (temp[i] != '\0')
        {
            Push(mystacks, temp[i++]); //由于是链式结构故不考虑存储空间不足的问题;
        }
        printf("原字符串的逆序是:\n");
        while (!Stack_Empty(mystacks))
        {
            Pop(mystacks, &ch); //顺序出栈即可得到原字符串的逆序;
            putchar(ch);
        }
        putchar('\n');
        puts("您可以再次输入一串字符串(或换行退出):");
    }
    free(mystacks); //销毁头结点;
    puts("本程序完成!");

    return 0;
}

Stack *Init_Stack(void)
{
    Stack *node = (Stack *)malloc(sizeof(Stack));
    if (NULL == node)
    {
        fprintf(stderr, "动态内存分配失败!本程序退出!\n");
        exit(EXIT_FAILURE);
    }
    node->next = NULL;
    return node;
}

bool Stack_Empty(Stack *mystack)
{
    return NULL == mystack->next ? true : false;
}

bool Push(Stack *mystack, char val)
{
    Stack *node = (Stack *)malloc(sizeof(Stack));
    if (NULL == node)
    {
        fprintf(stderr, "动态内存分配失败!本程序退出!\n");
        exit(EXIT_FAILURE);
    }
    node->ch = val;
    node->next = mystack->next; //新结点的指针域指向原栈顶结点;
    mystack->next = node;       //头结点指针域指向新结点(新结点成为栈顶结点);
    return true;
}

bool Pop(Stack *mystack, char *val)
{
    if (Stack_Empty(mystack)) //若是空栈则无法执行出栈操作;
    {
        return false;
    }
    *val = mystack->next->ch;    //存放栈顶数据元素的值;
    Stack *temp = mystack->next; //临时指针保存栈顶结点的地址;
    mystack->next = temp->next;  //头结点指针域指向栈顶结点的下一个结点(重新形成一个新栈);
    free(temp);                  //释放栈顶结点的内存;
    return true;
}

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

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

#include <stdio.h>
#define SIZE 10

int binary_search(const int sorted[], int size, int val);

int main(void)
{
    int num, found;
    int nums[SIZE] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

    printf("请输入您需要查找的数字:");
    while (scanf("%d", &num) == 1)
    {
        found = binary_search(nums, SIZE, num);
        printf("%d%s此数组中.\n", num, found ? "在" : "不在");
        printf("您可以继续输入一个数字(或按q退出): ");
    }
    puts("本程序完成!");

    return 0;
}

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

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

/*第17章编程练习第7题的words_count.c*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "tree.h"
#define SLEN 81

char *s_gets(char *st, int n);
int menu(void);
void showwords(const Tree *pt);
void findword(const Tree *pt);
void print_all_items(Item item);
int get_first(void);
void eatline(void);

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

    printf("请您输入一个文本文件名:\n");
    s_gets(filename, SLEN);

    if ((fp = fopen(filename, "r")) == NULL)
    {
        fprintf(stderr, "无法打开文件%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, "关闭%s文件失败!\n", filename);
    }
    puts("欢迎再次使用!");

    return 0;
}

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("       欢迎来到单词统计程序!");
    puts("       以下是可供选择的清单");
    puts("       s)列出文本中所有的单词及其出现的次数");
    puts("       f)查找某个单词在文本中出现的次数");
    puts("       q)退出本程序");
    puts("=========================================");
    printf("请您输入选择:");
    ch = get_first();
    while (strchr("sfq", ch) == NULL)
    {
        printf("选择有误!请输入s,f或者q:");
        ch = get_first();
    }
    return ch;
}

void showwords(const Tree *pt)
{
    if (TreeIsEmpty(pt)) //使用二叉树存储的单词若为空则表示无单词;
    {
        puts("文本中暂无单词!");
    }
    else
    {
        Traverse(pt, print_all_items);
    }
    return;
}

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

    if (TreeIsEmpty(pt))
    {
        puts("文本中暂无单词!");
        return;
    }
    printf("请输入您要查找的单词:");
    scanf("%80s", word);
    eatline();
    strcpy(entry.wrd, word);      //把word数组中的单词复制到二叉树的项目中;
    pi = WhereInTree(&entry, pt); //寻找单词在二叉树中的位置;
    if (NULL == pi)
    {
        printf("单词%s不在文本中!\n", word);
    }
    else
    {
        printf("单词%s在文本中出现了%d次\n", word, pi->count);
    }
    return;
}

void print_all_items(Item item)
{
    printf("单词%s在文本中总共出现的次数:%d次\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;
}

/*第17章编程练习第7题的tree.h*/
/*
#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
*/
/*--------------------------------------------------*/

/*第17章编程练习第7题的tree.c*/
/*
#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 ptree->root == NULL ? true : false;
}

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

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

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

    if (TreeIsFull(ptree))
    {
        fprintf(stderr, "存储空间已满!无法添加新项目!\n");
        return false;
    }
    if ((seek = SeekItem(pi, ptree)).child != NULL)
    {
        seek.child->item.count++;
        return true;
    }
    new = MakeNode(pi);
    if (new == NULL)
    {
        fprintf(stderr, "动态内存分配失败!本程序退出!\n");
        exit(EXIT_FAILURE);
    }
    ptree->size++;
    if (ptree->root == NULL)
    {
        ptree->root = new;
    }
    else
    {
        AddNode(new, 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, "调用函数AddNode时发生错误!\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.修改宠物俱乐部程序,把所有同名的宠物都储存在同一个节点中。当用户选择查找宠物时,程序应
询问用户该宠物的名字,然后列出该名字的所有宠物(及其种类)。

/*第17章编程练习第8题的petclub.c*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include "tree.h"

int 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);
void print_all_pets(Item item);
void my_malloc(Item *item);
void print_same_pets(Item item, const char *str);
void my_traverse(const Trnode *root, void (*pfun)(Item item, const char *temp), const char *str);
void pets_count(int *count, int *temp);

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

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;
}
/*第17章编程练习第8题的tree.h*/
/*
#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
*/
/*--------------------------------------------------*/

/*第17章编程练习第8题的tree.c*/
/*
#include <string.h>
#include <stdio.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 ptree->root == NULL ? true : false;
}

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

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, "Attempted to 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)
{
    Trnode *temp;

    if ((*ptr)->left == NULL)
    {
        temp = *ptr;
        *ptr = (*ptr)->right;
        Kind *tp;
        while (temp->item.many_petkinds != NULL)
        {
            tp = temp->item.many_petkinds->next;
            free(temp->item.many_petkinds);
            temp->item.many_petkinds = tp;
        }
        free(temp);
    }
    else if ((*ptr)->right == NULL)
    {
        temp = *ptr;
        *ptr = (*ptr)->left;
        Kind *tp;
        while (temp->item.many_petkinds != NULL)
        {
            tp = temp->item.many_petkinds->next;
            free(temp->item.many_petkinds);
            temp->item.many_petkinds = tp;
        }
        free(temp);
    }
    else
    {
        for (temp = (*ptr)->left; temp->right != NULL; temp = temp->right)
        {
            continue;
        }
        temp->right = (*ptr)->right;
        temp = *ptr;
        *ptr = (*ptr)->left;
        Kind *tp;
        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;
}
*/
/*--------------------------------------------------*/
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值