Calculando a Mediana, Tenenbaum 1.2.1 a

Olá. Essa aqui é a resolução comentada do exercício 1.2.1 a da página 53 do livro Estrutura de dados em C que transcrevo aqui:

A mediana de um vetor de números é o elemento m do vetor, tal que metade dos números restantes no vetor é maior ou igual a m e metade é menor ou igual a m, se o número de elementos no vetor for ímpar. Se o número de elementos for par, a mediana será a média dos dois elementos, m1 e m2, tal que metade dos elementos restantes é maior ou igual a ml e m2, e metade dos elementos é menor ou igual a m1 e m2. Escreva uma função em C que aceite um vetor de números e retorne a mediana dos números no vetor.

Tenenbaum, Langsam e Augesnstein (2013)

Bom, esse aqui está relativamente fácil de resolver e temos dois cenários:

  • Antes de tudo, temos de classificar o array em ordem crescente.
  • Se a gente tiver um array com um conjunto par de números, basta tirar a média entre os dois elementos do meio do array e teremos a mediana.
  • Se a gente tiver um array com um conjunto ímpar de números, basta escolher o elemento central do array.

Antes de continuarmos:

Meu caro. Se esse artigo lhe ajudar e de alguma forma der um adianto para ti, vou ficar muito feliz se você clicar nos links de meus anunciantes e dar uma olhada no que eles tem para te oferecer. Grato :-).

Alguns pontos importantes:

O código dessa implementação, inclusive com os testes unitários, podem ser baixados diretamente de meu repositório no GitHub, clicando aqui.

Essa solução utiliza a biblioteca de teste unitário CuTest que é de código aberto e pode ser baixada diretamente no site do SourceForge, clicando aqui.

O legal dessa solução é que você pode apagar todo o código principal, deixar os testes unitários e ir implementando as funções no seu estilo, tendo o original para dar uma olhadinha caso queira. Basta remover o código principal, rodar o teste unitário, vai dar erro em tudo e voilá… Hora de sair implementando código e inclusive fazendo melhor que eu :-).

Para simplificar os testes e a execução do programa, eu automatizei a geração dos números aleatórios, o que facilita os testes e não precisamos ficar manualmente inventando valores para testar o programa ou para ver como ele funciona.

A implementação:

Conforme imagem abaixo segue a organização do projeto, começando pela pasta “Source” que contém as pastas “Sources”, “Headers” e “Teste_unitário”.

Organização dos arquivos do projeto.

O programa mesmo são os arquivos main.c, funcoes.c e funcoes.h. Os demais arquivos podem ser removidos, desde que obviamente sejam ajustados os includes.

Caso você queira desenvolver a sua solução, pode apagar o conteúdo de funcoes.c, rodar o teste unitário e sair implementando a solução, no seu estilo, seguindo os testes unitários.

Descrição dos arquivos:

main.c:

Esse arquivo é a entrada do programa. Basicamente esse arquivo faz a impressão da tela e chama as funções:

  • Contém a seleção do modo do programa, debug ou normal.
  • Contém a seleção do modo de execução: contínuo ou unitário.
  • “gera_aleatorio” que gera um array de 10 ou 11 elementos, conforme o caso..
  • “classifica” que classifica o array em ordem crescente e calcula o valor da mediana.
  • Faz a impressão da saída dos dados.

funcoes.h e funcoes.c:

Esses dois arquivos acomodam a função “gera_aleatorio”, responsável por popular um array de int, de acordo com o valor especificado na variável “tamanho”.

Eles acomodam a função “classifica” que faz a classificação do array que foi gerado anteriormente e calcula a mediana. A função “classifica” utiliza o método quicksort para classificar o array.

A função “qsort”, para funcionar, faz uma chamada à “funcao_compara” que também está nos mesmos aquivos funcoes.h e funcoes.c.

TesteMediana_121a.h e TesteMediana_121a.c:

Esses arquivos acomodam os testes unitário para fazer a asserção das funções do programa e também serve como documentação do software. São 4 funções, sendo duas para gerar o array de números aleatórios e 2 funções para verificar se a mediana está sendo calculada corretamente.

