PDA

Ver la versión completa : Una ayudita con C



Multi
13/05/2012, 22:34
Hola famigos foreros.

Veréis, tengo que desarrollar un programa en C y me encuentro con el siguiente problema:

Tengo un fichero con números, repetidos y desordenados, tal que:
50252
50344
50200
50252
50344

y necesito mostrar por pantalla el que más se repite (y las veces que se repite) y el que menos se repite (y las veces que se repite).

El caso es que llevo toda la tarde trasteando con ifs y bucles for y no consigo nada...

Alguien me puede echar un cable? Gracias! :brindis:

Endher
13/05/2012, 22:45
Tengo un poco oxidado el C, así que te medio explicaré mi lógica a ver si sirve :). Vas leyendo el fichero, y cada vez que leas una línea almacenas esa cifra en una variable. Luego creas más variables, una por cada número diferente que haya. Y creas una serie de fucles if-else tal que:
if (variable==50252) { a=a+1;} else...

Y así sucesivamente. Cuando acabes, haces bucles de comparación entre las variables, y enseñas el que mas, y el que menos ;)

Seguro que hay formas más mejores y más limpias, pero yo soy un poco gitano xD

Los últimos bucles los haria en plan if(a>b && a>c...) para intentar ahorrar cadenas.

Multi
13/05/2012, 23:19
El problema está en que la cantidad de números distintos puede variar, entonces no puedo (o no sé) crear tantas variables como números, ya que no sé cuántos hay... Hay alguna forma de hacerlo?

