Code for reversing sequence of non-vowels ending with zero status

Asked

Viewed 300 times

5

I’m implementing the function decodificar, which aims to call auxiliary functions to reverse all non-vowel sequences. For example, if the word is "cool monsters," it will go to "mortsnol segais".

void inverterNvs(NO* elemento, NO* anteriorAoElemento) {
    if (elemento->prox != NULL) {
        inverterNvs(elemento->prox, elemento);
    }
    elemento->prox = anteriorAoElemento;
}


bool verificaSequencia(NO* dado) {
    if (dado->letra != 'a' || dado->letra != 'e' || dado->letra != 'i' || dado->letra != 'o' || dado->letra != 'u'){
        return true;
    }
    else{
        return false;
    }
}

void decodificar(LISTA* resp) {
    NO* pNv = NULL; // Primeira não-vogal encontrada.
    NO* ultNv = NULL; // Última não-vogal encontrada.

    NO* atual = resp->inicio; // Ponteiro para percorrer a lista.

    /* Laço para percorrer toda lista. */
    while (atual->prox != NULL) {

        /* Enquanto atual apontar para uma não-vogal. */
        if (verificaSequencia(atual)) {
            /* Salva o primeiro caso encontrado de não-vogal. */
            pNv = atual;

            /* Procura na lista o último caso de não-vogal. */
            while (verificaSequencia(atual->prox)) {
                atual = atual->prox;
            }
            /* Quando a próxima letra for uma vogal, então foi atingido o fim da sequência de não-vogais. */
            ultNv = atual;

            /* Se existir uma sequência de não-vogais, ou seja, pNv e ultNv não apontarem para o mesmo elemento, então a troca de posições deve ser efetuada. */
            if (pNv != ultNv) {
                /* Chama uma função recursiva para efetuar a troca de posições sem precisar criar uma nova lista. */
                inverterNvs(pNv->prox, pNv);
            }
        }

        /* Move para o próximo elemento. */
        atual = atual->prox;
    }
}

I wonder if my code solves the problem and how to complete it so that it works, because the inversions are not being made. My program is ending with status 0, according to Codeblocks, even after calling the function decodificar. Complete code: https://repl.it/KrQg/3

3 answers

3

You can separate this problem into two small problems:

  1. Find the "sub-list" containing the sequence of non-vowels (consonants)
  2. Invert a simply chained list.

The first problem in a way is easier to solve, you can address it in several ways possible. In the code below, I used a Recursive Function calling for InverteElementos.

However, it is possible (and in my opinion easier to understand) to create a new temporary list that will help to reverse the positions of the non-vowel sequence. I did not take this path because I did not know how the functions of creating its structure were implemented LISTA, and also because I don’t know if your problem allows the use of auxiliary memory.

The function inverterNvs, traverses the list simply chained, member by member, and when finding a sequence of consonants, exchange the positions of the members of the sequence using a recursive function.

It is worth noting that the function ehNaoVogal serves only to make the code more readable.

void inverterNvs(LISTA* resp) {
    NO* pNv = NULL; // Primeira não-vogal encontrada.
    NO* ultNv = NULL; // Última não-vogal encontrada.

    NO* atual = resp->inicio; // Ponteiro para percorrer a lista.

    /* Laço para percorrer toda lista. */
    while (atual->prox != NULL) {

        /* Enquanto atual apontar para uma não-vogal. */
        if (ehNaoVogal(atual)) {
            /* Salva o primeiro caso encontrado de não-vogal. */
            pNv = atual;

            /* Procura na lista o último caso de não-vogal. */
            while (ehNaoVogal(atual->prox)) {
                atual = atual->prox;
            }
            /* Quando a próxima letra for uma vogal, então foi atingido o fim da sequência de não-vogais. */
            ultNv = atual;

            /* Se existir uma sequência de não-vogais, ou seja, pNv e ultNv não apontarem para o mesmo elemento, então a troca de posições deve ser efetuada. */
            if (pNv != ultNv) {
                /* Chama uma função recursiva para efetuar a troca de posições sem precisar criar uma nova lista. */
                inverteElementos(pNv->prox, pNv);
            }
        }

        /* Move para o próximo elemento. */
        atual = atual->prox;
    }
}

void inverteElementos(NO* elemento, NO* anteriorAoElemento) {
    if (elemento->prox != NULL) {
        inverteElementos(elemento->prox, elemento);
    }
    elemento->prox = anteriorAoElemento;
}

bool ehNaoVogal(NO* dado) {
    if (dado->letra != 'a' || dado->letra != 'e' || dado->letra != 'i' || dado->letra != 'o' || dado->letra != 'u'){
        return true;
    }
    else{
        return false;
    }
}
  • Thank you very much for your help, Marcos. However, it was not possible to reverse the non-vowels. Here is the code for further details: https://repl.it/Kdko/21

2


The logic you are using makes sense, and answers the problem, but there are several details of the implementation that are not correct.

Starting with the knot reversal:

void inverterNvs(NO* elemento, NO* anteriorAoElemento) {
    if (elemento->prox != NULL) {
        inverterNvs(elemento->prox, elemento);
    }
    elemento->prox = anteriorAoElemento;
}

In this case the navigation is being done until the NULL to invert only one section of the sentence, which does not respond to what the method intends to do, which is for the final consonant. That is if we want to invert "nstr" from "n" to "r" then we have to indicate the "r" somehow otherwise it goes to the end of the sentence.

Logo can be changed including an end pointer:

void inverterNvs(NO* elemento, NO* anteriorAoElemento, NO* fim /*novo fim aqui*/) { 
    if (elemento != fim) { //teste agora com o fim em vez de NULL
        inverterNvs(elemento->prox, elemento, fim);
    }
    elemento->prox = anteriorAoElemento;
}