O código:

main.c:

#include <stdio.h>
#include <stdlib.h>
#include "Teste_unitario/Teste_Mediana_121a.h"
#include "Teste_unitario/CuTest.h"
#include "funcoes.h"

/*
Exercício 1.2.1 a.
A mediana de um vetor de números é o elemento m do vetor, tal  que  metade  dos
números restantes no vetor é maior ou igual a m e metade é menor ou igual a  m,
se o número de elementos no vetor for ímpar. Se o número de elementos for  par,
a mediana será a média dos  dois  elementos,  m1  e  m2,  tal  que  metade  dos
elementos restantes é maior ou igual a ml  e  m2,  e  metade  dos  elementos  é
menor ou igual a m1 e m2. Escreva uma função  em  C  que  aceite  um  vetor  de
números e retorne a mediana dos números no vetor.

Fonte: Estruturas de Dados Usando C - Tenembaum, pg53.

Autor da solução: Renato de Pierri
nets-nuts.com.br

Para simplificar a solução, ao inves de inserir os valores no array, optei  por
gerar automaticamente os valores do array.

*/
//Suite de testes
CuSuite* CuGetSuite();
CuSuite* CuStringGetSuite();

int main()
{
    int debug =0;
    int continuo = 1;
    int mediana_10[10];
    int mediana_11[11];
    double mediana;
    int controle;

    do{
        if(debug == 0){

            printf("Calcula mediana de 10 elementos.\n\n");
            printf("Aqui a mediana eh a media entre o quinto e sexto elemento do array.\n");
            printf("Gerando um array de 10 elementos inteiros.\n");

            gera_aleatorio(mediana_10,10);

            printf("Classificando o array de 10 elementos.\n");

            mediana = classifica(mediana_10,10);

            printf("Imprimindo o array de 10 elementos, classificado.\n");
            for(controle = 0;controle<=9;controle++){
              printf("%i, ", mediana_10[controle])  ;
            }
            printf("\n");
            printf("A mediana eh: %.01f.\n\n\n",mediana);

            printf("Calcula mediana de 11 elementos.\n\n");
            printf("Aqui a mediana eh o sexto elemento do array.\n");
            printf("Gerando um array de 11 elementos inteiros.\n");

            gera_aleatorio(mediana_11,11);

            printf("Classificando o array de 11 elementos.\n");

            mediana = classifica(mediana_11,11);

            printf("Imprimindo o array de 11 elementos, classificado.\n");
            for(controle = 0;controle<=10;controle++){
              printf("%i, ", mediana_11[controle])  ;
            }
            printf("\n");
            printf("A mediana eh: %.01f.\n\n",mediana);

            system("pause");
            system("cls");

        }else{
            RunAllTests();
            system("pause");
            system("cls");
        }
    }while(continuo == 1);
return 0;
}

funcoes.h:

#ifndef FUNCOES_H_INCLUDED
#define FUNCOES_H_INCLUDED

void gera_aleatorio(int valores[],int tamanho);
float classifica(int mediana[], int tamanho);
int funcao_compara (const void * a, const void * b);

#endif // FUNCOES_H_INCLUDED

funcoes.c:

#include <stdio.h>
#include <stdlib.h>
#include "Teste_unitario/Teste_Mediana_121a.h"
#include "Teste_unitario/CuTest.h"
#include "funcoes.h"

void gera_aleatorio(int valores[],int tamanho){
    int controle;
    for(controle = 0;controle<=tamanho;controle++){
        valores[controle]=rand() % 100;
    }
}

float classifica(int mediana[], int tamanho){
    int sup;
    int inf;
    float med;
    qsort(mediana, tamanho, sizeof(int), funcao_compara);
    if (tamanho%2==0){
        sup = (int)(tamanho/2);
        inf = sup - 1;
        med = (mediana[sup]+mediana[inf])/2.0f;
    }else{
        sup = (int)(tamanho/2);
        med =(float) mediana[sup];
    }
return med;
}

