Code to invert sequence of non-vowels ending with zero status

5

I'm implementing the decodificar function, which aims to call auxiliary functions to invert all non-vowel sequences. For example, if the word is "legal monsters", it will continue 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 inversions are not being made. My program is ending with status 0, according to CodeBlocks, even after calling the decodificar function. Full Code: link

    
asked by anonymous 04.09.2017 / 18:34

3 answers

2

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

Starting by reversing the nodes:

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 up to NULL to invert only a portion of the phrase, 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.

You can then change it by 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;
    }
}

It is also not correct in if because it validates with or ( || ) when it should validate with e ( && ). 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 give false .

Just change the if so that it stays:

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

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

You need:

  • Adjust the conditions of the 2% with%
  • Reconnect the inverted block with the rest of the list
  • Update while after inversion

Considering all this, it's now like this (I've cut your comments to focus only on the changes I've 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 that I had to add both the atual pointer and the anterior pointer to be able to bind the inverted block to the list that already existed. Because when the inversion of proximoOriginal to o"nstr" is made the o"rtsn" was still pointing to o when it should now point to n , which is what does the statement:

anterior->prox = ultNv;

Likewise, the% w / o% that is now the new end must point to the next letter to this block, which is what is done in this statement:

pNv->prox = proximoOriginal;

See working on Ideone

    
08.09.2017 / 20:29
3

You can separate this problem into two small problems:

  • Find the "sub list" that contains the sequence of non-vowels (consonants)
  • Invert a list that is simply linked.
  • The first problem is somewhat easier to solve, you can approach it in several ways. In the code below, I used a Recursive Function call InverteElementos .

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

    The function inverterNvs , traverses the list that is simply chained, member by member, and finds a sequence of consonants, exchanges the positions of the sequence members using a recursive function. p>

    Note that the function ehNaoVogal only serves 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;
        }
    }
    
        
    05.09.2017 / 04:03
    1

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

    The following is a filter that uses regular expressions only searches the critical zones and writes them inverted. In case I'm going to use flex , which generates C :

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

    How to 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 support for regular expression processing. Example:

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