C Primer Plus 第6版 编程练习——第17章(下)

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

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

#define MAX_SIZE 1000

// 栈结构定义
typedef struct {
    char items[MAX_SIZE];
    int top;
} Stack;

// 初始化栈
void initStack(Stack* stack) {
    stack->top = -1;
}

// 检查栈是否为空
int isEmpty(Stack* stack) {
    return stack->top == -1;
}

// 检查栈是否已满
int isFull(Stack* stack) {
    return stack->top == MAX_SIZE - 1;
}

// 将字符压入栈
void push(Stack* stack, char item) {
    if (isFull(stack)) {
        printf("栈已满,无法压入更多元素!\n");
        return;
    }
    stack->items[++stack->top] = item;
}

// 从栈中弹出字符
char pop(Stack* stack) {
    if (isEmpty(stack)) {
        printf("栈为空,无法弹出元素!\n");
        return '\0';
    }
    return stack->items[stack->top--];
}

// 获取栈的大小
int size(Stack* stack) {
    return stack->top + 1;
}

// 使用栈反转字符串
void reverseStringWithStack(char* input, char* output) {
    Stack stack;
    initStack(&stack);

    // 将字符串中的每个字符逐个压入栈中
    int len = strlen(input);
    for (int i = 0; i < len; i++) {
        push(&stack, input[i]);
    }

    // 从栈中弹出字符并构建反转后的字符串
    int index = 0;
    while (!isEmpty(&stack)) {
        output[index++] = pop(&stack);
    }
    output[index] = '\0'; // 添加字符串结束符
}

int main() {
    system("chcp 65001");
    char input[MAX_SIZE];
    char reversed[MAX_SIZE];

    // 提示用户输入字符串
    printf("请输入一个字符串: ");
    fgets(input, sizeof(input), stdin);

    // 移除可能的换行符
    int len = strlen(input);
    if (len > 0 && input[len - 1] == '\n') {
        input[len - 1] = '\0';
    }

    // 使用栈反转字符串
    reverseStringWithStack(input, reversed);

    // 显示结果
    printf("原字符串: %s\n", input);
    printf("反转后字符串: %s\n", reversed);

    return 0;
}

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

int binarySearch(int arr[], int n, int target) {
    int left = 0;
    int right = n - 1;

    while (left <= right) {
        int mid = left + (right - left) / 2;  // 防止整数溢出

        if (arr[mid] == target) {
            return 1;  // 找到目标值,返回1
        }
        else if (arr[mid] < target) {
            left = mid + 1;  // 在右半部分查找
        }
        else {
            right = mid - 1;  // 在左半部分查找
        }
    }

    return 0;  // 未找到目标值,返回0
}


int main() {
    system("chcp 65001");
    int arr[] = { 1, 3, 5, 7, 9, 11, 13, 15, 17, 19 };
    int n = sizeof(arr) / sizeof(arr[0]);

    // 测试查找存在的元素
    printf("查找  7: %d\n", binarySearch(arr, n,  7));   // 应该输出 1
    printf("查找  1: %d\n", binarySearch(arr, n,  1));   // 应该输出 1
    printf("查找 19: %d\n", binarySearch(arr, n, 19));   // 应该输出 1

    // 测试查找不存在的元素
    printf("查找  4: %d\n", binarySearch(arr, n,  4));   // 应该输出 0
    printf("查找 20: %d\n", binarySearch(arr, n, 20));   // 应该输出 0

    return 0;
}

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

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

// 改进的二叉查找树节点结构
typedef struct TreeNode {
    char word[100];
    int count;
    struct TreeNode* left;
    struct TreeNode* right;
} TreeNode;

// 创建新节点
TreeNode* createNode(const char* word) {
    TreeNode* newNode = (TreeNode*)malloc(sizeof(TreeNode));
    if (newNode == NULL) {
        printf("内存分配失败\n");
        exit(1);
    }
    strcpy_s(newNode->word, word);
    newNode->count = 1;
    newNode->left = NULL;
    newNode->right = NULL;
    return newNode;
}

// 插入单词到二叉查找树
TreeNode* insertWord(TreeNode* root, const char* word) {
    if (root == NULL) {
        return createNode(word);
    }

    int cmp = strcmp(word, root->word);
    if (cmp == 0) {
        root->count++;
    }
    else if (cmp < 0) {
        root->left = insertWord(root->left, word);
    }
    else {
        root->right = insertWord(root->right, word);
    }

    return root;
}

// 中序遍历打印所有单词和计数(按字典顺序)
void printAllWords(TreeNode* root) {
    if (root != NULL) {
        printAllWords(root->left);
        printf("%s: %d\n", root->word, root->count);
        printAllWords(root->right);
    }
}

// 查找单词出现次数
int findWordCount(TreeNode* root, const char* word) {
    if (root == NULL) {
        return 0;
    }

    int cmp = strcmp(word, root->word);
    if (cmp == 0) {
        return root->count;
    }
    else if (cmp < 0) {
        return findWordCount(root->left, word);
    }
    else {
        return findWordCount(root->right, word);
    }
}