furfur
13/05/2012, 23:32
Eso que dices, contar las veces que sale cada valor, es un histograma y hay programas matemáticos que te los pueden pintar, yo uso root que es prácticamente C++... Así de repente se me ocurre que puedes hacerte un array, y como no sabes el número total de elementos, los metes con el método push_back (http://www.cplusplus.com/reference/stl/vector/push_back/)
y una vez almacenado todos los valores en un array ya puedes hacer bucles para comparar y eso... no sé si esto te sirve de ayuda hamijo!!

pakoito
13/05/2012, 23:33
¿Puedes usar las STL? un mapita que te pego con el número de key y la cantidad de valor, y la búsqueda en O(1). Si no puedes, lista ordenada de struct { int numero; int cantidad; } te hace el apaño.

Xonaag
13/05/2012, 23:41
¿Has pensado en usar listas dinámicas enlazadas (http://www.macs.hw.ac.uk/~rjp/Coursewww/Cwww/linklist.html)?

Se despide Xonaag

Multi
13/05/2012, 23:47
¿Puedes usar las STL? un mapita que te pego con el número de key y la cantidad de valor, y la búsqueda en O(1). Si no puedes, lista ordenada de struct { int numero; int cantidad; } te hace el apaño.

Pero STL es C++, no? Yo necesito hacerlo en C, pero gracias :)


¿Has pensado en usar listas dinámicas enlazadas (http://www.macs.hw.ac.uk/~rjp/Coursewww/Cwww/linklist.html)?

Se despide Xonaag

Pues no tenía ni idea de lo que era eso... voy a mirarlo. Muchas gracias!

Xonaag
13/05/2012, 23:52
[...]
Pues no tenía ni idea de lo que era eso... voy a mirarlo. Muchas gracias!

Lo único que ese ejemplo no incluye el liberar la memoria al final del programa (y es obligatorio si usas calloc o malloc), si necesitas más ayuda solo avísame y quedamos por skype o algo.

Se despide Xonaag

pakoito
14/05/2012, 00:13
Tiene que haber una solución por algoritmia que requiera menos almacenamiento, pero no caigo ahora :/ Y paso de ir a stackoverflow a que me dejen en ridículo xD

amkam
14/05/2012, 00:25
Hace la tira que no hago nada en c, pero igual esto te puede servir, ni sé si funciona...:

Cada numero nuevo que leas guárdalo en un array de struct que aumente dinámicamente, el struct tendrá el puntero y un contador (optimizas así el uso de memoria). Cada numero leído se buscará en la lista, si lo encuentra aumentará el contador del struct encontrado y pasará a leer el siguiente numero sin leer; pero si no lo encuentra y llega al final del array, entonces lo añade y pasa al siguiente sin leer también. Cuando termines de leer numeros, repasa una última vez el array para encontrar el que tenga el contador mayor y voilá.

pakoito
14/05/2012, 00:45
Eso que comentas no es un array, es una lista enlazada que hemos dicho antes. Los arrays en C son un poco estrictos y no puedes ir añadiendoles memoria al final como los MutableArrays de Java.

otto_xd
14/05/2012, 01:08
Creo que lo mas sencillo seria crearte un elemento lista, con un entero (numero de elementos de la lista) y un puntero a nodo.
Nodo seria otro elemento, con un entero (el numero que lees), numero de veces que aparece y un puntero a nodo.

Cada vez que lees un numero, miras si existe en tu lista (la recorres), si existe, incrementas el numero de veces en el que aparece, sino aparece, creas un nuevo elemento al final de la lista.

Finalmente recorres la lista, sacando el puntero del valor mas bajo y mas alto, y puedes imprimirlos por pantalla.

Despues de esto tienes que recorrer la lista limpiando la memoria que has reservado.

Y esto sin mirar nada de C, pero creo que seria mas o menos asin

pakoito
14/05/2012, 01:16
Otto, ¿crees que ir reordenando la lista por tamaño en cada pasada gastará mas proceso que hacer una busqueda del máximo al final? supongo que depende del tamaño final :/

otto_xd
14/05/2012, 01:34
Otto, ¿crees que ir reordenando la lista por tamaño en cada pasada gastará mas proceso que hacer una busqueda del máximo al final? supongo que depende del tamaño final :/
Dependiendo de como se construya la lista y del algoritmo, y en eso no estoy muy puesto.

Pero el que yo me conozco creo que hacia tantas iteraciones como el factorial del numero de elementos de la lista, y si vas metiendo mas elementos, pues el proceso va creciendo.

Buscar el elemento mas alto y el mas bajo seria tan facil como recorrer la lista 1 vez comparando con los numeros de los nodos, en el primer caso los dos numeros serian el mismo, en el siguiente ya cambiarian.

juanvvc
14/05/2012, 01:47
Imagino que lo que te están pidiendo es que programes una hash table. Utilizar alguna standard, como la de search.h no tendría ninguna gracia porque se hace en un puñado de líneas.

pakoito
14/05/2012, 01:50
Eso también lo he dicho yo, pero es c a pelo y no pueden usar STL o similares, y si no sabe lo que es una lista enlazada lo de crearse su propia función de hash no lo veo jajajaja

juanvvc
14/05/2012, 01:55
Es que no sabemos de qué va la pregunta. Si la pregunta es "programa una hash table", como supongo, que no sepa lo que es una lista enlazada solo significa que tiene que estudiar más y después volver a intentar responder la pregunta ;)

Por otro lado, no he mencionado STL sino search.h que sí que es C. Si la pregunta es "busca y usa alguna hash table", entonces ésa es la respuesta :D http://pubs.opengroup.org/onlinepubs/7908799/xsh/hsearch.html

pakoito
14/05/2012, 01:58
No, me da que esto es solo algoritmia y los numericos esos. Tiene que haber otra solución si no han dado las listas enlazadas aun :P

otto_xd
14/05/2012, 02:06
No, me da que esto es solo algoritmia y los numericos esos. Tiene que haber otra solución si no han dado las listas enlazadas aun :P

Si, crear un array de 10000000000 de elementos xD

juanvvc
14/05/2012, 02:30
Bueno, por algoritmia y suponiendo que sepa que hay como máximo NUM números diferentes.




#define NUM 100

int numbers[NUM]; // array de números que nos hemos encontrado.
int frequency[NUM]; // array de frecuencias de los números encontrados. Mismo índice que numbers[]
char* line; // última línea leída
int number; // últimos número leído
int pos; // contador de posición en numbers[] y frequency[]
int lastpos = 0; // última posición de numbers[+ y frequency[] con información.

while(line=readline()) {
// convertimos la línea leída a número
number = atoi(line);
// metemos en pos la posición dentro de numbers[] donde encontramos el número. Nota que si no encontramos el números, pos==lastpos
for(pos=0; pos<lastpos; pos++) if (numbers[pos] == number) break;
// si no hemos encontrado el número porque nunca lo habíamos visto, lo registramos en ambos arrays
if (pos == lastpos) {
numbers[pos] = number;
frequency[pos] = 0;
lastpos++;
}
// pase lo que pase, aumentamos la frecuencia de ese número
frequency[pos]++;
}


Y luego la información "el que más se repite" y "el que menos" se encuentra recorriendo el array frequencies.

(si quiere limitar NUM, podría estimarlo por ejemplo leyendo primero el número de líneas que hay en el archivo. Así sabe que como máximo, NUM será igual al número de líneas :D)

---------- Post added at 02:30 ---------- Previous post was at 02:08 ----------

Hablando de todo un poco: desde línea de comandos si el archivo se llama datos.txt

* Número más usado, y apariciones: cat datos.txt | sort | uniq -c | sort -n | tail -n 1
* Número menos usado, y apariciones: cat datos.txt | sort | uniq -c | sort -n | head -n 1

Multi
14/05/2012, 02:31
Hemos dado C a un nivel bastante básico, la verdad.

Os explico lo que me piden:
Tengo un fichero con las ventas de una tienda, ordenadas tal que así:

CODIGO_EMPLEADO CODIGO_PRENDA PRECIO

Me piden mostrar cual es el empleado que más ha vendido (y el importe total de sus ventas) y el que menos (y el importe total de sus ventas) y, por otro lado, la prenda que mas se ha vendido (y el importe total) y la que menos (y el importe total).

El de la prenda es relativamente fácil y ya lo tenía hecho, pero el del empleado era el que me faltaba.

Seguro que lo he hecho de una manera mucho más difícil, pero el caso es que funciona.
Os cuento:

Creo dos array de dimensión 100 (qué tienda tiene más de 100 empleados? jajaja). Uno lo usaremos para almacenar el codigo de empleado y otro para almacenar las veces que se repite.

Leo el fichero y guardo en el array los códigos de los empleados, repetidos incluidos. Luego, ayudándome de arrays auxiliares, dejo el vector sólo con los que no se repiten.

Vuelvo a leer el fichero y comparo.
Si el codigo que leo es igual a (por ejemplo) empleado[i], sumamos una unidad a veces[i] (veces[i]++)

Y luego ya viene la ristra de ifs para ver cual es el que más ha vendido y tal.

Cómo lo veis? fatal, no? jajaja

juanvvc
14/05/2012, 02:34
Eso es casi lo mismo que he puesto arriba, así que lo veo perfectamente :D

Lo único que no entiendo es por qué metes en un array "los códigos de los empleados, repetidos incluidos", en vez de meterlo directamente en los arrays auxiliares que es lo que haces justo después.

Multi
14/05/2012, 02:37
Eso es casi lo mismo que he puesto arriba, así que lo veo perfectamente :D

Lo único que no entiendo es por qué metes en un array "los códigos de los empleados, repetidos incluidos", en vez de meterlo directamente en los arrays auxiliares que es lo que haces justo después.

Cosas de ir como un pollo sin cabeza... jajajaja
Voy a modificar eso. Gracias!

Reycat
14/05/2012, 12:24
Sin arrays ni nada (pero poco eficiente). Ah, y sin notación C, que no la recuerdo :)

