Помогите решить задачку на языке С

Передо мной стояла задача:Упражнение 6.2. Напишите программу, которая читает текст Си-программы и печатает в алфавитном порядке все группы имен переменных, в которых совпадают первые 6 символов, но последующие в чем-то различаются. Не обрабатывайте внутренности закавыченных строк и комментариев. Число 6 сделайте параметром, задаваемым в командной строке. Решал я ее в более упрощенном варианте, и обрабатывал просто слова, который вводились в терминал. Размещал я это все как одно большое бинарное дерево, узлы которого являются так же деревьями, но уже с одинаковыми N количеством букв. Я хочу, чтобы моя программа не выводила те деревья, в которых находится одно слово, как я бы мог изменить программу, чтобы работало должным образом.

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



struct tnode { /* узел дерева */
    char *word; /* указатель на текст */
    struct tnode *left; /* левый сын */
    struct tnode *right; /* правый сын */
    int count; // подсчет количества слов в узле
};


struct tree_of_trees {
    struct tnode *bin_tree;
    struct tree_of_trees *left_son;
    struct tree_of_trees *right_son;
};



/* talloc: создает tnode */
struct tnode *talloc(void)
{
    return (struct tnode *) malloc(sizeof(struct tnode));
}


char *strdup_(char *s) /* делает дубликат s */
{
    char *p;
    p = (char *) malloc(strlen(s)+1); /* +1 для '\0' */
    if (p != NULL)
        strcpy(p, s);
    return p;
}

/* addtree: добавляет узел со словом w в р или ниже него */
struct tnode *addtree(struct tnode *p, char *w)
{
    int cond;
    if (p == NULL) { /* слово встречается впервые */
        p = talloc(); /* создается новый узел */
        p->word = strdup_(w);
        p->left = p->right = NULL;
        p -> count = 1;
    }
    else if ((cond = strcmp(w, p -> word)) < 0){ /* меньше корня левого поддерева */
        p->left = addtree(p->left, w);
        p -> count++;
    }
    else if (cond > 0){ /* больше корня правого поддерева */
        p->right = addtree(p->right, w);
        p -> count++;
    }
    return p;
}

struct tree_of_trees *balloc(void)
{
    return (struct tree_of_trees *) malloc(sizeof(struct tree_of_trees));
}

char *skip_n(char *word, int n){
    return &word[n + 1];
}

char *check_n(char *word, int n){
    char *p, *w;
    p = w = word;
    for (int i = 1; i < n; i++)
        *++w = *(++word);

    return p;
}


struct tree_of_trees *big_tree(struct tree_of_trees *p, struct tnode *vet, int n){
    int cond;
    if (vet == NULL) return p;
    if (p == NULL){
        p = balloc();
        p->bin_tree = vet;
        p->left_son = p->right_son = NULL;
    }
    if (strcmp(check_n(vet->word, n), check_n(p -> bin_tree -> word, n)) == 0){ 
        if ((cond = strcmp(skip_n(vet->word, n), skip_n(p -> bin_tree -> word, n))) < 0)
            p -> left_son = big_tree(p->left_son, vet, n);
        else if (cond > 0)
            p -> right_son = big_tree(p->right_son, vet, n);
    }
    return p;
}


#define BUFSIZE 100
char buf[BUFSIZE]; // буфер для ungetch
int bufp = 0; // след. свободная позиция в буфере
int getch(void) // взять (возможно возращенный) символ 
{   
    return (bufp > 0) ? buf[--bufp] : getchar();
}

void ungetch(int c) // вернуть символ на ввод. Чтобы избежать потери какого-либо символа и непредвиденных ошибок.
{
    if (bufp >= BUFSIZE)
        printf("ungetch: a lot of symbols\n");
    else
        buf[bufp++] = c;
}


