Помогите решить задачку на языке С
Передо мной стояла задача:Упражнение 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 шт):
С помощью некоторых изменений и созданием некого префиксного дерева я думаю, что смог достичь правильного выполнения программы. В предложенной логике(в одном из комментариев) в узле 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;
}