Defines cuatro variables: num_1 y num_2 y repe_1 y repe_2

for bucle1 = 1 to fin_fichero
begin

elemento= fichero[bucle1]
repe_temp=0

for bucle2 = 1 to fin_fichero
begin
Si fichero[bucle2]=elemento Then repe_temp++

end for

Si repe_temp>repe_1 Then
begin if
repe_1=repe_temp
num_1=elemento
End

Si repe_temp<repe_2 Then
begin if
repe_2=repe_temp
num_2=elemento
End if

End for

hardyx
14/05/2012, 13:22
Lo mas fácil es hacer un array de estructuras, y cada estructura que sea el número y las veces que aparece en el fichero. Luego lees el fichero y buscas en el array cada número, si está le sumas 1 a las veces, y si no está lo añades al array. Necesitas una variable que indique el tamaño del array, y lo dimensionarás con 1000 elementos por ejemplo. Es una solución sencilla si no quieres usar estructuras dinámicas o STL, que son mejores por supuesto. Es parecido a la solución que ha puesto juanvvc.

SplinterGU
14/05/2012, 16:48
la cosa aca es que no solo tienes empleados repetidos, sino que tambien tambien puedes tener mas de 1 que sean los que mas vendieron o los que menos vendieron...

la primera opcion que se me ocurria es que cargues todo el archivo a memoria, lo ordenes con un qsort y a contar, guardando los ids de los que mas y menos se repiten, pero teniendo en cuenta que podes tener mas de 1 id de maximo y mas de 1 de minimo (podes usar una lista enlazada, una string separadas por comas o punto y coma de los ids, lo que se te ocurra)