/* getword: принимает следующее слово или символ из ввода */
int getword (char *word, int lim)
{   
    char c;
    char *w = word;
    while (isspace(c = getch()));
    if (c != EOF)
        *w++ = c;
    if (!isalpha(c)) {
        *w = '\0';
        return c;
    }
    for ( ; --lim > 0; w++)
        if (!isalnum(*w = getch())) {
            ungetch(*w);
            break;
        }
    *w = '\0';
    return word[0];
}

void treeprint_(struct tnode *a);
// Печать дерева(из деревьев) отсортированного по алфавиту 
void bigtreeprint(struct tree_of_trees *p){
    if (p != NULL){
        bigtreeprint(p -> left_son);
        treeprint_(p -> bin_tree);
        bigtreeprint(p -> right_son);
    }   
}

/* treeprint: упорядоченная печать дерева р */
void treeprint_(struct tnode *p)
{  
    if (p != NULL) {
        treeprint_(p->left);
        printf("%s\n", p->word);
        treeprint_(p->right);
    }
}

void free_tree(struct tnode *p) {
    if (p != NULL) {
        free_tree(p->left);
        free_tree(p->right);
        free(p->word);
        free(p);
    }
}

void free_big_tree(struct tree_of_trees *p) {
    if (p != NULL) {
        free_big_tree(p->left_son);
        free_big_tree(p->right_son);
        free_tree(p->bin_tree);
        free(p);
    }
}

int main(int argc, char *argv[])
{   
    int n = 6;
    while (--argc > 0) n = atoi(*++argv);
    struct tnode *root_internal;
    struct tree_of_trees *root_main;
    char word[100];
    root_main = NULL;
    root_internal = NULL;
    while (getword (word, 100) != EOF){
        if ((isalpha(word[0]) || word[0] == '_') && strlen(word) > n){
            root_main = big_tree(root_main, root_internal, n);
            root_internal = addtree(root_internal, word);
        }
    }
    bigtreeprint(root_main);
    free_big_tree(root_main);


    return 0;
}

Ответы (1 шт):

Автор решения: Treeesk

С помощью некоторых изменений и созданием некого префиксного дерева я думаю, что смог достичь правильного выполнения программы. В предложенной логике(в одном из комментариев) в узле struct tree_of_trees должны храниться первые n символов имени и count (это количество имен в группе), а в узлах struct tnode count не нужен (каждый узел в этих деревьях содержит одно имя). Кстати, когда мы читаем имя, которое уже в дереве, то повторно вставлять его не надо. И еще, вызывать вставку в дерево (если использовать дерево tnode, а не список) нужно прямо из функции big_tree(), когда в big tree найдена группа для нового слова (или создается новый узел)

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

struct tnode { /* узел дерева */
    char *word; /* указатель на текст */
    struct tnode *left; /* левый сын */
    struct tnode *right; /* правый сын */
};


struct tree_of_trees {
    char *first_n_sym;
    int count;
    struct tnode *bin_tree;
    struct tree_of_trees *left_son;
    struct tree_of_trees *right_son;
};



/* talloc: создает tnode */
struct tnode *talloc(void)
{
    return (struct tnode *) malloc(sizeof(struct tnode));
}


char *strdup_(char *s) /* делает дубликат s */
{
    char *p;
    p = (char *) malloc(strlen(s)+1); /* +1 для '\0' */
    if (p != NULL)
        strcpy(p, s);
    return p;
}

/* addtree: добавляет узел со словом w в р или ниже него */
struct tnode *addtree(struct tnode *p, char *w)
{
    int cond;
    if (p == NULL) { /* слово встречается впервые */
        p = talloc(); /* создается новый узел */
        p->word = strdup_(w);
        p->left = p->right = NULL;
    }
    else if ((cond = strcmp(w, p -> word)) < 0){ /* меньше корня левого поддерева */
        p->left = addtree(p->left, w);
    }
    else if (cond > 0){ /* больше корня правого поддерева */
        p->right = addtree(p->right, w);
    }
    return p;
}

struct tree_of_trees *balloc(void)
{
    return (struct tree_of_trees *) malloc(sizeof(struct tree_of_trees));
}

