├── 01-Cpp ├── 01-numeric_types.cpp ├── 02-other_types.cpp ├── 03-conditional.cpp ├── 04-Loops.cpp ├── 05-arrays.cpp ├── 06-structs.cpp ├── 07-pointers.cpp ├── 08-functions.cpp ├── 09-dynamic_memory.cpp ├── 10-dynamic_memory_matrix.cpp ├── 11-strings.cpp ├── 12-text_files.cpp ├── 13-binary_files.cpp ├── 14-binary_files_struct_arrays.cpp ├── archivo.txt ├── array.dat └── struct.dat ├── 02-TDA ├── 1-example.cpp └── 2-rational.cpp ├── 03-Exercise ├── caracteres_distintos │ ├── Exer.cpp │ └── Solu.cpp └── estudiantes_aprobados │ ├── Exer.cpp │ └── Solu.cpp ├── 04-EDDLineales ├── Browser_Chino.cpp ├── Cajeros.cpp └── Parentesis_Balanceado.cpp ├── 06-Hashing ├── hashing_attempt.cpp ├── hashing_attempt2.cpp └── hashing_attempt3.cpp └── README.md /01-Cpp/01-numeric_types.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | int main() { 5 | // Tipo de dato entero, contiene solo números enteros entre 6 | // [-2^31, 2^31 - 1] 7 | int num = 123; 8 | // Tipo de dato entero, pero cubre una mayor cantidad de enteros 9 | // este tipo de dato cubre entre [-2^64, 2^64 - 1] 10 | long long int num_grande = 10000000000; 11 | 12 | cout << "num = " << num << "\n"; 13 | cout << "num_grande = " << num_grande << "\n"; 14 | 15 | // Unsigned es una palabra que modifica el tipo numero a unicamente positivos 16 | // Para el caso de los `int`, el rango de numeros es ahora [0, 2^32 - 1] 17 | // Para el caso de los `long long`, el rango de numeros es ahora [0, 2^64- 1] 18 | unsigned long long int positivo = 123; 19 | // Si intentan guardar un numero negativo, C++ va a ignorar que es un numero negativo 20 | // y lo va guardar tal cual tiene los bits, provocando cosas que uno no esperaria 21 | unsigned long long int negativo_raro = -1; 22 | 23 | cout << "positivo = " << positivo << "\n"; 24 | cout << "negativo_raro = " << negativo_raro << "\n"; 25 | 26 | // Dato curioso, en este caso negativo raro va a ser equivalente al mayor entero 27 | // positivo representable que corresponde a 2^64 - 1 28 | 29 | // Tipo de dato flotante, corresponde a los decimales, o sea no necesariamente 30 | // enteros 31 | float con_coma = 232.231; 32 | // Pero tambien puede almacenar "enteros", solo que se guardan como X.0 33 | float entero = 2; 34 | // Por ejemplo, aqui estas guardando un 2, pero por detras es un 2.0 35 | cout << "con_coma = " << con_coma << "\n"; 36 | cout << "entero = " << entero << "\n"; 37 | 38 | // Si guardo en una variable de tipo entero una variable de tipo flotante 39 | // este se trunca 40 | int truncado = con_coma; 41 | cout << "truncado = " << truncado << "\n"; 42 | // Deberiamos ver por pantalla 232, no 232.231 43 | 44 | // Tipo de dato double, corresponde a los decimales, pero cubre un mayor rango 45 | double mas_rango = 12312.213123; 46 | cout << "mas_rango = " << mas_rango << "\n"; 47 | 48 | return 0; 49 | } 50 | -------------------------------------------------------------------------------- /01-Cpp/02-other_types.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | int main() { 5 | // Tipo de dato caracter, este corresponde a un caracter, ej. 'A', 'B', '(', etc. 6 | // Este tipo de datos se almacena como un entero segun el codigo ASCII 7 | // Si quieres revisar los valores de cada caracter en ASCII, revisar: https://elcodigoascii.com.ar 8 | char a = 'a'; 9 | cout << "a = " << a << "\n"; 10 | 11 | char A = 'A'; 12 | cout << "A = " << A << "\n"; 13 | 14 | // Al trabajar con el codigo ASCII, podemos realizar los siguiente trucos 15 | int ascii_A = A; 16 | cout << "ascii_A = " << ascii_A << "\n"; 17 | // Deberiamos ver en pantalla 65 18 | 19 | // El valor ASCII de `a` es 97, si es que le sumo 1 da 98. El 98 corresponde a 20 | // `b` en ASCII, por lo que ahora si imprimimos la variable deberiamos ver una `b` 21 | a++; 22 | cout << "a = " << a << "\n"; 23 | 24 | // El tipo de dato booleano, corresponde a verdadero y falso, para C++ cualquier numero 25 | // que no sea 0, es verdadero 26 | bool falso = false; 27 | cout << "falso = " << falso << "\n"; 28 | // De hecho, deberiamos ver un 0 en pantalla 29 | bool verdadero = true; 30 | cout << "verdadero = " << verdadero << "\n"; 31 | // Ahora deberiamos ver un 1 en pantalla 32 | bool intento = 123; 33 | cout << "intento = " << intento << "\n"; 34 | // Como se dijo arriba, deberiamos ver un 1 en pantalla. Dado que todo numero no 0 35 | // es verdadero 36 | return 0; 37 | } 38 | -------------------------------------------------------------------------------- /01-Cpp/03-conditional.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | int main() { 5 | // En este condicional, se prueba que dos numeros sean iguales 6 | int x = 3; 7 | int y = 2; 8 | if(x == y) { 9 | cout << "Son iguales\n"; 10 | } 11 | 12 | // Se puede escribir lo mismo, pero agregandole un `else` para indicar el caso contrario 13 | if(x == y) { 14 | cout << "Son iguales\n"; 15 | } else { 16 | cout << "No son iguales\n"; 17 | } 18 | 19 | // Si se quiere probar varias opciones, se puede seguir anidando `if` y `else` 20 | // Se verifica que x sea mayor a y 21 | if(x > y) { 22 | cout << "x es mayor que y\n"; 23 | // Si no es mayor, entonces se verifica que sea menor 24 | } else if(x < y) { 25 | cout << "x es menor que y\n"; 26 | // Si tampoco es mayor, entonces significa que son iguales 27 | } else { 28 | cout << "son iguales\n"; 29 | } 30 | return 0; 31 | } 32 | -------------------------------------------------------------------------------- /01-Cpp/04-Loops.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | int main() { 5 | // Existen diferentes tipos de loops 6 | 7 | // While, que significa mientras la condicion sea verdadera, se realizara el 8 | // codigo que se encuentra entre las llaves 9 | int x = 15; 10 | int count = 0; 11 | while(x > 0) { 12 | x -= 2; 13 | count++; 14 | } 15 | cout << count << "\n"; 16 | // Este codigo calcula cuantas veces puedo restar 2 en x 17 | 18 | // Do-while, es casi lo mismo que el while, pero realiza el codigo dentro de 19 | // las llaves al menos 1 vez 20 | int x2 = 0; 21 | int count2 = 0; 22 | do { 23 | x -= 2; 24 | count++; 25 | } while(x > 0); 26 | cout << count << "\n"; 27 | // Este codigo calcula lo mismo que el codigo anterior, pero al usar un 28 | // do-while, si es que `x == 0`, entonces count valdrá 1 de todas formas 29 | 30 | // For, es un ciclo que itera, entonces este a diferencia de los otros dos 31 | // anteriores, se compone de 3 partes: asignacion inicial, condicion e incremento 32 | for(int i = 0; i < 10; i++) { 33 | cout << i << "\n"; 34 | } 35 | // Este codigo mostrara por pantalla todos lo numeros entre 0 y 9. 36 | // Recordar que el orden siempre es: 37 | // 1. Asignacion inicial 38 | // 2. Verifica si la condicion es verdadera 39 | // 3. Si condicion verdadera realiza lo que esta adentro 40 | // 4. Incrementa el valor y velve al paso 2. 41 | return 0; 42 | } 43 | -------------------------------------------------------------------------------- /01-Cpp/05-arrays.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | int main() { 5 | // Los arreglos corresponden a un conjunto de elementos que estan contiguos en memoria 6 | // Solo se puede almacenar un tipo de dato en cada arreglo 7 | // Yo puedo tener arreglos de enteros, flotantes, etc. 8 | // Ademas, los arrreglos tienen tamanio fijo hasta el final del programa 9 | // Si el arreglo tiene tamanio n, entonces las posiciones del arreglo son entre 0 y n - 1 10 | int arr[10]; 11 | // De esta forma yo puedo almacenar cosas en los arreglos. 12 | arr[0] = 1; 13 | arr[1] = 3; 14 | arr[2] = 4; 15 | 16 | // De la misma forma, podemos obtener lo guardado en un arreglo 17 | int x = arr[1]; 18 | cout << "x = " << x << "\n"; 19 | cout << "arr[1] = " << arr[1] << "\n"; 20 | 21 | // Si tu intentas acceder a una posicion que no es del arreglo, pueden suceder cosas no desadas 22 | //cout << arr[12] << "\n"; 23 | 24 | // Tambien podemos hacer eso de los ciclos para recorrer mas comodamente los arreglos 25 | for(int i = 0; i < 10; i++) { 26 | arr[i] = i; 27 | } 28 | 29 | for(int i = 0; i < 10; i++) { 30 | cout << "arr[" << i << "] = " << arr[i] << "\n"; 31 | } 32 | 33 | // Ahora, si ustedes intentan lo siguiente 34 | cout << arr << "\n"; 35 | // No se va a imprimir el arreglo completo, sino que la direccion de memoria de donde esta 36 | // almacenado el comiezno del arreglo 37 | 38 | // Para mostrar que en efecto es memoria contigua haremos uso del operador &, que nos entrega la direccion 39 | // de memoria de una variable 40 | // Dato curioso: &arr[0] == arr 41 | for(int i = 0; i < 10; i++) { 42 | cout << "&arr[" << i << "] = " << &arr[i] << "\n"; 43 | } 44 | 45 | // Dado, que son enteros los saltos en la memoria seran de tamano 4 bytes, si nosotros ponemos otro tipo de dato 46 | // podriamos ver saltos mas grandes o mas pequeño 47 | long long int arr_long[10]; 48 | for(int i = 0; i < 10; i++) { 49 | cout << "&arr_long[" << i << "] = " << &arr_long[i] << "\n"; 50 | } 51 | // Aqui vamos a ver saltos de tamanio 8 bytes 52 | 53 | return 0; 54 | } 55 | -------------------------------------------------------------------------------- /01-Cpp/06-structs.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | // Un struct puede tener diversos campos, de diferentes tipos. 5 | // La idea de utilizar struct es poder representar tipos de datos que consistan 6 | // varios parametros 7 | // Importante decir que los campos de un struct tambien se encuentran en memoria 8 | // contigua 9 | struct arma { 10 | int danio; 11 | char sigla; 12 | float durabilidad; 13 | }; 14 | 15 | int main() { 16 | // ahora puedo declarar variables del tipo del struct 17 | arma var; 18 | // para acceder a los campos de la variable, se utiliza el `.` 19 | var.danio = 2; 20 | var.sigla = 'A'; 21 | var.durabilidad = 23.23; 22 | cout << "var.danio = " << var.danio << "\n"; 23 | cout << "var.sigla = " << var.sigla << "\n"; 24 | cout << "var.durabilidad = " << var.durabilidad << "\n"; 25 | 26 | // cabe destacar que el struct solo define el compartamiento de una variable 27 | // nosotros podemos tener varias variables del mismo struct hasta podemos 28 | // tener un arreglo de struct 29 | arma armas[10]; 30 | for(int i = 0; i < 10; i++) { 31 | armas[i].danio = i; 32 | armas[i].sigla = 'A' + i; 33 | armas[i].durabilidad = i / 10; 34 | } 35 | 36 | for(int i = 0; i < 10; i++) { 37 | cout << "armas[i].danio = " << armas[i].danio << "\n"; 38 | cout << "armas[i].sigla = " << armas[i].sigla << "\n"; 39 | cout << "armas[i].durabilidad = " << armas[i].durabilidad << "\n"; 40 | } 41 | 42 | // Ahora, solo para demostrar que la memoria es contigua dentro de un struct, 43 | // imprimamos las direcciones de memoria correspondientes 44 | for(int i = 0; i < 10; i++) { 45 | cout << " &armas[i].danio = " << &armas[i].danio << "\n"; 46 | // esto de aqui se debe realizar, porque como sabra mas adelante un puntero 47 | // a char es un string para C++, entonces para ver la direccion de memoria debemos 48 | // castearlo a void 49 | cout << "&armas[i].sigla = " << (void*) &armas[i].sigla << "\n"; 50 | cout << "&armas[i].durabilidad = " << &armas[i].durabilidad << "\n"; 51 | } 52 | return 0; 53 | } 54 | -------------------------------------------------------------------------------- /01-Cpp/07-pointers.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | struct test { 5 | int i; 6 | }; 7 | 8 | int main() { 9 | // Puntero es una variable que en vez de almacenar un valor, almacena 10 | // la direccion de memoria en donde se encuentra un valor 11 | // Los punteros siempre apuntan a un tipo de dato, por ejemplo puntero a entero 12 | // puntero a flotante, etc 13 | int* p; 14 | int i = 0; 15 | p = &i; 16 | // Ahora, p esta apuntando a la variable i. Para acceder al valor que apunta p 17 | // se debe hacer uso de `*` 18 | cout << "valor apuntado por p = " << *p << "\n"; 19 | 20 | *p = *p + 2; 21 | cout << "i = " << i << "\n"; 22 | // como p apunta a i, entonces si modificamos lo que apunta p, tambien veremos eso 23 | // en la variable i 24 | 25 | // tambien podemos hacer punteros a struct 26 | test* t; 27 | test var; 28 | t = &var; 29 | // para acceder a los campos del struct se puede hacer de dos formas 30 | (*t).i = 0; 31 | // pero tambien utilizando la flecha 32 | t->i = 2; 33 | 34 | // si van al codigo 5-arrays.cpp, veran que la variable del arreglo es una direccion 35 | // de memoria por lo que podemos igualar esa variable a un punto 36 | int arr[10]; 37 | int* p_arr; 38 | for(p_arr = arr; p_arr < arr + 10; p_arr++) { 39 | *p_arr = 1; 40 | } 41 | 42 | for(p_arr = arr; p_arr < arr + 10; p_arr++) { 43 | cout << "*p_arr (arr[i]) = " << *p_arr << "\n"; 44 | } 45 | return 0; 46 | } 47 | -------------------------------------------------------------------------------- /01-Cpp/08-functions.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | // las funciones en C++ funcionan de la siguiente forma: 5 | // primero hay que escribir el elemento a retornar 6 | // el nombre de la funcion 7 | // sus parametros 8 | // los parametros de esta forma son una copia de los parametros que les pasaron 9 | // por lo tanto si los modificamos dentro de la funcion no se vera afectado 10 | // en el main 11 | int hace_algo(int a, float b) { 12 | a++; 13 | a = a + 2; 14 | if(a > b) { 15 | return a; 16 | } 17 | 18 | return b; 19 | } 20 | 21 | // si es que queremos modificar una variable dentro de una funcion 22 | // tenemos 2 formas: 23 | // 1. por punteros 24 | // 2. por referencia 25 | void swap_punteros(int* a, int* b) { 26 | int aux = *a; 27 | *a = *b; 28 | *b = aux; 29 | } 30 | 31 | void swap_referencias(int &a, int &b) { 32 | int aux = a; 33 | a = b; 34 | b = aux; 35 | } 36 | 37 | // los arreglos se puede pasar por punteros 38 | // para pasar correctamente por parametro, se debe incluir el tamanio del arreglo 39 | void array_con_zeros(int *arr, int n) { 40 | for(int i = 0; i < n; i++) { 41 | arr[i] = 0; 42 | } 43 | } 44 | 45 | // NO SE PUEDEN RETONAR ARREGLOS DE ESTA FORMA 46 | // para eso necesitamos memorai dinamica 47 | // si intentan usar esta funcion, altamente probable que se caiga 48 | int* ret_array() { 49 | int arr[10]; 50 | for(int i = 0; i < 10; i++) { 51 | arr[i] = 0; 52 | } 53 | return arr; 54 | } 55 | 56 | int main() { 57 | int x = 2; 58 | float y = 2.3; 59 | int ret = hace_algo(x, y); 60 | cout << "hace_algo(2, 2.3) " << ret << "\n"; 61 | cout << "x = " << x << "\n"; 62 | cout << "y = " << y << "\n"; 63 | 64 | int var1 = 5; 65 | int var2 = 10; 66 | swap_punteros(&var1, &var2); 67 | swap_referencias(var1, var2); 68 | 69 | int arr[10]; 70 | array_con_zeros(arr, 10); 71 | for(int i = 0; i < 10; i++) { 72 | cout << "arr[i] = " << arr[i] << "\n"; 73 | } 74 | return 0; 75 | } 76 | -------------------------------------------------------------------------------- /01-Cpp/09-dynamic_memory.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | int* ret_array(int t) { 5 | int* arr = new int[t]; 6 | for(int i = 0; i < t; i++) { 7 | arr[i] = i; 8 | } 9 | return arr; 10 | } 11 | 12 | void borrar_array(int* arr) { 13 | delete[] arr; 14 | } 15 | 16 | int main() { 17 | // para hace uso de la memoria del heap, se utiliza new 18 | // se puede pedir memoria para un tipo de dato y cuantos espacios necesitamos 19 | int n = 10; 20 | // el new siempre retorna un arreglo 21 | int* arr = new int[n]; 22 | // la memoria no se elimina sola, por lo tanto existe el delete 23 | // este nos permite liberar la memoria 24 | delete[] arr; 25 | 26 | // ahora que tenemos la memoria dinamica, poder tener funciones que retornen 27 | // arreglos 28 | int* ret = ret_array(n); 29 | for(int i = 0; i < n; i++) { 30 | cout << "ret[" << i << "] = " << ret[i] << "\n"; 31 | } 32 | borrar_array(ret); 33 | return 0; 34 | } 35 | -------------------------------------------------------------------------------- /01-Cpp/10-dynamic_memory_matrix.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | // Para devolver una `matriz` se tiene que retornar 5 | // int**, esto debido a que al un arreglo se puede almacenar en 6 | // int*, entonces para almacenar una `matriz` que corresponde a un puntero 7 | // de donde cada posicion es un puntero a un arreglo. Por lo que, el tipo de 8 | // retorno debe ser int**. 9 | // 10 | // Para realizar esto, primero deberemos pedir memoria para almacenar un arreglo 11 | // de punteros. Luego deberemos ir por cada puntero para pedir memoria para el 12 | // respectivo arreglo. 13 | int** ret_matriz(int f, int c) { 14 | // int** almacena una direccin de memoria de int* 15 | // entonces se debe hacer new de int* 16 | int** m = new int*[f]; 17 | for(int i = 0; i < f; i++) { 18 | // m[i] corresponde a un int*, entonces hay que pedir memoria para enteros 19 | m[i] = new int[c]; 20 | } 21 | 22 | // Rellenemos la matriz con valores para probar 23 | for(int i = 0; i < f; i++) { 24 | for(int j = 0; j < c; j++) { 25 | // se almacena en la posicion j del arreglo i de la matriza i * j 26 | m[i][j] = i * j; 27 | } 28 | } 29 | 30 | return m; 31 | } 32 | 33 | 34 | // Hagamos una funcion que libere la memoria, como no podemos hacer 35 | // delete[] m, porque perderiamos todos los punteros 36 | // 37 | // Deberemos liberar por partes, primero hacer delete por los punteros de 0..f 38 | // y luego el puntero m 39 | void free_matriz(int** m, int f) { 40 | for(int i = 0; i < f; i++) { 41 | delete[] m[i]; 42 | } 43 | delete[] m; 44 | } 45 | 46 | int main() { 47 | int f = 3; 48 | int c = 6; 49 | int** ret = ret_matriz(f, c); 50 | for(int i = 0; i < f; i++) { 51 | for(int j = 0; j < c; j++) { 52 | cout << ret[i][j] << " "; 53 | } 54 | cout << "\n"; 55 | } 56 | 57 | free_matriz(ret, f); 58 | return 0; 59 | } 60 | -------------------------------------------------------------------------------- /01-Cpp/11-strings.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | using namespace std; 5 | 6 | int main() { 7 | // existen dos formas de utilizar strings en C++ 8 | // 1. arreglos de char 9 | // 2. string 10 | 11 | // los arreglos de char cuando almacenan un string 12 | // se agrega al final un `\0`, esto debido que es la forma de C++ 13 | // para saber donde termina el string 14 | char fecha[11] = "1999-02-12"; 15 | cout << fecha << "\n"; 16 | 17 | // los arreglos de char pueden tener mayor del string que puede almacenar 18 | char arr[123]; 19 | // esta funcion permite copiar un arreglo de char a otro 20 | // igualar directamente no se pueden hacer, porque son punteros 21 | strcpy(arr, fecha); 22 | cout << arr << "\n"; 23 | 24 | // aqui se observara que el largo del string no corresponde al largo del arreglo 25 | cout << "largo del string " << strlen(arr) << "\n"; 26 | 27 | // concatena el string de fecha en el arr 28 | strcat(arr, fecha); 29 | cout << arr << "\n"; 30 | 31 | // para poder comprar dos string en arreglos de char, se debe hacer uso de 32 | // strcmp 33 | if(strcmp(arr, fecha) == 0) { 34 | cout << "Son iguales\n"; 35 | } else { 36 | cout << "No son iguales\n"; 37 | } 38 | 39 | char* ch = strchr(arr, '-'); 40 | cout << *ch << "\n"; 41 | 42 | // string es un objeto de C++ que permite manejar con mayor flexibilidad los 43 | // strings 44 | string s = "hola soy un string"; 45 | 46 | // de esta forma podemos juntar dos strings 47 | cout << s + s << "\n"; 48 | // de esta forma podemos saber el largo de un string 49 | cout << s.length() << "\n"; 50 | 51 | if(s.empty()) { 52 | cout << "s es un string vacio\n"; 53 | } else { 54 | cout << "s no es un string vacio\n"; 55 | } 56 | 57 | // asi podemos acceder/modificar un caracter de un string 58 | s[2] = '2'; 59 | cout << s << "\n"; 60 | 61 | string s2 = "hola soy otro string"; 62 | if(s2 == s) { 63 | cout << "Son iguales\n"; 64 | } else { 65 | cout << "No son iguales\n"; 66 | } 67 | 68 | // gracias a string podemos buscar no solo caracteres sino que tambien 69 | // otro string dentro 70 | // si no se encuentra el caracter o el string retorna el maximo largo de un string 71 | cout << "Posicion donde se encuentra una s " << s.find('s') << "\n"; 72 | cout << "Posicion donde comienza `soy` en el string s " << s.find("soy") << "\n"; 73 | return 0; 74 | } 75 | -------------------------------------------------------------------------------- /01-Cpp/12-text_files.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; 4 | 5 | int main() { 6 | // archivo de entraga (lectura) 7 | ifstream fin; 8 | // archivo de salida (escritura) 9 | ofstream fout; 10 | // archivo tanto entrada como salida 11 | fstream file; 12 | 13 | // ambas formas son equivalentes, puesto que `fin` es un archivo solo de lectura 14 | // y `file` no se sabe, entonces al usar `ios::in` se sabe que `file` es de lectura 15 | fin.open("archivo.txt"); 16 | fin.close(); 17 | file.open("archivo.txt", ios::in); 18 | file.close(); 19 | 20 | file.open("archivo.txt", ios::in); 21 | // si el archivo de lectura no se pudo abrir porque no existe o alguna otra razon 22 | // file.is_open() retornara falso 23 | if(!file.is_open()) { 24 | cout << "Error al abrir el archivo\n"; 25 | exit(1); 26 | } else { 27 | cout << "El archivo se abrio correctamente\n"; 28 | } 29 | 30 | // para leer del archivo, primero se debe saber que esta escrito, sino no hay forma de leer 31 | // el archivo 32 | // por ejemplo digamos que en archivo.txt esta escrito `2 hola 3` 33 | // nosotros podemos leerlo de la siguiente forma 34 | int x; 35 | file >> x; 36 | cout << x << "\n"; 37 | 38 | string s; 39 | file >> s; 40 | cout << s << "\n"; 41 | 42 | file >> x; 43 | cout << x << "\n"; 44 | 45 | file.close(); 46 | 47 | // ahora abramos un archivo para escribir en el 48 | file.open("escribir.txt", ios::in); 49 | // si el archivo no existe C++ crea un archivo vacio 50 | // si el archivo existe C++ borra todo el contenido del archivo 51 | 52 | // para escribir en el archivo es igual que usar `cout`, pero dentro del archivo 53 | file << "x = " << x << "\n"; 54 | file << "s = " << s << "\n"; 55 | 56 | file.close(); 57 | 58 | 59 | // DATO FREAK 60 | // si el `cout` es para imprimir por consola 61 | // el `cin` es para leer por consola 62 | 63 | int x2; 64 | cin >> x2; // de esta forma leeremos un entero 65 | 66 | string s2; 67 | cin >> s2; 68 | 69 | cout << x2 << " " << s2 << "\n"; 70 | // la lectura tanto en ambos casos ignora los espacios y saltos de linea 71 | // cuando por ejemplo queremos leer una variable de entero, busca el primer elemento 72 | // que no sea un espacio y lo intenta almacenar en la variable 73 | return 0; 74 | } 75 | -------------------------------------------------------------------------------- /01-Cpp/13-binary_files.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; 4 | 5 | int main() { 6 | // los archivos binarios son distintos a los archivos de texto, 7 | // puesto lo que se almacena es la informacion en binario. No es tan facil 8 | // de leer esos archivos al ojo humano 9 | 10 | // los archivos binarios usan el mismo tipo de variable que los otros archivos 11 | // pero cambia la forma de escribir y leer 12 | fstream file; 13 | file.open("binario.dat", ios::binary | ios::out); 14 | 15 | // si quiero escribir un entero en el archivo, debo indicarle la direccion de memoria 16 | // y el tamano de la cosa que quiero escribir 17 | int x = 3; 18 | 19 | file.write((char*) &x, sizeof(int)); 20 | 21 | // de esta forma escribi un entero en binario, luego si es que escribo otra cosa 22 | // ira pegada al entero 23 | 24 | float y = 2; 25 | file.write((char*) &y, sizeof(float)); 26 | 27 | file.close(); 28 | 29 | // Ahora, para leer del archivo binario, primero se debe abrir en modo lectura 30 | file.open("binario.dat", ios::binary | ios::in); 31 | 32 | int x2; 33 | float y2; 34 | 35 | // leer es la misma que escribir, pero utilizando es read 36 | file.read((char*) &x2, sizeof(int)); 37 | file.read((char*) &y2, sizeof(float)); 38 | 39 | file.close(); 40 | 41 | 42 | cout << x2 << " " << y2 << "\n"; 43 | return 0; 44 | } 45 | -------------------------------------------------------------------------------- /01-Cpp/14-binary_files_struct_arrays.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | using namespace std; 5 | 6 | struct persona { 7 | int edad; 8 | float vida; 9 | }; 10 | 11 | int main() { 12 | fstream file; 13 | file.open("struct.dat", ios::out | ios::binary); 14 | 15 | // Uno pensaria que para guardar un struct en un archivo binario, deberia 16 | // ir campo por campo y luego para leer debemos leer campo por campo 17 | // 18 | // Pero, no! podemos guardarlo directamente debido a que como guardamos binarios 19 | // y la memoria en los struct es contigua, podemos hacerlo directamente 20 | // 21 | // OJO!: la otra forma tambien esta bien, pero la otra es as rapida 22 | 23 | persona p; 24 | p.edad = 12; 25 | p.vida = 32.23; 26 | 27 | // Escribimos de la misma forma, pero sizeof del struct correspondiente 28 | file.write((char*)&p, sizeof(persona)); 29 | 30 | file.close(); 31 | 32 | file.open("struct.dat", ios::in | ios::binary); 33 | 34 | persona p2; 35 | file.read((char*)&p2, sizeof(persona)); 36 | 37 | cout << p.edad << " " << p.vida << "\n"; 38 | file.close(); 39 | 40 | // Esto mismo podemos hacerlo con los arreglos, pero con una pequena diferencia 41 | // en el sizeof se entrega el espacio en bytes de 1 cosa, pero un arreglo almacena 42 | // n cosas, entonces se debe multiplicar el sizeof por n 43 | 44 | int n = 3; 45 | persona* arr = new persona[n]; 46 | 47 | file.open("array.dat", ios::out | ios::binary); 48 | 49 | // se va a rellenar todo a mano, porque sino es poco customizable 50 | arr[0].edad = 12; 51 | arr[0].vida = 12.123; 52 | 53 | arr[1].edad = 10; 54 | arr[1].vida = 15.123; 55 | 56 | arr[2].edad = 1212; 57 | arr[2].vida = 0.12312; 58 | 59 | // primero se debe guardar la cantidad de cosas a guardar, porque sino 60 | // en otro programa al menos que siempre sepamos que es un arreglo de tamanio 61 | // 3, no podemos adivinar cuantas cosas estan escritas 62 | file.write((char*)&n, sizeof(int)); 63 | // ahora guardamos el arreglo 64 | file.write((char*)arr, sizeof(persona) * n); 65 | 66 | delete[] arr; 67 | file.close(); 68 | 69 | // Ahora intentemos leerlo 70 | file.open("array.dat", ios::in | ios::binary); 71 | 72 | int n2; 73 | // primero leemos la cantidad de elementos en el arreglo 74 | file.read((char*)&n2, sizeof(int)); 75 | 76 | persona* arr2 = new persona[n2]; 77 | file.read((char*)arr2, sizeof(persona) * n2); 78 | 79 | cout << n2 << "\n"; 80 | // veamos si leyo bien 81 | for(int i = 0; i < n2; i++) { 82 | cout << arr2[i].edad << " " << arr2[i].vida << "\n"; 83 | } 84 | 85 | delete[] arr2; 86 | file.close(); 87 | 88 | return 0; 89 | } 90 | -------------------------------------------------------------------------------- /01-Cpp/archivo.txt: -------------------------------------------------------------------------------- 1 | 2 hola 3 2 | -------------------------------------------------------------------------------- /01-Cpp/array.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yhatoh/INF134-Data_Structures/a6e139e7ffce6b4c8c52288ef3a19225968eec06/01-Cpp/array.dat -------------------------------------------------------------------------------- /01-Cpp/struct.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yhatoh/INF134-Data_Structures/a6e139e7ffce6b4c8c52288ef3a19225968eec06/01-Cpp/struct.dat -------------------------------------------------------------------------------- /02-TDA/1-example.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; 4 | 5 | // Gracias a la palabra class, nosotros podemos crear un tipo de dato abstracto 6 | // la idea es que puedan representar a traves de un conjunto de datos y operaciones 7 | // una cosa sea de la vida real o algo inventado 8 | // La idea es que este encapsule el comportamiento y solo se piense en que esta 9 | // hecho y no el como esta hecho 10 | class Personaje { 11 | // Estos son los campos privados, solo la clase puede acceder directamente 12 | // los programadores no 13 | private: 14 | string name; 15 | int vida; 16 | float danio; 17 | int posicion; 18 | bool esta_vivo; 19 | // Estos son los elementos publicos, todos pueden acceder a estos 20 | public: 21 | // Estos corresponden a los contructores 22 | // * Primero tenemos el contructor vacio, significa que no recibe parametros 23 | // al momento que declaramos una variable 24 | // * Segundo tenemos otro constructo que recibe un string como parametro 25 | // al momento de declarar la variable 26 | // Un TDA puede tener diferentes constructores con tal que tenga distintos 27 | // parametros basta 28 | // El constructor la idea es setear los campos de manera default 29 | Personaje(); 30 | Personaje(string name_); 31 | // Este es el destructor, este llama al momento que una variable vaya a morir 32 | // esto nos va a ser util cuando usemo memoria dinamica 33 | ~Personaje(); 34 | 35 | // Ahora vamos a declarar ciertas operaciones que podria tener el personaje 36 | int hacer_danio(); 37 | void recibir_danio(int danio_); 38 | void hablar(int op); 39 | void avanzar(); 40 | void retroceder(); 41 | 42 | // Como los campos estan en el privado, si es que queremos que el usuario 43 | // acceda los campos, deben ser a traves de operaciones, esto se atravese de 44 | // algo que se conoce como getters 45 | // Lo mismo si es que nosotros queremos modificar los campos, esto se atraves 46 | // de operaciones que se llaman setters 47 | // 48 | // Para este caso particular no quiero que el usuario modifique los campos, 49 | // por lo que no crearemos setters; 50 | string get_name(); 51 | int get_vida(); 52 | float get_danio(); 53 | int get_posicion(); 54 | bool get_esta_vivo(); 55 | }; 56 | 57 | // Vamos a hacer que el constructor vacio, ponga solo los vamores default 58 | Personaje::Personaje() { 59 | name = "default"; 60 | vida = 10; 61 | danio = 5.123; 62 | posicion = 0; 63 | esta_vivo = true; 64 | } 65 | 66 | // Como este constructor tiene un parametro, corresponde al nombre del personaje 67 | Personaje::Personaje(string name_) { 68 | name = name_; 69 | vida = 10; 70 | danio = 5.123; 71 | posicion = 0; 72 | esta_vivo = true; 73 | } 74 | 75 | // esta es una funcion que no hace nada 76 | Personaje::~Personaje() {} 77 | 78 | int Personaje::hacer_danio() { 79 | // si en algun punto alquien quisiera llegar a cambiar el como hacer danio, 80 | // solo debe cambiar esta funcion, en el main jamás veremos el cambio 81 | // return danio * posicion; 82 | return danio * vida; 83 | } 84 | 85 | // si el danio lo deja con vida negativa o zero, entonces el personaje muere 86 | void Personaje::recibir_danio(int danio_) { 87 | vida -= danio_; 88 | if(vida <= 0) { 89 | esta_vivo = false; 90 | vida = 0; 91 | } 92 | } 93 | 94 | // Dire tres opciones el valor de `op` 95 | void Personaje::hablar(int op) { 96 | if(op == 1) { 97 | cout << name << ": " << " Hola!\n"; 98 | } else if(op == 2) { 99 | cout << name << ": " << " Muerte\n"; 100 | } else { 101 | cout << name << ": " << " ...\n"; 102 | } 103 | } 104 | 105 | void Personaje::avanzar() { 106 | posicion++; 107 | } 108 | 109 | void Personaje::retroceder() { 110 | posicion--; 111 | if(posicion <= 0) { 112 | posicion = 0; 113 | } 114 | } 115 | 116 | string Personaje::get_name() { return name; } 117 | int Personaje::get_vida() { return vida; } 118 | float Personaje::get_danio() { return danio; } 119 | int Personaje::get_posicion() { return posicion; } 120 | bool Personaje::get_esta_vivo() { return esta_vivo; } 121 | 122 | int main() { 123 | // Declaro una variable usando el constructor vacio 124 | Personaje p; 125 | cout << p.get_name() << "\n"; 126 | // Ahora declaro otra variable usando el constructo que recibe el string 127 | Personaje p2("Thor El PepeitosDestructor"); 128 | 129 | // Ahora podemos usar las operaciones de nuestros personaje 130 | cout << p.hacer_danio() << "\n"; 131 | 132 | p.avanzar(); p.avanzar(); p.avanzar(); 133 | cout << p.get_posicion() << "\n"; 134 | p.retroceder(); p.retroceder(); 135 | p.retroceder(); p.retroceder(); 136 | cout << p.get_posicion() << "\n"; 137 | // Cada campo de la clase es `unico` de cada variable, entonces 138 | // al verse modificado p, no afecto a p2 139 | cout << p2.get_posicion() << "\n"; 140 | 141 | p2.recibir_danio(100); 142 | cout << p2.get_esta_vivo() << "\n"; 143 | return 0; 144 | } 145 | -------------------------------------------------------------------------------- /02-TDA/2-rational.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | // Vamos a crear una clase Racional, que nos servira para ilustrar respecto al 5 | // uso de los TDA y de como para el programador no deberia importar la implementacion 6 | // solo que funcione 7 | // 8 | // Descomentar las cosas un arreglo, para que vean que no tuve que modificar nada en el main 9 | // solo en las funciones del TDA 10 | class Racional { 11 | private: 12 | // int frac[2]; 13 | int _den; 14 | int _num; 15 | public: 16 | Racional(); 17 | Racional(int num, int den); 18 | // vamos a crear una funcion que sirva para hacer `=` 19 | void igual(Racional r); 20 | // hagamos la operacion multiplicar racionales 21 | // o sea que haga la operacion r1 * r2 22 | // r1 no se haga por parametro, puesto que cuando uno hace 23 | // r1.multiplicar(r2), los campos de r1 ya se encuentran desde la funcion 24 | Racional multiplicar(Racional r2); 25 | int get_num(); 26 | int get_den(); 27 | void print(); 28 | }; 29 | 30 | Racional::Racional() {} 31 | Racional::Racional(int num, int den) { 32 | // frac[0] = num; 33 | // frac[1] = den; 34 | _num = num; 35 | _den = den; 36 | } 37 | 38 | void Racional::igual(Racional r) { 39 | // frac[0] = r.get_num(); 40 | // frac[1] = r.get_den(); 41 | _num = r.get_num(); 42 | _den = r.get_den(); 43 | } 44 | 45 | Racional Racional::multiplicar(Racional r2) { 46 | // Racional r3(frac[0] * r2.get_num(), 47 | // frac[1] * r2.get_den()); 48 | Racional r3(_num * r2.get_num(), 49 | _den * r2.get_den()); 50 | return r3; 51 | } 52 | 53 | int Racional::get_num() { 54 | // return frac[0]; 55 | return _num; 56 | } 57 | int Racional::get_den() { 58 | // return frac[1]; 59 | return _den; 60 | } 61 | 62 | void Racional::print() { 63 | cout << get_num() << " / " << get_den() << "\n"; 64 | } 65 | 66 | int main() { 67 | Racional r1(2, 3); 68 | Racional r2(4, 5); 69 | Racional r3; 70 | // En este caso r1.multiplicar(r2) 71 | // _num seria igual a 2 y r2.get_num() seria igual a 4 72 | // _den seria igual a 3 y r2.get_den() seria igual a 5 73 | r3.igual(r1.multiplicar(r2)); 74 | // En este caso r2.multiplicar(r1) 75 | // _num seria igual a 4 y r2.get_num() seria igual a 2 76 | // _den seria igual a 5 y r2.get_den() seria igual a 4 77 | r3.igual(r2.multiplicar(r1)); 78 | r3.print(); 79 | 80 | return 0; 81 | } 82 | -------------------------------------------------------------------------------- /03-Exercise/caracteres_distintos/Exer.cpp: -------------------------------------------------------------------------------- 1 | class Texto { 2 | private: 3 | char lineas[1000][1000]; 4 | int cant_lineas; 5 | public: 6 | // te entrega la cantidad de lineas del texto 7 | int get_cant_lineas(); 8 | // te entrega la linea `i` del texto 9 | char* get_linea(int i); 10 | // te entrega el caracter `j` de la linea `i` del texto 11 | char* get_char_linea(int i, int j); 12 | }; 13 | 14 | // Dado el TDA presentado, escriba una funcion `comparar` que reciba dos variables de tipo texto, 15 | // que retorna un arreglo de enteros donde en la posicion `i` se almacena la cantidad de caracteres 16 | // distintos de la linea `i` entre los dos textos. 17 | 18 | int* comparar(Texto t1, Texto t2) { 19 | // su codigo 20 | } 21 | -------------------------------------------------------------------------------- /03-Exercise/caracteres_distintos/Solu.cpp: -------------------------------------------------------------------------------- 1 | class Texto { 2 | private: 3 | char lineas[1000][1000]; 4 | int cant_lineas; 5 | public: 6 | // te entrega la cantidad de lineas del texto 7 | int get_cant_lineas(); 8 | // te entrega la linea `i` del texto 9 | char* get_linea(int i); 10 | // te entrega el caracter `j` de la linea `i` del texto 11 | char* get_char_linea(int i, int j); 12 | }; 13 | 14 | // Dado el TDA presentado, escriba una funcion `comparar` que reciba dos variables de tipo texto, 15 | // que retorna un arreglo de enteros donde en la posicion `i` se almacena la cantidad de caracteres 16 | // distintos de la linea `i` entre los dos textos. 17 | 18 | // nunca olvidar el tamanio del arreglo utilizando un parametro por referencia 19 | int* comparar(Texto t1, Texto t2, int &t) { 20 | // se obtendra quien tiene la mas lineas y el que tiene las menos lineas 21 | int max_lineas = max(t1.get_cant_lineas(), t2.get_cant_lineas()); 22 | int min_lineas = min(t1.get_cant_lineas(), t2.get_cant_lineas()); 23 | 24 | // crearemos un arreglo de tamanio `max_lineas` puesto que esa es la mayor cantidad de lineas a comparar 25 | int* res = new int[max_lineas]; 26 | t = max_lineas; 27 | 28 | // Ahora solo nos importa comparar las primeras 0 hasta min_lineas - 1. puesto que esas son las unicas lineas 29 | // a comparar 30 | 31 | for(int i = 0; i < min_lineas; i++) { 32 | // obtenemos la linea `i` de ambos textos 33 | char* l_t1 = t1.get_linea(i); 34 | char* l_t2 = t2.get_linea(i); 35 | 36 | // se obtiene el largo mas grande y el largo mas chico 37 | int l_chica = min(strlen(l_t1), strlen(l_t2)); 38 | int l_grande = max(strlen(l_t1), strlen(l_t2)); 39 | 40 | // ahora recorreremos las posiciones entre 0 hasta l_chica - 1 y ver cuales son los caracteres distintos 41 | // se crea una variable para almacenar la cantidad de caracteres distintos 42 | int distintos = 0; 43 | for(int j = 0; j < l_chica; j++) { 44 | if(l_t1[j] != l_t2[j]) { 45 | distintos++; 46 | } 47 | } 48 | // se suma todos los caracteres que posee una linea por ser mas grande que la otra 49 | distintos += l_grande - l_chica; 50 | res[i] = distintos; 51 | } 52 | 53 | // Ahora se suma todos los caracteres de las lineas que tiene un texto y que no tiene el otro 54 | if(t1.get_cant_lineas() == max_lineas) { 55 | // la ultima linea comparada fue la linea en la posicion `min_lineas - 1` 56 | for(int i = min_lineas; i < max_lineas; i++) { 57 | // aqui la cantidad de caracteres distintos es el largo de la linea 58 | res[i] = strlen(t1.get_linea(i)); 59 | } 60 | } else { 61 | for(int i = min_lineas; i < max_lineas; i++) { 62 | // aqui la cantidad de caracteres distintos es el largo de la linea 63 | res[i] = strlen(t2.get_linea(i)); 64 | } 65 | } 66 | 67 | return res; 68 | } 69 | -------------------------------------------------------------------------------- /03-Exercise/estudiantes_aprobados/Exer.cpp: -------------------------------------------------------------------------------- 1 | struct Estudiante { 2 | char rut[11]; 3 | int c1; 4 | int c2; 5 | int c3; 6 | }; 7 | 8 | // Enunciado 9 | // Escriba una funcion llamada `aprobados` que reciba el nombre de un archivo binario 10 | // que contiene un entero `n`, luego le siguen `n` structs `Estudiante`. Su función debe 11 | // retornar un arreglo de `Estudiante`, que contenga a todos los estudiantes que aprobaron 12 | // el curso. Para saber si estudiante aprobo su promedio de los certamenes debe ser mayor o igual 13 | // a 54.45 14 | 15 | Estudiante* aprobados(string nombre_archivo) { 16 | // tu codigo 17 | } 18 | -------------------------------------------------------------------------------- /03-Exercise/estudiantes_aprobados/Solu.cpp: -------------------------------------------------------------------------------- 1 | struct Estudiante { 2 | char rut[11]; 3 | int c1; 4 | int c2; 5 | int c3; 6 | }; 7 | 8 | // Enunciado 9 | // Escriba una funcion llamada `aprobados` que reciba el nombre de un archivo binario 10 | // que contiene un entero `n`, luego le siguen `n` structs `Estudiante`. Su función debe 11 | // retornar un arreglo de `Estudiante`, que contenga a todos los estudiantes que aprobaron 12 | // el curso. Para saber si estudiante aprobo su promedio de los certamenes debe ser mayor o igual 13 | // a 54.45 14 | 15 | // primer detalle importante agregar el parametro que indique el tamaño del arreglo 16 | Estudiante* aprobados(string nombre_archivo, int &t) { 17 | fstream file; 18 | // se abre el archivo en modo lectura y en modo binario 19 | file.open(nombre_arch, ios::in | ios::binary); 20 | 21 | // se lee el entero `n` descrito 22 | int n; 23 | file.read((char*)&n, sizeof(int)); 24 | 25 | // se pide memoria para almacenar `n` `Estudiante` 26 | Estudiante *arr = new Estudiante[n]; 27 | // se lee los `n` `Estudiantes` 28 | file.read((char*)arr, sizeof(Estudiante) * n); 29 | 30 | // recordar cerrar el archivo 31 | file.close(); 32 | 33 | // creo un arreglo del tamanio maximo posible 34 | Estudiante *res = new Estudiante[n]; 35 | 36 | // creo una variable count, para guardar los estuidantes de mantera contigua 37 | int count = 0; 38 | for(int i = 0; i < n; i++) { 39 | int num = arr[i].c1 + arr[i].c2 + arr[i].c3; 40 | float promedio = num / 3.0; 41 | if(promedio >= 54.45) { 42 | res[count] = arr[i]; 43 | count++; 44 | } 45 | } 46 | 47 | // modificop el valor de t 48 | t = count; 49 | // creo un arreglo mas chico para almacenar la respuesta real 50 | Estudiante *ret = new Estudiante[count]; 51 | for(int i = 0; i < count; i++) { 52 | ret[i] = res[i]; 53 | } 54 | 55 | // se elimina la memoria dinamica pedida y que no es util 56 | delete[] arr; 57 | delete[] res; 58 | 59 | return ret; 60 | 61 | } 62 | -------------------------------------------------------------------------------- /04-EDDLineales/Browser_Chino.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "tLista.hpp" 3 | 4 | using namespace std; 5 | 6 | /* Enunciado 7 | * 8 | * Existe un Browser Chino llamado Adventurer Explorer, este navegador debe tener 9 | * las siguientes funcionalidades: 10 | * - Recibir Link: debe recibir link y agregarlo al final del historial, se debe eliminar todo lo que este adelante 11 | * en caso de que no este al final 12 | * - Volver Atras: debe poder volver atras en el historial 13 | * - Volver Adelante: debe volver hacia adelante en el historial 14 | * - Moverse hasta una posicion `i`: debe moverse a la posición `i`del historial 15 | * y borrar todo lo que este adelante de ese link 16 | * - Mostrar link actual 17 | * 18 | * Para resolver esto, haremos uso del TDA de Listas y vamos a almacenar char* dentro de la lista 19 | * 20 | * Para el programa haremos el siguiente mapeo de opciones: 21 | * - op == 1, es la opcion recibir link 22 | * - op == 2, es la opcion de volver atras 23 | * - op == 3, es la opcion de volver adelante 24 | * - op == 4, es la opcion de moverse a una posicion particular 25 | * - op == 5, es la opcion de mostrar el link 26 | * - op == 6, es una opcion extra para terminar el programa 27 | * 28 | * ¿Qué lista usar? 29 | * Se debe usar lista basada en arreglos, esto se debe principalmente por la opcion numero 2 y 4 30 | * la cual nos obliga a movernos a una opcion particular, en esta implementacion seria facil moverse 31 | * porque acceso al `prev` de un eelemento tiene complejidad O(1). En cambio, ena lista enlazada tiene 32 | * complejidad O(n) 33 | * 34 | * Este codigo esta implementado de tal forma que no tendremos que modificar NADA de la implementación de Lista 35 | * para agregar los arreglos de char, PERO importante recalcar que la memoria se debe borrar en el main 36 | * o sea tengan cuidado 37 | */ 38 | int main() { 39 | // Leemos la primera opcion por la consola 40 | int op; 41 | cin >> op; 42 | tLista list; 43 | while(op != 6) { 44 | if(op == 1) { 45 | // declaramos una variable de tipo char* para almacenar el link que se va a recibir 46 | char str[STRING_SIZE]; 47 | cin >> str; 48 | 49 | // este pedazo de codigo nos sirve porque si agregamos algo al final y no estamos en la pos final 50 | // debemos borrar todo lo que este al frente 51 | int i = list.curr_pos(); 52 | list.move_to_end(); 53 | list.prev(); 54 | while(list.curr_pos() > (unsigned int) i) { 55 | t_elem_list aux = list.erase(); 56 | // eliminamos la memoria puesto que el erase no hace el trabajo por nosotros 57 | // esto es para no tener que modificar la implementacion del erase, puesto que es algo particular 58 | // del tipo del elemento 59 | delete[] aux; 60 | list.prev(); 61 | } 62 | // se pide memoria para almacenar el string dentro de la Lista 63 | char* to_append = new char[STRING_SIZE]; 64 | strcpy(to_append, str); 65 | // realizamos append 66 | list.append(to_append); 67 | // despues de hacer append, movemos el curr si es la lista no es de tamanio 1 68 | // esto porque el curr no se mueve con el append y nosotros siempre queremos ver el ultimo ingresado 69 | if(list.length() > 1) { 70 | list.next(); 71 | } 72 | } else if(op == 2) { 73 | // gracias a que tenemos prev es directo 74 | list.prev(); 75 | } else if(op == 3) { 76 | // debemos checkear si es que no estamos en el ultimo elemento, para no movernos al end 77 | if(list.curr_pos() < list.length() - 1) { 78 | list.next(); 79 | } 80 | } else if(op == 4) { 81 | // recibimos la posicion que nos queremos mover 82 | int i; 83 | cin >> i; 84 | // nos movemos al final y hacemos prev para posicionarnos en el ultimo elemento 85 | list.move_to_end(); 86 | list.prev(); 87 | // eliminamos todo el historia que haya entre el ultimo elemento y la posicion que nos vamos a mover 88 | // todo esto por la descripcion del problema 89 | while(list.curr_pos() > (unsigned int) i) { 90 | t_elem_list aux = list.erase(); 91 | delete[] aux; 92 | list.prev(); 93 | } 94 | } else if(op == 5) { 95 | // se obtiene el link actual en que uno esta 96 | cout << list.get_value() << "\n"; 97 | } 98 | cin >> op; 99 | } 100 | 101 | // como no modificados el TDA para eliminar la memoria, tenemos que acordarnos de borrar todos los nodos que 102 | // queden con memoria flotando que requiera ser eliminada antes de llamar al destructor 103 | for(list.move_to_start(); (unsigned int) list.curr_pos() < list.length(); list.next()) { 104 | t_elem_list aux = list.get_value(); 105 | delete[] aux; 106 | } 107 | return 0; 108 | } 109 | -------------------------------------------------------------------------------- /04-EDDLineales/Cajeros.cpp: -------------------------------------------------------------------------------- 1 | /* Enunciado 2 | * 3 | * Se tiene una fila de personas con un carrito de compras. Las personas quieren pagas sus compras 4 | * cada persona tiene un tiempo `t` para ser atendidos por un cajero. Existen tres cajeros. 5 | * ¿Quieres saber cuanto es el tiempo mínimo para que todas las personas puedan pagar sus compras? 6 | * 7 | * Ejemplo: 8 | * p1 se demora 3 segundos 9 | * p2 se demora 5 segundos 10 | * p3 se demora 4 segundos 11 | * p4 se demora 2 segundos 12 | * p5 se demora 2 segundos 13 | * p6 se demora 1 segundos 14 | * 15 | * La respuesta sería: 6 segundos el tiempo en atender todos 16 | * 17 | * Solución: 18 | * Como los tres cajeros están libres, mandaremos a las tres primeras personas en la fila a cada 19 | * cajero. Luego, la siguiente persona será el que tenga el cajero con menor tiempo acumulado. 20 | * 21 | * Por ejemplo: 22 | * C1 = p1 23 | * C2 = p2 24 | * C3 = p3 25 | * 26 | * Luego, como p1 es menor que todos entonces p4 lo mandamos al cajero C1 27 | * 28 | * Dando, 29 | * C1 = p1 + p4 30 | * C2 = p2 31 | * C3 = p3 32 | * 33 | * Luego, p5 lo mandamos al cajero C3 34 | * 35 | * Dando, 36 | * C1 = p1 + p4 37 | * C2 = p2 38 | * C3 = p3 + p5 39 | * 40 | * Finalmente, p6 podría ser enviado tanto al cajero C1 como C2 41 | * 42 | * Dando 43 | * C1 = p1 + p4 44 | * C2 = p2 + p6 45 | * C3 = p3 + p5 46 | * 47 | * Por lo tanto el tiempo mínimo es la suma máxima 48 | */ 49 | 50 | int tiempo_minimo(Queue personas) { 51 | // estado inicial de los cajeros 52 | int C1 = 0; 53 | int C2 = 0; 54 | int C3 = 0; 55 | 56 | while(personas.size() > 0) { 57 | if(C1 < C2 && C1 < C3) { 58 | C1 += personas.front(); 59 | } else if(C2 < C1 && C2 < C3) { 60 | C2 += personas.front(); 61 | } else { 62 | C3 += personas.front(); 63 | } 64 | personas.dequeue(); 65 | } 66 | return max(C1, max(C2, C3)); 67 | } 68 | -------------------------------------------------------------------------------- /04-EDDLineales/Parentesis_Balanceado.cpp: -------------------------------------------------------------------------------- 1 | /* Enunciado 2 | * 3 | * Se tiene un string con puros simbolois `(` y `)`, se dice que el string esta balanceado 4 | * si es todo abre parentesis tiene su respectio cierra parentesis y viceversa. 5 | * 6 | * Ejemplos buenos 7 | * ((())()) este string esta balanceado puesto que todo abre parentesis tiene su cierra parentesis 8 | * ()()()() este igual 9 | * Ejemplos malos 10 | * ()), este string no esta balanceado puesto que el segundo cierra parentesis no tiene con quien cerrarse 11 | * ((), este string no esta balanceado puesto que el primer abre parentesis no tiene su respectivo cierra parentesis 12 | * )(, pueden deducir porque esta malo 13 | * 14 | * Solucion: 15 | * ¡Pilas! 16 | * Si se ve bien los strings, se junta el ultimo abre parentesis con el primer cierra parentesis que se encuentre. 17 | * Por lo tanto, por cada abre parentesis que veamos lo agregaremos a la pila. Si vemos un cierra parentesis haremos el siguiente 18 | * checkeo: 19 | * - Si en la pila no hay nada, entonces esta malo porque no hay un abre parentesis con quien cerrarse 20 | * - Si la pila no esta vacia, entonces sacamos el abre parentesis que esta en el tope, puesto que lo cerrarremos con ese cierra parentesis 21 | * Si terminamos de revisar el string y quedan cosas en la pila, significa que faltaron parentesis por revisar. Si esta vacia, ganamos 22 | */ 23 | bool check(String s) { 24 | // Creamos una variable tipo pila 25 | tPila pila; 26 | // recorreremos el string desde la posicion 0 hasta el final 27 | for(int i = 0; i < s.length(); i++) { 28 | // Si es un abre parentesis realizamos push 29 | if(s[i] == '(') pila.push('('); 30 | // Si es un cierra parentesis 31 | else { 32 | // Si hay cosas en la pila, sacamos el ultimo abre parentesis 33 | if(pila.size() > 0) pila.pop(); 34 | // Si no hay nada retornamos falso 35 | else return false; 36 | } 37 | } 38 | // Si al terminar el for la pila no esta vacia, entonces retornamos falso 39 | if(pila.size() > 0) return false; 40 | // Si esta vacia retornamos verdadero 41 | else return true; 42 | } 43 | -------------------------------------------------------------------------------- /06-Hashing/hashing_attempt.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace std; 5 | 6 | #define M 100 7 | #define VACIA -1 8 | #define LIBERADA -2 9 | #define R 2 10 | 11 | typedef int tipoClave; 12 | 13 | struct tipoInfo { 14 | int v; 15 | }; 16 | 17 | tipoInfo VALORINVALIDO; 18 | 19 | struct ranura { 20 | tipoClave clave; 21 | tipoInfo info; 22 | }; 23 | 24 | ranura HT[M]; 25 | 26 | int log_10(int num) { 27 | int cont = 0; 28 | while(num >= 10) { 29 | num /= 10; 30 | cont++; 31 | } 32 | return cont; 33 | } 34 | 35 | int h(int k) { 36 | int cuadrado = k * k; 37 | int largo = log_10(cuadrado) + 1; 38 | 39 | if(largo <= R) { 40 | return cuadrado; 41 | } 42 | 43 | int cuantos_borrar = ceil((largo - R) / 2.0); 44 | for(int i = 0; i < cuantos_borrar; i++) { 45 | cuadrado /= 10; 46 | } 47 | 48 | return cuadrado % 100; 49 | } 50 | 51 | int p(tipoClave k, int i) { 52 | return 47*i*i + 73*i + 79; 53 | } 54 | 55 | int hashInsert(ranura HT[], tipoClave k, tipoInfo I) { 56 | int inicio, i; 57 | int pos = inicio = h(k); 58 | for (i = 1; HT[pos].clave != VACIA && HT[pos].clave != k; i++) 59 | pos = (inicio + p(k, i)) % M; // próxima ranura en la secuencia 60 | if (HT[pos].clave == k) 61 | return 0; // inserción no exitosa: clave repetida 62 | else { 63 | HT[pos].clave = k; 64 | HT[pos].info = I; 65 | return 1; // inserción exitosa 66 | } 67 | } 68 | 69 | tipoInfo hashSearch(ranura HT[], tipoClave k) { 70 | int inicio, i; 71 | int pos = inicio = h(k); 72 | 73 | for (i = 1; HT[pos].clave != VACIA && HT[pos].clave != k; i++) 74 | pos = (inicio + p(k, i)) % M; // próxima ranura en la secuencia 75 | 76 | if (HT[pos].clave == k) 77 | return HT[pos].info; // registro encontrado, búsqueda exitosa 78 | else 79 | return VALORINVALIDO; // Ejercicio: solucionar esto! 80 | } 81 | 82 | void init(ranura HT[]) { 83 | for(int i = 0; i < M; i++) { 84 | HT[i].clave = VACIA; 85 | } 86 | } 87 | 88 | void printValorNoVacio(ranura HT[]) { 89 | for(int i = 0; i < M; i++) { 90 | if(HT[i].clave != VACIA && HT[i].clave != LIBERADA) { 91 | cout << "clave: " << HT[i].clave << " " 92 | << "info: " << HT[i].info.v << "\n"; 93 | } 94 | } 95 | } 96 | 97 | int main() { 98 | VALORINVALIDO.v = -1; 99 | init(HT); 100 | tipoClave clave = 4567; 101 | tipoInfo info; 102 | info.v = 245003; 103 | hashInsert(HT, clave, info); 104 | tipoClave clave2 = 1273; 105 | tipoInfo info2; 106 | info2.v = 21938746; 107 | hashInsert(HT, clave2, info2); 108 | tipoClave clave3 = 9871; 109 | tipoInfo info3; 110 | info3.v = 9287364; 111 | hashInsert(HT, clave3, info3); 112 | tipoClave clave4 = 1000; 113 | tipoInfo info4; 114 | info4.v = 1; 115 | hashInsert(HT, clave4, info4); 116 | tipoClave clave5 = 100; 117 | tipoInfo info5; 118 | info5.v = 2; 119 | hashInsert(HT, clave5, info5); 120 | printValorNoVacio(HT); 121 | cout << hashSearch(HT, 9871).v << "\n"; 122 | 123 | return 0; 124 | } -------------------------------------------------------------------------------- /06-Hashing/hashing_attempt2.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | #define M 16666 6 | #define VACIA " " 7 | #define LIBERADA "$" 8 | 9 | typedef string tipoClave; 10 | 11 | struct tipoInfo { 12 | string clave_privada; 13 | }; 14 | 15 | tipoInfo VALORINVALIDO; 16 | 17 | struct ranura { 18 | tipoClave clave; 19 | tipoInfo info; 20 | }; 21 | 22 | ranura HT[M]; 23 | 24 | void init(ranura HT[]) { 25 | for(int i = 0; i < M; i++) { 26 | HT[i].clave = VACIA; 27 | } 28 | } 29 | 30 | /*int h(tipoClave k) { 31 | int sum = 0; 32 | for(int i = 0; i < k.length(); i++) { 33 | sum += (int) k[i]; 34 | } 35 | return sum % M; 36 | }*/ 37 | 38 | int h(tipoClave k) { 39 | int sum = 0; 40 | int pow_11 = 1; 41 | for(int i = 0; i < k.length(); i++) { 42 | sum = (((int) (k[i] * pow_11)) % M + sum + M) % M; 43 | pow_11 *= 11; 44 | } 45 | return sum % M; 46 | } 47 | 48 | int p(tipoClave k, int i) { 49 | return 7 * i * i + 17 * i + 47; 50 | } 51 | 52 | int hashInsert(ranura HT[], tipoClave k, tipoInfo I) { 53 | int inicio, i; 54 | int pos = inicio = h(k); 55 | for (i = 1; HT[pos].clave != VACIA && HT[pos].clave != k; i++) { 56 | cout << k << " hizo colision\n"; 57 | pos = (inicio + p(k, i)) % M; // próxima ranura en la secuencia 58 | } 59 | if (HT[pos].clave == k) 60 | return 0; // inserción no exitosa: clave repetida 61 | else { 62 | HT[pos].clave = k; 63 | HT[pos].info = I; 64 | return 1; // inserción exitosa 65 | } 66 | } 67 | 68 | tipoInfo hashSearch(ranura HT[], tipoClave k) { 69 | int inicio, i; 70 | int pos = inicio = h(k); 71 | for (i = 1; HT[pos].clave != VACIA && HT[pos].clave != k; i++) 72 | pos = (inicio + p(k, i)) % M; // próxima ranura en la secuencia 73 | 74 | if (HT[pos].clave == k) 75 | return HT[pos].info; // registro encontrado, búsqueda exitosa 76 | else 77 | return VALORINVALIDO; // Ejercicio: solucionar esto! 78 | } 79 | 80 | void printValorNoVacio(ranura HT[]) { 81 | for(int i = 0; i < M; i++) { 82 | if(HT[i].clave != VACIA && HT[i].clave != LIBERADA) { 83 | cout << "clave: " << HT[i].clave << " " 84 | << "info: " << HT[i].info.clave_privada << "\n"; 85 | } 86 | } 87 | } 88 | 89 | int main() { 90 | VALORINVALIDO.clave_privada = " "; 91 | init(HT); 92 | tipoClave k = "embajador"; 93 | tipoInfo i; 94 | i.clave_privada = "B0mb4 Nu21345"; 95 | hashInsert(HT, k, i); 96 | k = "asdlijasd"; 97 | i; 98 | i.clave_privada = "discretasXD"; 99 | hashInsert(HT, k, i); 100 | k = "Grande el prestigio"; 101 | i; 102 | i.clave_privada = "prestigioposting"; 103 | hashInsert(HT, k, i); 104 | k = "jadoremba"; 105 | i; 106 | i.clave_privada = "Viva la paz"; 107 | hashInsert(HT, k, i); 108 | 109 | cout << hashSearch(HT, "embajador").clave_privada << "\n"; 110 | cout << hashSearch(HT, "asdlijasd").clave_privada << "\n"; 111 | cout << hashSearch(HT, "Grande el prestigio").clave_privada << "\n"; 112 | 113 | cout << "Diccionario\n"; 114 | printValorNoVacio(HT); 115 | return 0; 116 | } -------------------------------------------------------------------------------- /06-Hashing/hashing_attempt3.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace std; 5 | 6 | #define M 16666 7 | #define VACIA "%" 8 | #define LIBERADA "$" 9 | 10 | typedef string tipoClave; 11 | 12 | struct tipoInfo { 13 | string nombre_de_juego; 14 | }; 15 | 16 | tipoInfo VALORINVALIDO; 17 | 18 | struct ranura { 19 | tipoClave clave; 20 | tipoInfo info; 21 | }; 22 | 23 | ranura HT[M]; 24 | 25 | /*int h(tipoClave k) { 26 | int sum = 0; 27 | for(int i = 0; i < k.length(); i++) { 28 | sum += (k[i] * k[i]) / 3; 29 | } 30 | return sum % M; 31 | }*/ 32 | 33 | int h(tipoClave k) { 34 | int sum = 0; 35 | for(int i = 0; i < k.length(); i++) { 36 | sum = (k[i] + sum * 1000) % M; 37 | } 38 | return sum % M; 39 | } 40 | 41 | int p(tipoClave k, int i) { 42 | return 7 * i * i + 3 * i + 11; 43 | } 44 | 45 | int hashInsert(ranura HT[], tipoClave k, tipoInfo I) { 46 | int inicio, i; 47 | int pos = inicio = h(k); 48 | for (i = 1; HT[pos].clave != VACIA && HT[pos].clave != LIBERADA && HT[pos].clave != k; i++) { 49 | cout << k << " tuvo colision F\n"; 50 | pos = (inicio + p(k, i)) % M; // próxima ranura en la secuencia 51 | } 52 | if (HT[pos].clave == k) 53 | return 0; // inserción no exitosa: clave repetida 54 | else { 55 | HT[pos].clave = k; 56 | HT[pos].info = I; 57 | return 1; // inserción exitosa 58 | } 59 | } 60 | 61 | tipoInfo hashSearch(ranura HT[], tipoClave k) { 62 | int inicio, i; 63 | int pos = inicio = h(k); 64 | 65 | for (i = 1; HT[pos].clave != VACIA && HT[pos].clave != k; i++) 66 | pos = (inicio + p(k, i)) % M; // próxima ranura en la secuencia 67 | 68 | if (HT[pos].clave == k) 69 | return HT[pos].info; // registro encontrado, búsqueda exitosa 70 | else 71 | return VALORINVALIDO; // Ejercicio: solucionar esto! 72 | } 73 | 74 | void init(ranura HT[]) { 75 | for(int i = 0; i < M; i++) { 76 | HT[i].clave = VACIA; 77 | } 78 | } 79 | 80 | void printValorNoVacio(ranura HT[]) { 81 | for(int i = 0; i < M; i++) { 82 | if(HT[i].clave != VACIA && HT[i].clave != LIBERADA) { 83 | cout << "clave: " << HT[i].clave << " " 84 | << "info: " << HT[i].info.nombre_de_juego << "\n"; 85 | } 86 | } 87 | } 88 | 89 | int main() { 90 | VALORINVALIDO.nombre_de_juego = ""; 91 | init(HT); 92 | tipoClave k = "Juanito El Gamer 777"; 93 | tipoInfo i; 94 | i.nombre_de_juego = "roblox"; 95 | hashInsert(HT, k, i); 96 | k = "MrYhatoh"; 97 | i.nombre_de_juego = "Super Mario Sunshine"; 98 | hashInsert(HT, k, i); 99 | k = "SniperXD"; 100 | i.nombre_de_juego = "Col ov Duiti"; 101 | hashInsert(HT, k, i); 102 | k = "ASDHAKSDHLA"; 103 | i.nombre_de_juego = "lol"; 104 | hashInsert(HT, k, i); 105 | k = "SnipXDer"; 106 | i.nombre_de_juego = "Col ov Duiti 2"; 107 | hashInsert(HT, k, i); 108 | printValorNoVacio(HT); 109 | return 0; 110 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # INF134-Data_Structures 2 | Este repositorio contendrá códigos para complementar el aprendizaje de los alumnos de INF134 de la UTFSM 3 | 4 | ## Contenidos 5 | 6 | ### I. [Cpp](./01-Cpp) 7 | 8 | 1. [Tipos numericos de datos](./01-Cpp/01-numeric_types.cpp) 9 | 2. [Otros tipos de datos](./01-Cpp/02-other_types.cpp) 10 | 3. [Condicionales](./01-Cpp/03-conditional.cpp) 11 | 4. [Ciclos (while, do-while, for)](./01-Cpp/04-loops.cpp) 12 | 5. [Arreglos](./01-Cpp/05-arrays.cpp) 13 | 6. [Structs](./01-Cpp/06-structs.cpp) 14 | 7. [Pointers](./01-Cpp/07-pointers.cpp) 15 | 8. [Funciones](./01-Cpp/08-functions.cpp) 16 | 9. [Memoria Dinámica](./01-Cpp/09-dynamic_memory.cpp) 17 | 10. [Hacer una matriz con memoria dinamica](./01-Cpp/10-dynamic_memory_matrix.cpp) 18 | 11. [Strings](./01-Cpp/11-strings.cpp) 19 | 12. [Archivos de texto](./01-Cpp/12-text_files.cpp) 20 | 13. [Archivos binarios](./01-Cpp/13-binary_files.cpp) 21 | 14. [Escribir/Leer structs y arreglos](./01-Cpp/14-binary_files_struct_arrays.cpp) 22 | 23 | ### II. [TDA](./02-TDA) 24 | 25 | 1. [Ejemplo de un TDA Personaje](./02-TDA/1-example.cpp) 26 | 2. [Ejemplo de la implementación de un racional](./02-TDA/2-rational.cpp) 27 | 28 | ### III. [Exercise](./03-Exercise) 29 | 30 | 1. [Estudiantes aprobados](./03-Exercise/estudiantes_aprobados/) 31 | 2. [Caracteres distintos](./03-Exercise/caracteres_distintos/) 32 | 33 | ### IV. [EDD Lineales](./04-EDDLineales) 34 | 35 | 1. [Browser Chino](./04-EDDLineales/Browser_Chino.cpp) (Listas) 36 | 2. [Parentesis_Balanceado](./04-EDDLineales/Parentesis_Balanceado.cpp) (Pilas) 37 | 3. [Cajeros](./04-EDDLineales/Cajeros.cpp) (Colas) 38 | 39 | ## Contribuciones 40 | 41 | * Si hay algo que arreglar, no duden en hacer una pull request 42 | * Si hay algo que quieran agregar, no duden en hacer un issue o una pull request! 43 | --------------------------------------------------------------------------------