Compress array by removing zeros [C]

Asked

Viewed 751 times

0

Question:

Make a program that reads a vector of 15 positions and compact, that is, eliminate zero positions. For this, all elements ahead of zero a rearward position shall be moved in the vector.

My problem is this:
When placed on the run 3 Digits 0 in a row the numbers after {0} are simply deleted

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

int main() {    

    int vet[10];
    int i,aux, s=1, c=0, l;

    for(i=0; i<10; i++){ //entrada de dados
        printf("Digite o valor da posicao %d do vetor: ",i+1);
        scanf("%d",&vet[i]);
    }
    for(i=0; i<10; i++){
        if(vet[i] == 0){
            c++;
        }
    }
    for(i=0; i<10; i++){ 
        if(vet[i] == 0){
            if(vet[i+1] == 0) s=2;
            aux=vet[i];
            vet[i]=vet[i+s];
            vet[i+1]=aux;
            s++;
        }
    }
    l = i - c;
    printf("\n");
    for(i=0; i<l; i++){
        if(vet[i] != 0){
            printf("VetorFinal [%d] = %d\n",i+1,vet[i]);
        }
    }
}

3 answers

2

One solution is to maintain an index for the copy position and another to the reading position. The copy position moves forward when it receives a different number from 0, already the reading always goes forward. At the end of this process, the copy position will be the size of the compressed vector.

In that loop, there’s a invariant. In case the invariant is that always at the end of the loop the variable pos_copia is pointing to a forward position of the last element of the new compressed vector.

To guarantee of termination loop can also be checked, since the variable pos_leitura always walks forward and never reads more elements than existed in the original vector.

A possible implementation of the programme is presented below.

#include <stdio.h>

#define MAX_TAM 5

int main()
{ 
    int vet[MAX_TAM];

    // lê entrada
    for(int i = 0; i < MAX_TAM; i++)
    {
        printf("Digite o valor da posicao %d do vetor: ", i + 1);
        scanf("%d", &vet[i]);
    }

    // realiza-se a cópia utilizando dois índices
    int pos_copia = 0;
    for(int pos_leitura = 0; pos_leitura < MAX_TAM; pos_leitura++)
    {
        if(vet[pos_leitura] == 0)
            continue;

        vet[pos_copia] = vet[pos_leitura];
        pos_copia++;
    }

    // imprime o resultado
    printf("\n");
    for(int i = 0; i < pos_copia; i++)
        printf("VetorFinal [%d] = %d\n", i + 1, vet[i]);
}
  • 1

    good solution, easy to understand

2

It already has some answers with alternative solutions to the question it intends to solve, but it is always good to understand where we went wrong and what does not serve our goal. This is where my answer focuses.

Starting with the second for:

for(i=0; i<10; i++){
    if(vet[i] == 0){
        c++;
    }
}

This for counts the boxes with 0 to be able to discount this amount of the size and show the correct final size, but it is unnecessary to do this in a separate block, since you can do it in the for that removes zeros. It still doesn’t break the logic.

The problem comes in the for next:

for(i=0; i<10; i++){ 
    if(vet[i] == 0){
        if(vet[i+1] == 0) s=2;
        aux=vet[i];
        vet[i]=vet[i+s];
        vet[i+1]=aux;
        s++;
    }
}

He has several problems actually. The second condition, the if(vet[i+1] == 0) s=2;, only allows you to see if you have two zeroes in a row to switch with the element 2 boxes in front. But what if you have 3 ? or 4 ? You can never do it with just one if Because you don’t know how many zeroes in a row. This would have to be replaced by a loop to find the next element other than 0, or the end if there is no one else. In this loop the s would always have to start at 1, to leave the house in front where is the zero.

Then the exchange between the two elements was also not correct, the vet[i+1]=aux;, for use i+1 when you should wear i+s.

To correct only your second for can do so:

for(i=0; i<10; i++){
    if(vet[i] == 0){
        s = 1; //começa sempre em 1
        while(i + s < 10 && vet[i+s] == 0){ //com while em vez de if
            s++;
        }
        if (i + s >= 10){ //se não tem mais zeros à frente para trocar termina
            break;
        }
        aux=vet[i];
        vet[i]=vet[i+s];
        vet[i+s]=aux; //agora i+s
        //sem o incremento s++;
    }
}
l = 10 - c;

Note that I had to include the l = 10 - c; for the i no longer necessarily ends at the end, which makes the old l = i - c; doesn’t always work properly.

See this change working on ideone

It is important to note that there are better algorithms for this problem, which are not only simpler but more efficient. One of them is what is in response posed by alandplm. I just showed you how to correct the logic you wrote to do the intended.

  • +1 for having shown the reason why the code does not work, effectively answering the question.

0

You don’t need to exchange content, you just need to move the following positions to the previous one when it’s zero.

#include <stdio.h>
int main() {

    int vet[15];
    int i, j, lim=15, k;

    for (i=0;i<15;i++) { //entrada de dados
         printf("Digite o valor da posicao %d do vetor: ",i+1);
         scanf("%d",&vet[i]);
    }
    do {
        k = 0;
        for (i=0;i<lim;i++) {
             if (vet[i]==0) {
                 for (j=i+1; j<lim; j++)
                        vet[j-1] = vet[j];
                 lim--;
                 k++;
             }
        }
    } while (k > 0);
    printf("\n");
    for (i=0;i<lim;i++) {
         printf("VetorFinal [%d] = %d\n",i,vet[i]);
    }
    return 0;
}
  • This solution presents problems. Entering only 5 elements to simplify, for example the following errors occur: input (0,0,0,1,2) -> output (0,1,2); input (0,0,0,0,0) -> output (0,0), input (1,2,0,0,3) -> output (1,2,0,3).

  • 1

    Corrected code.

Browser other questions tagged

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