char *skip_n(char *word, int n){
    return word + n;
}

char *head_of_tree(const char *word, int n){
    char *p = (char *)malloc(n + 1);
    if (p == NULL) {
        return NULL; // Проверка на успешное выделение памяти
    }
    for (int i = 0; i < n; i++)
        p[i] = word[i];
    p[n] = '\0'; // Завершаем строку нулевым символом
    return p;
}

struct tree_of_trees *big_tree(struct tree_of_trees *p, char *word, int n){
    int cond;
    if (p == NULL){
        p = balloc();
        p->first_n_sym = head_of_tree(word, n);
        p->bin_tree = addtree(NULL, skip_n(word, n));
        p->left_son = p->right_son = NULL;
        p->count = 1;
    }
    else if ((cond = strcmp(head_of_tree(word, n), p->first_n_sym)) == 0){
        p->bin_tree = addtree(p->bin_tree, skip_n(word, n));
        p->count++;
    }
    else if (cond < 0)
        p -> left_son = big_tree(p->left_son, word, n);
    else
        p -> right_son = big_tree(p->right_son, word, n);
    return p;
}


#define BUFSIZE 100
char buf[BUFSIZE]; // буфер для ungetch
int bufp = 0; // след. свободная позиция в буфере
int getch(void) // взять (возможно возращенный) символ 
{   
    return (bufp > 0) ? buf[--bufp] : getchar();
}

void ungetch(int c) // вернуть символ на ввод. Чтобы избежать потери какого-либо символа и непредвиденных ошибок.
{
    if (bufp >= BUFSIZE)
        printf("ungetch: a lot of symbols\n");
    else
        buf[bufp++] = c;
}


/* getword: принимает следующее слово или символ из ввода */
int getword (char *word, int lim)
{   
    char c;
    char *w = word;
    while (isspace(c = getch()));
    if (c != EOF)
        *w++ = c;
    if (!isalpha(c)) {
        *w = '\0';
        return c;
    }
    for ( ; --lim > 0; w++)
        if (!isalnum(*w = getch())) {
            ungetch(*w);
            break;
        }
    *w = '\0';
    return word[0];
}

void treeprint_(struct tnode *a);
// Печать дерева(из деревьев) отсортированного по алфавиту 
void bigtreeprint(struct tree_of_trees *p){
    if (p != NULL){
        bigtreeprint(p -> left_son);
        if (p->count > 1){
          printf("Prefix: %s\n", p->first_n_sym);
          treeprint_(p -> bin_tree);
        }
        bigtreeprint(p -> right_son);
    }   
}

/* treeprint: упорядоченная печать дерева р */
void treeprint_(struct tnode *p)
{  
    if (p != NULL) {
        treeprint_(p->left);
        printf("%s\n", p->word);
        treeprint_(p->right);
    }
}

void free_tree(struct tnode *p) {
    if (p != NULL) {
        free_tree(p->left);
        free_tree(p->right);
        free(p->word);
        free(p);
    }
}

void free_big_tree(struct tree_of_trees *p) {
    if (p != NULL) {
        free_big_tree(p->left_son);
        free_big_tree(p->right_son);
        free_tree(p->bin_tree);
        free(p);
    }
}

int main(int argc, char *argv[])
{   
    int n = 6;
    while (--argc > 0) n = atoi(*++argv);
///    struct tnode *root_internal;
    struct tree_of_trees *root_main;
    char word[100];
    root_main = NULL;
//    root_internal = NULL;
    while (getword (word, 100) != EOF){
        if ((isalpha(word[0]) || word[0] == '_') && strlen(word) > n){
       //     root_main = big_tree(root_main, root_internal, n);
      //      root_internal = addtree(root_internal, word);
              root_main = big_tree(root_main, word, n);
        }
    }
    bigtreeprint(root_main);
    free_big_tree(root_main);

    return 0;
}
→ Ссылка