| Linha | Codigo |
| 001 | // Prof. Leo^nidas - http://www.matematica.br ; http://line.ime.usp.br |
| 002 | // MAC122 |
| 003 | // 2017/09/07 |
| 004 | // |
| 005 | // Baseado no metodo de ordenacao para caracteres do tipo "digito menos significativo" ("least significant digits first" - LSD) |
| 006 | // Exemplo de metodo no paradigma "GULOSO" |
| 007 | // |
| 008 | // Aplicacao ao caso de inteiros: ordena supondo que numeros estao em pequena faixa de valores ("universo") |
| 009 | // |
| 010 | // Usa a ideia de "vetor de bits" para representar conjunto: x presente <=> vet[x]==1. |
| 011 | // Aqui usaremos o indice deslocado de 1 : x presente <=> vet[x+1]==1 |
| 012 | // |
| 013 | // Complexidade do algoritmo de ordenacao : O(n + u), se u = #universo |
| 014 | |
| 015 | // Algumas referencias: |
| 016 | // - "Chapter Ten. Radix Sorting" do livro do Sedgewick "Algorithms in C"/"C++ Programming" |
| 017 | // - "Ordenacao digital", material do prof. Paulo Feofiloff: https://www.ime.usp.br/~pf/algoritmos/aulas/radix.html |
| 018 | |
| 019 | #include <stdio.h> // para 'printf' e 'scanf' |
| 020 | #include <stdlib.h> // para "rand()" para gerar valores "pseudo-aleatorios" (agilizar "entrada de dados") |
| 021 | |
| 022 | #define TAM 10 // tamanho para o vetor de dados (maximo de elementos no vetor de dados) |
| 023 | #define INTERVALO 100 // gerar elementos entre 0..INTERVALO-1 para compor o conjunto "universo" |
| 024 | |
| 025 | // Prototipos para funcoes utilizadas (importante caso ocorra dependencia cruzada - funcao 'a()' depende de 'b()' e 'b()' depende de 'a()') |
| 026 | void gerarVetorDados(int [], int, int); |
| 027 | void imprimeVetor(int [], int); |
| 028 | void ordenaPorFrequencia(int *, int, int); |
| 029 | |
| 030 | // Gerar 'n' valores pseudo-aleatorios para o vetor V[] |
| 031 | void gerarVetorDados (int V[], int n, int intervalo) { |
| 032 | int i; |
| 033 | for (i=0; i<n; i++) |
| 034 | V[i] = (int)(rand() % intervalo); //1 rand() gera inteiro entre {0,...,(2^31)-1 }, srand() pode mudar "semente" |
| 035 | //2 V[i] = n-i-1; //2 outro teste... |
| 036 | //3 V[i] = i % 2; //3 outro teste... |
| 037 | } |
| 038 | |
| 039 | // Imprime dados do vetor |
| 040 | void imprimeVetor (int V[], int n) { |
| 041 | int i; |
| 042 | for (i=0; i<n; i++) |
| 043 | printf("%4d", V[i]); |
| 044 | printf("\n"); |
| 045 | } |
| 046 | |
| 047 | // Ordena crescente v[0..n-1] supondo que os elementos do vetor pertencem ao universo 0..U-1 |
| 048 | void ordenaPorFrequencia (int *vet, int n, int U) { |
| 049 | int ind, ii, i; |
| 050 | int *vetFreqAcum, *vetAux; |
| 051 | vetFreqAcum = malloc((U+1) * sizeof(int)); // para freq de cada diferente elemento |
| 052 | vetAux = malloc(n * sizeof(int)); // auxiliar para vetor de dados |
| 053 | |
| 054 | // Ideia: |
| 055 | // 1. Computar frequencia de cada elemento considerando o "universo" (ideia de "vetor de bits"): O(n) |
| 056 | // 2. Acumular as frequencias (de 0 ate U-1) somando frequencia acumulada anterior (FAA) |
| 057 | // 3. A posicao da primeira ocorrencia de cada elemento e' dada pela FAA |
| 058 | // A posicao da proxima ocorrencia do mesmo elemento e' na posicao seguinte |
| 059 | |
| 060 | // 1. Computar frequencia de cada elemento considerando o "universo" (ideia de "vetor de bits"): O(n) |
| 061 | for (i = 0; i <= U; i++) |
| 062 | vetFreqAcum[i] = 0; |
| 063 | for (i = 0; i < n; ++i) { // anotar a freq de i na posicao i+1 => permite pegar a freq do 0 (0+1-1) |
| 064 | ind = vet[i]; // encontra posicao (ind) do elemento no "vetor de bits" |
| 065 | vetFreqAcum[ind+1]++; // mais uma ocorrencia desse elemento => usar posicao seguinte |
| 066 | //D1 printf(" %3d", vetFreqAcum[ind+1]); //D1 para examinar as frequencias |
| 067 | } |
| 068 | //D1 printf("\n"); |
| 069 | |
| 070 | // 2. Acumular as frequencias (de 0 ate U-1) somando frequencia acumulada anterior (FAA) |
| 071 | // Acumular frequencias: vetFreqAcum[i] recebera a frequencia de i-1 => recebe soma dos anteriores |
| 072 | for (i = 1; i <= U; i++) { |
| 073 | vetFreqAcum[i] += vetFreqAcum[i-1]; |
| 074 | } |
| 075 | //D1 printf("FAA: "); imprimeVetor(vetFreqAcum, U); // no conj universo |
| 076 | |
| 077 | // 3. A posicao da primeira ocorrencia de cada elemento e' dada pela FAA |
| 078 | // A posicao da proxima ocorrencia do mesmo elemento e' na posicao seguinte |
| 079 | // Como vetFreqAcum[i] e' a freq. de todos os predecessores de i |
| 080 | // entao o elemento de i deve ser posicionado no indice vetFreqAcum[i] e proximas ocorrencias nas seguintes |
| 081 | for (i = 0; i < n; i++) { |
| 082 | ind = vet[i]; // pegar indice do elemento no vetor "universo" (1 a menos pois o primeiro deve ir para 0 e sua freq e' 1) |
| 083 | vetAux[vetFreqAcum[ind]] = vet[i]; // colocar na posicao considerando os anteriores |
| 084 | vetFreqAcum[ind]++; // a proxima ocorrencia do elemento i deve ir para proxima posicao |
| 085 | //D2 printf("(%2d) %2d para posicao %2d\n", ind-1, vet[i], vetFreqAcum[ind-1]); |
| 086 | } |
| 087 | //D1 printf("FAA: "); imprimeVetor(vetFreqAcum, U); |
| 088 | |
| 089 | // vetAux[0..n-1] este em ordem crescente |
| 090 | for (i = 0; i < n; ++i) |
| 091 | vet[i] = vetAux[i]; |
| 092 | |
| 093 | free(vetFreqAcum); // libera memoria |
| 094 | free(vetAux); |
| 095 | } |
| 096 | |
| 097 | // inicia aqui... |
| 098 | int main (void) { |
| 099 | int V[TAM], tam; |
| 100 | int continua, loc, x; |
| 101 | char c; |
| 102 | |
| 103 | printf("\n\n\nDados iniciais:\n"); |
| 104 | tam = TAM; |
| 105 | gerarVetorDados(V, tam, INTERVALO); |
| 106 | imprimeVetor(V, tam); |
| 107 | |
| 108 | ordenaPorFrequencia(V, tam, INTERVALO); |
| 109 | |
| 110 | printf("\nOrdenado:\n"); |
| 111 | imprimeVetor(V, tam); |
| 112 | |
| 113 | return 0; |
| 114 | } |