// 释放二叉查找树内存
void freeTree(TreeNode* root) {
    if (root != NULL) {
        freeTree(root->left);
        freeTree(root->right);
        free(root);
    }
}

// 清理单词字符串(转换为小写并移除标点符号)
void cleanWord(char* word) {
    int i, j = 0;
    char cleaned[100];

    // 转换为小写并移除标点符号
    for (i = 0; word[i] != '\0'; i++) {
        if (isalpha(word[i])) {
            cleaned[j++] = tolower(word[i]);
        }
    }
    cleaned[j] = '\0';

    // 复制回原字符串
    strcpy_s(word, 100, cleaned);
}

// 从文件读取并处理单词
TreeNode* processFile(const char* filename) {
    FILE* file;
    fopen_s(&file, filename, "r");
    if (file == NULL) {
        printf("无法打开文件: %s\n", filename);
        return NULL;
    }

    TreeNode* root = NULL;
    char word[100];

    // 读取文件中的每个单词
    while (fscanf_s(file, "%s", word, 100) != EOF) {
        cleanWord(word);
        if (strlen(word) > 0) {
            root = insertWord(root, word);
        }
    }

    fclose(file);
    printf("文件读取完成。\n");
    return root;
}

// 显示菜单
void showMenu() {
    printf("\n========== 单词计数程序 ==========\n");
    printf("1. 列出所有单词和出现次数\n");
    printf("2. 查询特定单词的出现次数\n");
    printf("3. 退出程序\n");
    printf("=================================\n");
    printf("请选择操作 (1-3): ");
}

int main() {
    system("chcp 65001");
    char filename[100];
    TreeNode* root = NULL;

    printf("请输入要读取的文本文件名: ");
    scanf_s("%s", filename, 100);

    // 读取和处理文件
    root = processFile(filename);
    if (root == NULL) {
        return 1;
    }

    int choice;
    do {
        showMenu();
        if (scanf_s("%d", &choice) != 1) {
            printf("输入无效,请输入数字 1-3。\n");
            while (getchar() != '\n'); // 清空输入缓冲区
            continue;
        }

        switch (choice) {
        case 1:
            if (root == NULL) {
                printf("没有单词数据。\n");
            }
            else {
                printf("单词统计结果:\n");
                printAllWords(root);
            }
            break;

        case 2: {
            char searchWord[100];
            printf("请输入要查询的单词: ");
            scanf_s("%s", searchWord, 100);
            cleanWord(searchWord);
            int count = findWordCount(root, searchWord);
            if (count > 0) {
                printf("单词 \"%s\" 在文件中出现了 %d 次。\n", searchWord, count);
            }
            else {
                printf("单词 \"%s\" 在文件中未找到。\n", searchWord);
            }
            break;
        }

        case 3:
            printf("感谢使用单词计数程序!\n");
            break;

        default:
            printf("无效选择,请输入 1-3 之间的数字。\n");
        }
    } while (choice != 3);

    // 释放内存
    freeTree(root);
    return 0;
}

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

// tree.h - 修改后的头文件
/* tree.h -- binary search tree                          */
/*           no duplicate items are allowed in this tree */
#ifndef _TREE_H_
#define _TREE_H_
#include <stdbool.h>

/* redefine Item as appropriate */
#define SLEN 20
typedef struct item
{
    char petname[SLEN];
    char petkind[SLEN];
} Item;

#define MAXITEMS 10