The function verificaSequencia:

bool verificaSequencia(NO* dado) {
    if (dado->letra != 'a' || dado->letra != 'e' || dado->letra != 'i' || dado->letra != 'o' || dado->letra != 'u'){
        return true;
    }
    else{
        return false;
    }
}

Also not correct in if because it is valid with or(||) when it should be validated with and(&&). If we have a 'e' the first test of dado->letra != 'a' gives true and how it is with or(||) no longer tests the rest and gives true as a result when it should false.

Just change the if to keep:

if (dado->letra != 'a' && dado->letra != 'e' && dado->letra != 'i' && dado->letra != 'o' && dado->letra != 'u'){

The function decodificar is the one that needs more changes to fully respond to logic.

It is necessary:

  • Adjust the conditions of the 2 while
  • Reconnect the inverted block with the rest of the list
  • Update the atual after the reversal

All things considered, it’s like this now (I cut your comments to focus only on the changes I made):

void decodificar(LISTA* resp) {
    NO* pNv = NULL;
    NO* ultNv = NULL;

    NO* atual = resp->inicio;

    //ponteiro necessário para voltar a ligar o bloco invertido com o resto
    NO* anterior = NULL; 

    //este while foi alterado de atual->prox!=NULL para atual!=NULL uma vez que o while
    //de dentro mexe também no atual e o atual=atual->prox do fim pode meter o atual 
    //a NULL fazendo com que atual->prox!=NULL pudesse dar erro aqui
    while (atual != NULL) {

        if (verificaSequencia(atual)) {
            pNv = atual;

            //se o while utiliza atual, é necessário não deixar passar o NULL senão
            //dá erro, e por isso adicionei aqui atual->prox != NULL &&
            while (atual->prox != NULL && verificaSequencia(atual->prox)) {
                atual = atual->prox;
            }

            ultNv = atual;

            if (pNv != ultNv) {

                //guardar o nó seguinte à inversão para depois voltar a ligar o bloco invertido
                NO* proximoOriginal = ultNv->prox;

                //chamada agora inclui também o ultNv como ponteiro de fim
                inverterNvs(pNv->prox, pNv, ultNv);

                //o pNv que era o primeiro é agora o ultimo, e por isso o seu prox
                //tem de apontar para o antigo próximo
                pNv->prox = proximoOriginal;

                //o ultNv que era o ultimo é agora o primeiro, e por isso o antes 
                //deste (o anterior) tem de agora apontar para ultNv. É necessário 
                //considerar o caso em que o anterior é nulo, que é quando inverte 
                //logo da primeira letra
                if (anterior == NULL){
                    resp->inicio = ultNv;
                }
                else {
                    anterior->prox = ultNv;
                }

                //o atual fica no ultimo após inversão
                atual = pNv;
            }
        }

        anterior = atual; //atualiza o anterior
        atual = atual->prox;
    }
}

Notice I had to add so much pointer anterior pointer proximoOriginal to be able to connect the inverted block with the list that already existed. Because when the inversion of o"nstr" for o"rtsn" the o continued to point to the n when it should now point to the r, which is what makes the instruction:

anterior->prox = ultNv;

Similarly the n which is now the new end has to point to the letter that comes after this block, which is what is done in this statement:

pNv->prox = proximoOriginal;

Watch it work on Ideone working

  • Your answer is exactly what I needed. Thank you very much!

  • @Nothing, good luck with the rest of the job

  • I just noticed two errors: the last letter is being ignored (in "will rain" the letter "r" is not treated); entries containing sentences with more than two words end with "non-zero status", for example, "will rain tomorrow".

  • @Caioignm the "vai chover" gives "vaihc over" which according to logic was expected. What was the result that "vai chover" should I? And I see the same for "vai chover amanha" that returns "vaich ove ramahna" that in my otica was the expected

  • @The detail of the point was not indicated in the question, which is why "vai chover." will result in "vaihc ove.r", which I suspect was not what I wanted ? It is supposed to program ignore accentuation characters like '?', '!','.',etc... ?

  • I noticed two errors: first, when the last word ends with a sequence of non-vowels, for example "it will rain tomorrow." the program does not work. Note that if the input was something like "it will rain tomorrow." the program works perfectly, because the word does not end in sequence of non-vowels. Second, your remark on the point is correct, ""will rain."" should result in "vaihc Ove. r". I am using Codeblocks 16 and, with this last example, the program does not work

  • @Caioignm This has to do with what I said. This was not contemplated in the logic soon a . is regarded as a vowel and is therefore reversed with the rest of the adjacent vowels. Hence I have asked if your program is supposed to ignore the dots, as well as other accentuation characters

Show 3 more comments

1

This nay is a direct answer to the question put, but only a solution of the problem posed.

Follow a filter that using regular expressions searches only the critical zones and writes them inverted. In case I will use flex, that generates C:

%%
[^aeiou\n]{2,}  {for( int i=yyleng-1; i>=0; i--) putchar(yytext[i]) ;}
%%

Mode of use:

$ flex -o filtro.c filtro.fl
$ cc filtro.c -o filtro -lfl
$ echo "monstros legais"| filtro
mortsnol segais

Finally this substitution is trivial in languages that have good support for regular expression processing. Example:

$ echo "monstros legais"| perl -pe 's/([^aeiou]{2,})/reverse($1)/ge'
mortsnol segais
  • 1

    Thank you, Jjoao. As this is an academic work I should use only pointers and lists simply chained

  • @ Caioignm, OK.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.