int funcao_compara (const void * v1, const void * v2) {
    return ( *(int*)v1 - *(int*)v2 );
}

Teste_Mediana_121a.h:

#ifndef TESTE_MEDIANA_121A_H_INCLUDED
#define TESTE_MEDIANA_121A_H_INCLUDED
#include "CuTest.h"
CuSuite*StrUtilGetSuite();
void RunAllTests(void);

// Testes unitarios

void TesteAleatorio_10(CuTest *tc);
void TesteAleatorio_11(CuTest *tc);
void TesteClassifica_10(CuTest *tc);
void TesteClassifica_11(CuTest *tc);

#endif // TESTE_MEDIANA_121A_H_INCLUDED

Teste_Mediana_121a.c:

#include <stdlib.h>
#include <stdio.h>
#include "Teste_Mediana_121a.h"
#include "CuTest.h"
#include "../funcoes.h"

CuSuite* StrUtilGetSuite();

void RunAllTests(void){
    CuString* output = CuStringNew();
    CuSuite* suite = CuSuiteNew();
    CuSuiteAddSuite(suite, StrUtilGetSuite());
    CuSuiteRun(suite);
    CuSuiteSummary(suite, output);
    CuSuiteDetails(suite, output);
    printf ("%s\n\n", output->buffer);

}

void TesteAleatorio_10(CuTest *tc){
    CuString* str = CuStringNew();
    int valores[10];
    size_t nr_elementos;
    char resp1[5];
    gera_aleatorio(valores,10);
    nr_elementos = sizeof(valores)/sizeof(valores[0]);
    sprintf(resp1,"%i",(int)nr_elementos);
    CuStringAppend(str,resp1);
    CuAssertStrEquals(tc, "10", str->buffer);
}

void TesteAleatorio_11(CuTest *tc){
    CuString* str = CuStringNew();
    int valores[11];
    size_t nr_elementos;
    char resp1[5];
    gera_aleatorio(valores,11);
    nr_elementos = sizeof(valores)/sizeof(valores[0]);
    sprintf(resp1,"%i",(int)nr_elementos);
    CuStringAppend(str,resp1);
    CuAssertStrEquals(tc, "11", str->buffer);
}

void TesteClassifica_10(CuTest *tc){
    int valores[10] = {91, 27, 27, 42, 45, 81, 91, 4, 36, 61};
    float mediana;
    mediana = 7.3;
    char resp1[5];
    CuString* str = CuStringNew();
    mediana = classifica(valores,10);
    sprintf(resp1,"%.01f",mediana);
    CuStringAppend(str,resp1);
    CuAssertStrEquals(tc, "43.5", str->buffer);
}

void TesteClassifica_11(CuTest *tc){
    int valores[11] = {91, 4, 27, 36, 45, 61, 81, 91, 95, 27, 42};
    float mediana;
    char resp1[5];
    char resp2[5];
    CuString* str = CuStringNew();
    mediana = classifica(valores,11);
    sprintf(resp1,"%.01f",mediana);
    sprintf(resp2,"%.01f",(float)valores[5]);
    CuStringAppend(str,resp1);
    CuAssertStrEquals(tc, resp2, str->buffer);
}

CuSuite*StrUtilGetSuite(){
    CuSuite* suite = CuSuiteNew();

    SUITE_ADD_TEST(suite,TesteAleatorio_10);
    SUITE_ADD_TEST(suite,TesteAleatorio_11);
    SUITE_ADD_TEST(suite,TesteClassifica_10);
    SUITE_ADD_TEST(suite,TesteClassifica_11);

}

Como sempre, muito obrigado e não esqueça de clicar nos anúncios e ver o que os anunciantes tem de bom para te oferecer.

Publicado em 21/01/2023 por Renato de Pierri.

Bibliografia:

TENENBAUM, Aaron M.; LANGSAM, Yedidyah; AUGESNSTEIN, Moshe J.. Estruturas de Dados Usando C. São Paulo: Pearson, 2013. 884 p. ISBN 13: 978-85-346-0348-5, pg 53.

Last updated by at .