typedef struct trnode
{
    Item items[MAXITEMS];      // 存储多个同名宠物
    int count;                 // 当前节点中宠物的数量
    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: find all pets with the same name         */
/* preconditions:  pname points to pet name            */
/*                 ptree points to an initialized tree */
/* postconditions: prints all pets with given name     */
void FindPetsByName(const Tree * ptree, const char * pname);

/* 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.c -- tree support functions */
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include "tree.h"

/* local data type */
typedef struct pair {
    Trnode* parent;
    Trnode* child;
} Pair;

/* prototypes for local functions */
static Trnode* MakeNode(const Item* pi);
static bool ToLeft(const char* name1, const char* name2);
static bool ToRight(const char* name1, const char* name2);
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 Trnode* SeekNodeByName(const char* pname, 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* found_node;

    if (TreeIsFull(ptree))
    {
        fprintf(stderr, "Tree is full\n");
        return false;
    }

    // 查找是否已存在同名宠物
    found_node = SeekNodeByName(pi->petname, ptree);
    if (found_node != NULL)
    {
        // 如果节点未满,添加到现有节点
        if (found_node->count < MAXITEMS)
        {
            found_node->items[found_node->count] = *pi;
            found_node->count++;
            ptree->size++;
            return true;
        }
        else
        {
            fprintf(stderr, "No room for more pets with that name\n");
            return false;
        }
    }

    // 创建新节点
    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)
{
    Trnode* found_node;

    found_node = SeekNodeByName(pi->petname, ptree);
    if (found_node == NULL)
        return false;

    // 检查该节点中是否有完全匹配的宠物
    for (int i = 0; i < found_node->count; i++)
    {
        if (strcmp(found_node->items[i].petkind, pi->petkind) == 0)
            return true;
    }

    return false;
}

void FindPetsByName(const Tree* ptree, const char* pname)
{
    Trnode* found_node;
    char upper_name[SLEN];
    strcpy_s(upper_name, pname);

    // 转换为大写以匹配存储格式
    for (int i = 0; upper_name[i]; i++)
        upper_name[i] = toupper(upper_name[i]);

    found_node = SeekNodeByName(upper_name, ptree);
    if (found_node == NULL)
    {
        printf("No pets named %s found.\n", pname);
        return;
    }

    printf("Pets named %s:\n", pname);
    for (int i = 0; i < found_node->count; i++)
    {
        printf("   Kind: %s\n", found_node->items[i].petkind);
    }
}

bool DeleteItem(const Item* pi, Tree* ptree)
{
    Pair look;
    Trnode* found_node;

    found_node = SeekNodeByName(pi->petname, ptree);
    if (found_node == NULL)
        return false;

    // 在节点中查找特定种类的宠物
    int index = -1;
    for (int i = 0; i < found_node->count; i++)
    {
        if (strcmp(found_node->items[i].petkind, pi->petkind) == 0)
        {
            index = i;
            break;
        }
    }

    if (index == -1)
        return false;

    // 从节点中移除该项
    for (int i = index; i < found_node->count - 1; i++)
    {
        found_node->items[i] = found_node->items[i + 1];
    }
    found_node->count--;
    ptree->size--;

    // 如果节点为空,删除节点
    if (found_node->count == 0)
    {
        look = SeekItem(pi, ptree);
        if (look.parent == NULL)
            DeleteNode(&ptree->root);
        else if (look.parent->left == look.child)
            DeleteNode(&look.parent->left);
        else
            DeleteNode(&look.parent->right);
    }

    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);
        for (int i = 0; i < root->count; i++)
            (*pfun)(root->items[i]);
        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->items[0].petname, root->items[0].petname))
    {
        if (root->left == NULL)
            root->left = new_node;
        else
            AddNode(new_node, root->left);
    }
    else if (ToRight(new_node->items[0].petname, root->items[0].petname))
    {
        if (root->right == NULL)
            root->right = new_node;
        else
            AddNode(new_node, root->right);
    }
    else
    {
        fprintf(stderr, "location error in AddNode()\n");
        exit(1);
    }
}

static bool ToLeft(const char* name1, const char* name2)
{
    if (strcmp(name1, name2) < 0)
        return true;
    else
        return false;
}

static bool ToRight(const char* name1, const char* name2)
{
    if (strcmp(name1, name2) > 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->items[0] = *pi;
        new_node->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->petname, look.child->items[0].petname))
        {
            look.parent = look.child;
            look.child = look.child->left;
        }
        else if (ToRight(pi->petname, look.child->items[0].petname))
        {
            look.parent = look.child;
            look.child = look.child->right;
        }
        else
            break;
    }

    return look;
}

static Trnode* SeekNodeByName(const char* pname, const Tree* ptree)
{
    Trnode* current = ptree->root;

    while (current != NULL)
    {
        int comp = strcmp(pname, current->items[0].petname);
        if (comp == 0)
            return current;
        else if (comp < 0)
            current = current->left;
        else
            current = current->right;
    }

    return NULL;
}

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

petclub.c

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

char menu(void);
void addpet(Tree* pt);
void droppet(Tree* pt);
void showpets(const Tree* pt);
void findpet(const Tree* pt);
void printitem(Item item);
void uppercase(char* str);
char* s_gets(char* st, int n);

int main(void)
{
    Tree pets;
    char choice;

    InitializeTree(&pets);
    while ((choice = menu()) != 'q')
    {
        switch (choice)
        {
        case 'a':  addpet(&pets);
            break;
        case 'l':  showpets(&pets);
            break;
        case 'f':  findpet(&pets);
            break;
        case 'n':  printf("%d pets in club\n",
            TreeItemCount(&pets));
            break;
        case 'd':  droppet(&pets);
            break;
        default:  puts("Switching error");
        }
    }
    DeleteAll(&pets);
    puts("Bye.");

    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, SLEN);
        uppercase(temp.petname);
        uppercase(temp.petkind);
        AddItem(&temp, pt);
    }
}

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

void printitem(Item item)
{
    printf("Pet: %-19s  Kind: %-19s\n", item.petname,
        item.petkind);
}

void findpet(const Tree* pt)
{
    char pname[SLEN];

    if (TreeIsEmpty(pt))
    {
        puts("No entries!");
        return;
    }

    puts("Please enter name of pet you wish to find:");
    s_gets(pname, SLEN);
    FindPetsByName(pt, pname);
}

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);
    puts("Please enter pet kind:");
    s_gets(temp.petkind, SLEN);
    uppercase(temp.petname);
    uppercase(temp.petkind);
    printf("%s the %s ", temp.petname, temp.petkind);
    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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

阿捏利

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值