la segunda opcion, ahora que nos dices que son ventas es tener un array bidimensional (ordenado con qsort) con la misma cantidad de elementos que la cantidad de vendedores (1 elemento por array, donde cada elemento es: id de vendedor y cantidad de venta o importe), y luego vas recorriendo el archivo y totalizando en cada vendedor por cada venta que vas encontrando (aca podes usar bsearch, ya que tenes el array ordenado previamente con qsort)... a medida que vas totalizando, vas guardando los ids de los que mas vende en una lista o array temporal y el valor de referencia para ese array temporal (cuando encuentras uno que haya vendido mas con respecto al valor de referencia maximo ultimo, limpias la lista con los ids anteriores e inicias una lista nueva)... cuando llenas el array de vendedores lo vuelves a recorrer para buscar los ids minimos (esta vez no lees el archivo, sino el array de vendedores mas chicos donde tienes todo totalizado), y encuentras cuales son los minimos, tomando como referencia de valor minimo el primero que encuentras en la lista.

asi de simple, no deberian ser para nada muchos ifs... deberia ser 20 lineas de codigo como mucho...

pakoito
14/05/2012, 19:09
Lo mas fácil es hacer un array de estructuras, y cada estructura que sea el número y las veces que aparece en el fichero. Luego lees el fichero y buscas en el array cada número, si está le sumas 1 a las veces, y si no está lo añades al array. Necesitas una variable que indique el tamaño del array, y lo dimensionarás con 1000 elementos por ejemplo. Es una solución sencilla si no quieres usar estructuras dinámicas o STL, que son mejores por supuesto. Es parecido a la solución que ha puesto juanvvc.Pero si esa solución la di yo antes xDD ¡Malditos copiotas!

hardyx
14/05/2012, 20:51
Pero si esa solución la di yo antes xDD ¡Malditos copiotas!
Tienes razón, pero si te das cuenta, Multi no te hizo ni p... caso. :D


Pero STL es C++, no? Yo necesito hacerlo en C, pero gracias :)

pakoito
14/05/2012, 21:53
^

Esa era la solución "smart" que estaba esperando, pero ¿cuánto se tardaría en ordenar la lista, más o menos que con la cuenta?

Multi
14/05/2012, 22:16
El problema es que tengo (tenemos, somos un grupo de 3) conocimientos limitados de C (lo que nos han dado en clase, que bueno... deja que desear xD). Estudiaré lo que habeis dicho y si me sale alguna de las formas que habéis propuesto la sustituiré por mi forma a lo gitano xD

Muchas gracias a todos de todas formas.

hardyx
15/05/2012, 02:08
No se te ocurre hacer la solución de comparar decenas de números con if. Normalmente cuando se plantea un ejercicio es para que se usen ciertas estructuras.