1 00:00:00,000 --> 00:00:00,500 2 00:00:00,500 --> 00:00:10,850 [MÚSICA DE FONDO] 3 00:00:10,850 --> 00:00:11,820 DAVID: Muy bien. 4 00:00:11,820 --> 00:00:14,540 Esto es CS50 y vamos a iniciar la lección 5. 5 00:00:14,540 --> 00:00:18,180 Y quizás recuerden que en esta semana, 6 00:00:18,180 --> 00:00:20,760 probablemente hemos enfrentado algo como esto. 7 00:00:20,760 --> 00:00:23,949 Y si no tenemos esta experiencia desde la infancia, 8 00:00:23,949 --> 00:00:25,740 a lo que nos referimos en esta serie de problemas 9 00:00:25,740 --> 00:00:29,414 es a estas gafas, que no son gafas 3-D porque tienen ambos ojos rojos 10 00:00:29,414 --> 00:00:31,330 o a veces solo son una gran pieza de plástico. 11 00:00:31,330 --> 00:00:34,680 Pero con esto podemos mirar hacia arriba y ver 12 00:00:34,680 --> 00:00:37,210 cuál se supone que es la respuesta correcta. 13 00:00:37,210 --> 00:00:40,770 Esta es la alusión a la que nos referimos 14 00:00:40,770 --> 00:00:43,230 y en la serie de problemas cinco que hicieron, el objetivo 15 00:00:43,230 --> 00:00:47,037 es averiguar cómo implementaríamos este filtro rojo. 16 00:00:47,037 --> 00:00:48,870 Pero para hacer eso, primero debemos entender 17 00:00:48,870 --> 00:00:52,380 esta cosa, la cual a primera vista, parece bastante complicada. 18 00:00:52,380 --> 00:00:54,131 Pero si ya nos sumergimos en este problema, 19 00:00:54,131 --> 00:00:56,380 probablemente han rondado en nuestra mente, al menos 20 00:00:56,380 --> 00:00:59,640 algunos de estos ámbitos, como el tamaño, el ancho 21 00:00:59,640 --> 00:01:02,940 y la altura de la imagen, con lo cual esto debería ser un poco más 22 00:01:02,940 --> 00:01:03,950 sencillo. 23 00:01:03,950 --> 00:01:07,680 Pero para implementarlo, tenemos que lidiar con algo 24 00:01:07,680 --> 00:01:10,200 llamado struct o una estructura. 25 00:01:10,200 --> 00:01:12,337 En C, tenemos esta función, recuérdenla. 26 00:01:12,337 --> 00:01:14,670 En realidad, la última vez no jugamos mucho con esto. 27 00:01:14,670 --> 00:01:17,640 Pero lo hemos visto en medicina forense, o lo haremos pronto. 28 00:01:17,640 --> 00:01:20,070 Aquí tenemos la definición de un student. 29 00:01:20,070 --> 00:01:22,950 Hace décadas, cuando se inventó C, no anticiparon 30 00:01:22,950 --> 00:01:24,570 la necesidad de un tipo de datos para los estudiantes. 31 00:01:24,570 --> 00:01:26,790 Tenían int, char, float y double. 32 00:01:26,790 --> 00:01:29,520 Pero como en Scratch, podemos inventar nuestros propios tipos de datos 33 00:01:29,520 --> 00:01:32,340 y hacer nuestras propias piezas de rompecabezas, de la siguiente manera. 34 00:01:32,340 --> 00:01:35,940 typedef para definir un tipo, struct para decir que viene una estructura. 35 00:01:35,940 --> 00:01:37,732 ¿Cuál es la estructura conocida como student? 36 00:01:37,732 --> 00:01:40,481 Bueno, en este caso, decidí arbitrariamente que un student 37 00:01:40,481 --> 00:01:42,930 tiene un name, un dorm y ambos serían cadenas. 38 00:01:42,930 --> 00:01:44,971 Imaginemos poner otras cosas allí 39 00:01:44,971 --> 00:01:47,580 como números ID, teléfonos, direcciones de correo electrónico o lo que sea 40 00:01:47,580 --> 00:01:50,890 y podríamos combinar toda esta información en conjunto. 41 00:01:50,890 --> 00:01:54,300 Echemos un vistazo rápido a cómo usaríamos un código como este. 42 00:01:54,300 --> 00:01:57,200 Aquí hay un archivo llamado struct.h 43 00:01:57,200 --> 00:02:01,620 Es algo común, pero no es necesario declarar las estructuras dentro 44 00:02:01,620 --> 00:02:05,490 de un archivo que también comienza con .h, para que podamos compartirlo en múltiples 45 00:02:05,490 --> 00:02:08,162 programas al igual que con los encabezados de otras bibliotecas. 46 00:02:08,162 --> 00:02:09,870 Aquí quité esas ruedas de entrenamiento 47 00:02:09,870 --> 00:02:13,830 donde string es una mentira blanca para el carácter asterisco. 48 00:02:13,830 --> 00:02:15,720 Pero esta es la misma estructura de datos 49 00:02:15,720 --> 00:02:17,940 y está en un archivo llamado struct. h. 50 00:02:17,940 --> 00:02:20,820 Démosle un vistazo rápido a un programa que utiliza 51 00:02:20,820 --> 00:02:25,660 esto en struct0.c. Veamos lo que hicimos aquí. 52 00:02:25,660 --> 00:02:28,180 En struct0.c tenemos arriba algunos encabezados de archivos. 53 00:02:28,180 --> 00:02:31,260 Pero también debemos incluir este encabezado de archivo para tener acceso 54 00:02:31,260 --> 00:02:33,030 a este nuevo tipo de datos personalizado. 55 00:02:33,030 --> 00:02:35,740 Luego haremos algunas cosas en main. 56 00:02:35,740 --> 00:02:39,120 Primero le pediremos al usuario un número entero llamado enrollment. 57 00:02:39,120 --> 00:02:41,550 Con suerte nos darán un número positivo. 58 00:02:41,550 --> 00:02:45,570 Si recibimos un número como se espera en la línea 13, 59 00:02:45,570 --> 00:02:48,060 ¿En inglés qué hacemos aquí? 60 00:02:48,060 --> 00:02:52,280 ¿Cómo describiríamos lo que hace la línea 13 en este punto del término? 61 00:02:52,280 --> 00:02:54,124 Alguien, ¿sí? 62 00:02:54,124 --> 00:02:56,510 PÚBLICO: [INAUDIBLE] 63 00:02:56,510 --> 00:03:00,170 DAVID: Sí, nos da un arreglo students de tamaño enrollment. 64 00:03:00,170 --> 00:03:03,050 De modo que, aunque en la línea 11 y previamente no lo hicimos, 65 00:03:03,050 --> 00:03:07,160 sabemos cuántos estudiantes necesitamos, sí en la línea 12 conseguimos 66 00:03:07,160 --> 00:03:09,030 la respuesta, con enrollment. 67 00:03:09,030 --> 00:03:12,440 En la línea 13 declaramos un arreglo mediante una variable que dice, 68 00:03:12,440 --> 00:03:17,250 dame tantos elementos o estudiantes en mi arreglo para almacenar cosas. 69 00:03:17,250 --> 00:03:20,260 Y en las líneas a continuación, procedemos de la siguiente manera. 70 00:03:20,260 --> 00:03:24,200 Comenzamos a iterar sobre enrollment, desde cero hasta enrollment. 71 00:03:24,200 --> 00:03:28,364 Y en cada iteración le pedimos al usuario el name y el dorm de student. 72 00:03:28,364 --> 00:03:31,280 La parte derecha de esas dos líneas de código es bastante familiar, 73 00:03:31,280 --> 00:03:32,860 llamamos a get_string. 74 00:03:32,860 --> 00:03:36,230 Pero en el lado izquierdo, tenemos una sintaxis ligeramente nueva. 75 00:03:36,230 --> 00:03:39,620 Tenemos students [ i ] el cual nos da a los estudiantes i-ésimo en el arreglo. 76 00:03:39,620 --> 00:03:42,380 ¿Pero cuál pieza de sintaxis tal vez nos brinca? 77 00:03:42,380 --> 00:03:45,140 ¿En especial si nunca antes hemos programado? 78 00:03:45,140 --> 00:03:48,355 Y aún no hemos utilizado este símbolo en este contexto. 79 00:03:48,355 --> 00:03:49,230 ¿Qué se ve diferente? 80 00:03:49,230 --> 00:03:49,810 Sí. 81 00:03:49,810 --> 00:03:50,710 PÚBLICO: [INAUDIBLE] 82 00:03:50,710 --> 00:03:52,043 DAVID: Sí, el .name. 83 00:03:52,043 --> 00:03:56,270 Probablemente podamos inferir que .name y .dorm de algún modo acceden 84 00:03:56,270 --> 00:03:58,170 al name y al dorm de student. 85 00:03:58,170 --> 00:03:59,919 Y eso es todo lo que está sucediendo. 86 00:03:59,919 --> 00:04:04,400 El operador punto le dice a la computadora, que entre en la estructura de student 87 00:04:04,400 --> 00:04:09,080 en esa ubicación i-ésima y almacene la cadena que 88 00:04:09,080 --> 00:04:11,060 regresa de get_string en esa variable. 89 00:04:11,060 --> 00:04:13,114 Y hace lo mismo para dorm. 90 00:04:13,114 --> 00:04:15,530 Es como tomar una estructura y luego mirar dentro de ella 91 00:04:15,530 --> 00:04:17,990 y va de manera muy específica hacia uno de los elementos de la misma. 92 00:04:17,990 --> 00:04:21,740 Nunca hemos necesitado este .operador porque en el pasado, cualquier arreglo, 93 00:04:21,740 --> 00:04:25,310 o variable que tuvimos fue un string, un int o un float. 94 00:04:25,310 --> 00:04:27,320 No hemos tenido nada en que profundizar. 95 00:04:27,320 --> 00:04:28,820 Entonces, eso es todo lo que sucede allí. 96 00:04:28,820 --> 00:04:33,200 Encapsulamos, el interior del structure, el name y el dorm de un estudiante. 97 00:04:33,200 --> 00:04:35,990 Y esta última parte es sólo un printf 98 00:04:35,990 --> 00:04:37,680 de esa misma información. 99 00:04:37,680 --> 00:04:40,740 Sólo imprimimos, así-y-así es en tal-y-tal dorm 100 00:04:40,740 --> 00:04:44,812 pasando esas dos cadenas, usando nuestro conocido %s 101 00:04:44,812 --> 00:04:47,270 Ahora, este programa al final del día es un poco inútil 102 00:04:47,270 --> 00:04:50,311 porque le indicamos al usuario algunos names y dorms de estudiantes, 103 00:04:50,311 --> 00:04:52,810 los imprimimos y luego los desechamos para siempre. 104 00:04:52,810 --> 00:04:55,670 Eso no es tan útil para un programa a largo plazo. 105 00:04:55,670 --> 00:05:00,320 Tenemos un truco nuevo para la segunda versión de este programa, struct1.c 106 00:05:00,320 --> 00:05:01,160 también. 107 00:05:01,160 --> 00:05:03,680 También es un adelanto sobre la dirección 108 00:05:03,680 --> 00:05:05,870 que llevaremos en esta serie de problemas, en la próxima, 109 00:05:05,870 --> 00:05:08,892 y en todas en las que usemos archivos, dado que los archivos en una computadora 110 00:05:08,892 --> 00:05:10,850 solo son un montón de bits, ceros y unos. 111 00:05:10,850 --> 00:05:13,050 Esos ceros y unos siguen algún patrón. 112 00:05:13,050 --> 00:05:16,280 Pero aún tenemos que ver un mecanismo para guardar los archivos. 113 00:05:16,280 --> 00:05:17,570 Pero así es como podemos hacerlo. 114 00:05:17,570 --> 00:05:20,720 Encima de esta línea, la 21 y más arriba, el mismo programa. 115 00:05:20,720 --> 00:05:24,140 Tenemos un montón de students del usuario, por su name y dorm. 116 00:05:24,140 --> 00:05:26,390 Después, en la línea 24 vemos algo que es 117 00:05:26,390 --> 00:05:30,740 nuevo, por ahora solo vimos esto en el problema forense. 118 00:05:30,740 --> 00:05:33,825 Llamamos a una función llamada fopen, que significa archivo abierto. 119 00:05:33,825 --> 00:05:36,200 Eso toma dos argumentos, según su documentación. 120 00:05:36,200 --> 00:05:38,840 El nombre del archivo que deseamos abrir y luego el segundo argumento 121 00:05:38,840 --> 00:05:40,760 es cómo queremos abrir el archivo. 122 00:05:40,760 --> 00:05:42,650 E incluso si nunca antes hemos visto esto, 123 00:05:42,650 --> 00:05:45,740 ¿Qué podría representar la w? 124 00:05:45,740 --> 00:05:46,699 PÚBLICO: [INAUDIBLE] 125 00:05:46,699 --> 00:05:47,740 DAVID: Sí, es cierto. 126 00:05:47,740 --> 00:05:51,140 Es read y write, dos de las operaciones más comunes para una computadora. 127 00:05:51,140 --> 00:05:53,040 La r sería read y la w para write. 128 00:05:53,040 --> 00:05:57,050 Esto tiene sentido, si el objetivo es guardar estos students en un archivo 129 00:05:57,050 --> 00:06:00,020 para que el programa sea útil si lo ejecutamos una y otra vez. 130 00:06:00,020 --> 00:06:03,110 A la izquierda tenemos un nuevo tipo de datos. 131 00:06:03,110 --> 00:06:06,260 Todos en mayúsculas, lo cual es un poco anormal, incluso en C. 132 00:06:06,260 --> 00:06:10,700 Pero FILE *file dice, oye, dame una variable en formato file 133 00:06:10,700 --> 00:06:13,880 que pueda almacenar la ubicación de un archivo, por así decirlo. 134 00:06:13,880 --> 00:06:16,820 Y técnicamente, esa no es la ubicación del archivo en el disco. 135 00:06:16,820 --> 00:06:19,441 Es la ubicación en la RAM, una vez que hayamos abierto el archivo. 136 00:06:19,441 --> 00:06:22,190 Pero por ahora, pensemos que esto es una abstracción para el file. 137 00:06:22,190 --> 00:06:23,720 Y simplemente se llama file. 138 00:06:23,720 --> 00:06:27,452 ¿cuál es el propósito en la vida, de la línea 25? 139 00:06:27,452 --> 00:06:29,660 Aunque nunca antes hemos escrito este código. 140 00:06:29,660 --> 00:06:32,010 141 00:06:32,010 --> 00:06:33,010 Sí, ¿qué piensan? 142 00:06:33,010 --> 00:06:34,680 PÚBLICO: Si el archivo existe. 143 00:06:34,680 --> 00:06:38,760 DAVID: Si el archivo existe, o más general, si el archivo se abrió 144 00:06:38,760 --> 00:06:39,540 correctamente. 145 00:06:39,540 --> 00:06:41,831 Porque podrían salir mal muchísimas cosas. 146 00:06:41,831 --> 00:06:43,960 Uno, como lo suponen, el archivo podría no existir. 147 00:06:43,960 --> 00:06:47,190 Dos, tal vez no tenemos permiso, entonces existe pero no podemos abrirlo. 148 00:06:47,190 --> 00:06:49,440 Tres, tal vez no haya suficiente memoria en la computadora 149 00:06:49,440 --> 00:06:50,920 para abrir un archivo más. 150 00:06:50,920 --> 00:06:52,740 Cualquier cantidad de cosas podría salir mal. 151 00:06:52,740 --> 00:06:58,600 Recordemos, ¿cuál es el valor centinela especial que representa los errores 152 00:06:58,600 --> 00:07:01,040 ahora que estamos en el mundo de los punteros? 153 00:07:01,040 --> 00:07:05,580 Null o N-U-L-L todo en mayúsculas es lo contrario a tener una ubicación válida. 154 00:07:05,580 --> 00:07:06,660 Significa que no hay tal ubicación. 155 00:07:06,660 --> 00:07:08,035 Y lo usamos para comprobar si hay errores. 156 00:07:08,035 --> 00:07:09,750 Eso es todo lo que hace la línea 25. 157 00:07:09,750 --> 00:07:13,350 Todo lo demás es casi idéntico al programa anterior, 158 00:07:13,350 --> 00:07:16,800 excepto por que no usamos printf. ¿Qué es lo que al parecer usamos? 159 00:07:16,800 --> 00:07:21,010 fprintf y adivinen ¿qué significa la f en printf?. 160 00:07:21,010 --> 00:07:24,060 Sí, es file printf y funciona casi igual 161 00:07:24,060 --> 00:07:25,680 excepto que necesitamos un argumento más. 162 00:07:25,680 --> 00:07:27,900 El primer argumento no es una cadena de formato 163 00:07:27,900 --> 00:07:29,640 como lo ha sido durante años. 164 00:07:29,640 --> 00:07:34,800 Es una variable que hace referencia a un archivo abierto y luego el resto de este 165 00:07:34,800 --> 00:07:35,480 todo es lo mismo. 166 00:07:35,480 --> 00:07:37,980 Lo que es genial sobre fprintf es que no sólo 167 00:07:37,980 --> 00:07:38,820 imprimimos en la pantalla, 168 00:07:38,820 --> 00:07:40,830 sino en cualquier archivo que tengamos 169 00:07:40,830 --> 00:07:43,020 abierto para que después, en la última línea 170 00:07:43,020 --> 00:07:47,430 aquí, cuando llamo fclose, eso sea el equivalente a guardar el archivo. 171 00:07:47,430 --> 00:07:48,990 Luego el programa simplemente se cierra. 172 00:07:48,990 --> 00:07:50,790 Al final, lo que es genial sobre esto es, 173 00:07:50,790 --> 00:07:53,040 que si sigo adelante y me desplazo hacia arriba, 174 00:07:53,040 --> 00:07:56,200 entraré en mi directorio fuente 5, 175 00:07:56,200 --> 00:08:02,980 continuaré en make struct1. 176 00:08:02,980 --> 00:08:04,820 structs.h no encontrado. 177 00:08:04,820 --> 00:08:05,590 ¿Qué hice mal? 178 00:08:05,590 --> 00:08:08,590 Bueno, acabo de arruinarlo antes del curso y nombré mal este archivo 179 00:08:08,590 --> 00:08:11,080 ¡eso no sucedió! 180 00:08:11,080 --> 00:08:12,670 Ya compilé el programa. 181 00:08:12,670 --> 00:08:17,560 Muy bien, para continuar ejecutaré esto, ./struct1 enrollment será 182 00:08:17,560 --> 00:08:18,550 3. 183 00:08:18,550 --> 00:08:28,100 Diremos que será María quien esté en Cabot House y Brian quien 184 00:08:28,100 --> 00:08:29,380 está en Winthrop. 185 00:08:29,380 --> 00:08:33,010 Y digamos que David estaba, digamos, en Mather. 186 00:08:33,010 --> 00:08:34,929 Enter y nada sucede. 187 00:08:34,929 --> 00:08:38,630 Pero si ahora escribo ls y miro dentro de este directorio, 188 00:08:38,630 --> 00:08:41,860 noten que tengo un archivo llamado a propósito students.csv 189 00:08:41,860 --> 00:08:43,960 porque si alguna vez usaron Excel o Numbers, 190 00:08:43,960 --> 00:08:48,610 son muy comunes los archivos csv, un formato de valores separados 191 00:08:48,610 --> 00:08:49,270 por comas. 192 00:08:49,270 --> 00:08:52,390 Es una base de datos muy simple. 193 00:08:52,390 --> 00:08:55,930 Si abro esto verán que, de hecho, los contenidos de este archivo 194 00:08:55,930 --> 00:08:58,760 están separados por comas. 195 00:08:58,760 --> 00:09:04,090 Y si tuviera que abrir este archivo en Excel, cada una de estas columnas 196 00:09:04,090 --> 00:09:06,920 se abrirían y visualmente serían exactamente como eso. 197 00:09:06,920 --> 00:09:09,690 Entonces, lo que hice con mi printf, si vuelvo a structs1.c, 198 00:09:09,690 --> 00:09:14,590 Noten como conscientemente incluí esa coma allí, 199 00:09:14,590 --> 00:09:17,560 para crear este tipo de formato de base de datos falso. 200 00:09:17,560 --> 00:09:19,750 Y solo por si acaso, déjenme ver si 201 00:09:19,750 --> 00:09:23,050 podemos descargarlo desde el administrador de archivos del IDE, 202 00:09:23,050 --> 00:09:26,260 luego abro students.csv. 203 00:09:26,260 --> 00:09:32,830 Si el programa coopera aquí tenemos Microsoft Excel. 204 00:09:32,830 --> 00:09:35,240 Me hice una pequeña hoja de cálculo, 205 00:09:35,240 --> 00:09:36,520 usé un código en C. 206 00:09:36,520 --> 00:09:39,130 Rápidamente encontraremos que esto no es 207 00:09:39,130 --> 00:09:40,840 tan útil para hacer archivos csv. 208 00:09:40,840 --> 00:09:44,025 Debido a que entre más filas agreguemos a estos archivos, más y más lento 209 00:09:44,025 --> 00:09:45,400 será el buscarlos. 210 00:09:45,400 --> 00:09:48,670 La próxima semana haremos la transición hacia la programación web 211 00:09:48,670 --> 00:09:52,450 y reemplazaremos las hojas de cálculo o los formatos csv, como este, 212 00:09:52,450 --> 00:09:56,860 por algo más poderoso, es decir, las bases de datos. 213 00:09:56,860 --> 00:09:59,210 Por lo que esto, es un adelanto de lo que está por venir. 214 00:09:59,210 --> 00:10:00,991 Pero, ¿dónde comenzamos esta conversación? 215 00:10:00,991 --> 00:10:02,740 Al parecer, todo nos conduce a lo que hay 216 00:10:02,740 --> 00:10:05,870 dentro de nuestra computadora, en lo cual continuaremos abstrayéndonos. 217 00:10:05,870 --> 00:10:08,080 No es necesario que comprendamos cómo funciona este hardware. 218 00:10:08,080 --> 00:10:10,600 Ya antes dijimos, que podíamos pensar 219 00:10:10,600 --> 00:10:13,360 en dividir la memoria de nuestra computadora en una cuadrícula, 220 00:10:13,360 --> 00:10:15,370 a fin de numerar todos los bytes. 221 00:10:15,370 --> 00:10:17,320 De modo que tengamos ubicaciones específicas, también 222 00:10:17,320 --> 00:10:19,420 conocidas como direcciones o punteros. 223 00:10:19,420 --> 00:10:22,840 La última vez aclaramos, que no toda la memoria se 224 00:10:22,840 --> 00:10:24,640 se ocupa de la misma forma dentro de la computadora. 225 00:10:24,640 --> 00:10:27,630 Por el contrario, cada fragmento de esta se utiliza de forma diferente. 226 00:10:27,630 --> 00:10:32,200 En la parte superior, digamos, aunque en realidad no hay tal parte superior, 227 00:10:32,200 --> 00:10:34,140 es solo es una interpretación del artista. 228 00:10:34,140 --> 00:10:35,890 Así que, la parte superior de la memoria de nuestra computadora podría 229 00:10:35,890 --> 00:10:40,600 ser el heap, donde almacenamos ciertos tipos de valores 230 00:10:40,600 --> 00:10:42,700 y aquí abajo está lo que llamamos stack, donde 231 00:10:42,700 --> 00:10:44,690 almacenamos otros tipos de valores. 232 00:10:44,690 --> 00:10:48,590 Y si hacemos un alejamiento, hay diferentes capas de memoria. 233 00:10:48,590 --> 00:10:51,010 Separemos lo qué está sucediendo aquí, 234 00:10:51,010 --> 00:10:53,410 Si cuando ejecutamos un programa, tenemos acceso 235 00:10:53,410 --> 00:10:56,170 a uno dos gigabytes de RAM y de hecho, eso es 236 00:10:56,170 --> 00:10:57,310 lo que hace tu Mac o PC. 237 00:10:57,310 --> 00:10:59,184 No importa la cantidad de RAM que tengamos, la computadora 238 00:10:59,184 --> 00:11:02,890 por lo general, nos da la ilusión de que tenemos acceso a toda. 239 00:11:02,890 --> 00:11:05,500 Esto serían dos gigabytes de memoria. 240 00:11:05,500 --> 00:11:07,270 Bueno, una de las primeras cosas que pasa, 241 00:11:07,270 --> 00:11:10,330 es que los ceros y unos que conforman nuestro programa, ya sea 242 00:11:10,330 --> 00:11:14,680 que se llamen A.out, Caesar, Vigenere o Structs1, esos ceros y unos 243 00:11:14,680 --> 00:11:18,140 se cargan aquí arriba, en la memoria de nuestra computadora. 244 00:11:18,140 --> 00:11:21,100 Así, el segmento de texto en la memoria es un nombre raro, 245 00:11:21,100 --> 00:11:23,320 para los ceros y unos de nuestro programa. 246 00:11:23,320 --> 00:11:24,610 No es texto ASCII. 247 00:11:24,610 --> 00:11:28,180 Literalmente son los ceros y unos del programa que compilamos. 248 00:11:28,180 --> 00:11:31,900 Luego están los que llamamos datos de inicio o no inicializados. 249 00:11:31,900 --> 00:11:34,510 Lo que básicamente significa, que cualquiera de las variables globales 250 00:11:34,510 --> 00:11:38,230 que tengamos en el programa, se almacenarán aquí o aquí. 251 00:11:38,230 --> 00:11:40,910 Si les asignamos valores en la parte superior del programa, 252 00:11:40,910 --> 00:11:42,582 estas se iniciarán por definición, 253 00:11:42,582 --> 00:11:44,290 pero si no lo hicimos, no se iniciarán. 254 00:11:44,290 --> 00:11:47,230 En este caso, el compilador establece las cosas un poco diferente. 255 00:11:47,230 --> 00:11:49,580 En el extremo inferior hay algo llamado variables de entorno, 256 00:11:49,580 --> 00:11:51,400 las cuales no ocupamos demasiado, pero las utilizaremos 257 00:11:51,400 --> 00:11:52,858 en algunas semanas para la programación web. 258 00:11:52,858 --> 00:11:56,500 A menudo, almacenaremos nombres de usuario, contraseñas y otros valores 259 00:11:56,500 --> 00:11:58,430 que no queremos guardar en el código, 260 00:11:58,430 --> 00:12:02,440 pero queremos que nuestra Mac, PC o el servidor tengan acceso de algún modo, 261 00:12:02,440 --> 00:12:05,811 por ello nos enfocaremos más en estos, stack y heap. 262 00:12:05,811 --> 00:12:08,560 Ya vimos un par de ejemplos de cada uno, pero brevemente. 263 00:12:08,560 --> 00:12:11,976 ¿Cómo usamos stack o en qué caso dijimos que lo usaríamos, la última vez? 264 00:12:11,976 --> 00:12:12,850 PÚBLICO: [INAUDIBLE] 265 00:12:12,850 --> 00:12:14,046 DAVID: ¿Dilo de nuevo? 266 00:12:14,046 --> 00:12:14,420 PÚBLICO: [INAUDIBLE] 267 00:12:14,420 --> 00:12:16,450 DAVID: con int main void y de manera más general, 268 00:12:16,450 --> 00:12:18,130 con las funciones cuando las llamamos. 269 00:12:18,130 --> 00:12:22,120 Main es, por supuesto, el que irá en todos los inicios de los programas, 270 00:12:22,120 --> 00:12:25,780 pero podría llamar a otra función como swap 271 00:12:25,780 --> 00:12:29,650 y swap, por sí mismo, podría llamar a algo más, tal vez a printf. 272 00:12:29,650 --> 00:12:34,990 Cada vez que llamamos una función, esta ocupa una porción o un marco de la memoria. 273 00:12:34,990 --> 00:12:38,920 Y aumenta cada vez más, conforme se llama a esas funciones. 274 00:12:38,920 --> 00:12:43,870 Al menos teóricamente, al final esto fue esclarecedor, 275 00:12:43,870 --> 00:12:46,330 en cuanto a por qué este programa no sirvió. 276 00:12:46,330 --> 00:12:49,900 El programa que vimos la última vez, en los programas de swap y noswap, 277 00:12:49,900 --> 00:12:51,940 afirmamos que esta implementación fue incorrecta. 278 00:12:51,940 --> 00:12:55,480 Pero aún creo que cuando Kate apareció, e hicimos el ejemplo con el intercambio 279 00:12:55,480 --> 00:12:57,580 de los sabores de Gatorade, esto fue más o menos 280 00:12:57,580 --> 00:13:00,220 una interpretación de eso en el código. 281 00:13:00,220 --> 00:13:03,630 Es correcto en un sentido e incorrecto en otro. 282 00:13:03,630 --> 00:13:06,510 ¿En qué sentido fue correcto este código? 283 00:13:06,510 --> 00:13:07,890 En el programa noswap, 284 00:13:07,890 --> 00:13:10,804 porque lo revisamos brevemente con el depurador. 285 00:13:10,804 --> 00:13:13,070 PÚBLICO: [INAUDIBLE] 286 00:13:13,070 --> 00:13:15,870 DAVID: OK, necesitábamos una variable o contenedor temporal, 287 00:13:15,870 --> 00:13:18,960 para almacenar uno de los valores o de los sabores de Gatorade. 288 00:13:18,960 --> 00:13:21,240 Y para cuando llegamos a esta tercera y última línea 289 00:13:21,240 --> 00:13:24,900 en esta función, ¿qué podríamos decir sobre a y b? 290 00:13:24,900 --> 00:13:26,070 PÚBLICO: [INAUDIBLE] 291 00:13:26,070 --> 00:13:27,810 DAVID: Sí, de hecho fueron intercambiados. 292 00:13:27,810 --> 00:13:31,060 Vi eso, creo que al conectarlos, creo que tuve problemas con el depurador 293 00:13:31,060 --> 00:13:32,940 de modo que usé eprintf en el último minuto, 294 00:13:32,940 --> 00:13:36,120 para ver lo que sucedió después de esa tercera línea. 295 00:13:36,120 --> 00:13:37,110 Entonces funciona. 296 00:13:37,110 --> 00:13:40,586 Esta función intercambia a y b, ¿pero qué es lo que no intercambia? 297 00:13:40,586 --> 00:13:41,460 PÚBLICO: [INAUDIBLE] 298 00:13:41,460 --> 00:13:44,040 DAVID: A x y y, las cuales fueron las variables en main. 299 00:13:44,040 --> 00:13:47,010 Recordemos la historia que contamos la última vez, 300 00:13:47,010 --> 00:13:49,680 dijimos que si solo nos enfocamos en el stack de la computadora, 301 00:13:49,680 --> 00:13:52,890 esa porción inferior de la memoria y cuando se llama a main 302 00:13:52,890 --> 00:13:55,157 se ocupa un fragmento de la memoria, esta parte de abajo, 303 00:13:55,157 --> 00:13:57,240 porque es la primera función en llamarse. 304 00:13:57,240 --> 00:14:01,680 Recordemos que tenía a las variables x y y, cuyos valores eran 1 y 2. 305 00:14:01,680 --> 00:14:05,150 Cuando main llamó a swap, la otra función que acabamos de ver, 306 00:14:05,150 --> 00:14:12,180 tenía a los valores a, b y también a tmp que al inicio eran 1 y 2 307 00:14:12,180 --> 00:14:14,844 y finalmente se convirtieron en 2 y 1. 308 00:14:14,844 --> 00:14:17,010 Pero esta imagen responde a toda la pregunta, 309 00:14:17,010 --> 00:14:19,620 la razón por la que x y y no cambiaron es porque 310 00:14:19,620 --> 00:14:23,370 en esa versión roja solo cambiamos a y b. 311 00:14:23,370 --> 00:14:27,416 Así resolvimos el problema, recuerdan ¿cuál era la función nueva en C? 312 00:14:27,416 --> 00:14:28,290 PÚBLICO: [INAUDIBLE] 313 00:14:28,290 --> 00:14:29,820 DAVID: Los punteros y direcciones. 314 00:14:29,820 --> 00:14:33,510 En vez de devolver la función, los valores que deseamos intercambiar, 315 00:14:33,510 --> 00:14:36,690 démosle a la función un mapa del camino, por así decirlo, a esos valores 316 00:14:36,690 --> 00:14:40,140 para que la función pueda ir a los valores que nos importan, 317 00:14:40,140 --> 00:14:42,010 y moverlos dondequiera que estén. 318 00:14:42,010 --> 00:14:43,871 Al principio la sintaxis se ve algo rara, 319 00:14:43,871 --> 00:14:45,870 parece como si multiplicáramos por todos lados, 320 00:14:45,870 --> 00:14:47,520 pero tiene dos usos diferentes. 321 00:14:47,520 --> 00:14:52,350 Si tenemos el asterisco aquí arriba y un tipo de datos como int junto a él, 322 00:14:52,350 --> 00:14:53,760 esto dice, oye computadora, 323 00:14:53,760 --> 00:14:57,060 dame una variable llamada a, pero eso no almacenará un int. 324 00:14:57,060 --> 00:14:58,525 ¿Qué almacenará? 325 00:14:58,525 --> 00:14:59,400 PÚBLICO: [INAUDIBLE] 326 00:14:59,400 --> 00:15:02,520 DAVID: Sí, la ubicación de un int en la memoria, al igual que b 327 00:15:02,520 --> 00:15:05,424 almacenará la ubicación de otro entero. 328 00:15:05,424 --> 00:15:07,590 Son una especie de marcadores de posición para las direcciones. 329 00:15:07,590 --> 00:15:09,300 Más adelante está el Centro de Ciencias. 330 00:15:09,300 --> 00:15:12,300 Si la dirección del Centro de Ciencias es 1 Oxford Street, Cambridge, 331 00:15:12,300 --> 00:15:16,290 Mass 02138, esa dirección postal es la única que identifica 332 00:15:16,290 --> 00:15:16,920 a ese edificio. 333 00:15:16,920 --> 00:15:20,697 De manera similar, en una computadora los valores tienen ubicaciones únicas. 334 00:15:20,697 --> 00:15:21,780 Pero son mucho más simples. 335 00:15:21,780 --> 00:15:24,738 Son números, no tienen calles, ni códigos postales, ni nada de eso. 336 00:15:24,738 --> 00:15:26,590 Pero es exactamente la misma idea. 337 00:15:26,590 --> 00:15:29,867 Pero aún tenemos una variable tmp de tipo int: int tmp = *a; 338 00:15:29,867 --> 00:15:31,950 Así que denme una variable temporal como la que tenía Kate, 339 00:15:31,950 --> 00:15:34,310 el vaso extra que al inicio estaba vacío. 340 00:15:34,310 --> 00:15:38,240 *a, sin embargo, sin un tipo de datos a la izquierda, ¿qué quiere decir? 341 00:15:38,240 --> 00:15:41,850 342 00:15:41,850 --> 00:15:45,710 En este contexto *a, es una oración en inglés, diferente a esta 343 00:15:45,710 --> 00:15:46,280 otra, 344 00:15:46,280 --> 00:15:50,480 que significa, denme un puntero para un int o declaren una variable para mí, 345 00:15:50,480 --> 00:15:52,430 que almacene la ubicación de un int. 346 00:15:52,430 --> 00:15:55,340 Pero esto dice, ve a esa ubicación. 347 00:15:55,340 --> 00:15:58,730 Esto es, que a esta en la ubicación y *a significa ve a esa ubicación, para que 348 00:15:58,730 --> 00:16:01,970 lleguemos al valor, el cual en la historia, probablemente es uno. 349 00:16:01,970 --> 00:16:03,260 *a significa lo mismo. 350 00:16:03,260 --> 00:16:04,850 De nuevo, ve a esa ubicación 351 00:16:04,850 --> 00:16:07,010 y después, por cierto, ve a la ubicación de b. 352 00:16:07,010 --> 00:16:11,120 Cualquiera que sea ese valor, colócalo donde apunta este dedo. 353 00:16:11,120 --> 00:16:15,710 Luego *b significa ve a esa dirección y pon lo que haya en el vaso temporal 354 00:16:15,710 --> 00:16:20,010 de Gatorade o en este caso, el valor uno. 355 00:16:20,010 --> 00:16:22,730 Así, los punteros, aunque tienen una manera muy complicada 356 00:16:22,730 --> 00:16:26,390 de arreglarlo, básicamente solucionan el problema, porque 357 00:16:26,390 --> 00:16:32,450 en vez de pasar el 1 y el 2, en su lugar pasamos aquí la ubicación de x 358 00:16:32,450 --> 00:16:35,600 y la ubicación de Y que la computadora permitió 359 00:16:35,600 --> 00:16:38,540 para luego ir a esas ubicaciones en la memoria y 360 00:16:38,540 --> 00:16:42,000 hacer lo que queríamos que hiciera. 361 00:16:42,000 --> 00:16:45,290 Para resumir la historia, así es como se usa el stack de la computadora. 362 00:16:45,290 --> 00:16:48,080 Cuando llamamos a una función, esta ocupa una nueva porción de la memoria, arriba 363 00:16:48,080 --> 00:16:49,750 de cualquier otra función que llamemos. 364 00:16:49,750 --> 00:16:52,280 Tan pronto como esa función termine de ejecutarse, 365 00:16:52,280 --> 00:16:54,890 está memoria se borra de manera eficaz. 366 00:16:54,890 --> 00:16:57,290 Técnicamente sigue ahí, porque es el hardware, 367 00:16:57,290 --> 00:16:59,510 no desaparecerá físicamente. 368 00:16:59,510 --> 00:17:04,069 Pero cualquiera que sea la próxima función que main llame, tal vez printf o algo 369 00:17:04,069 --> 00:17:08,030 más, reutilizará esa memoria de todas las maneras 370 00:17:08,030 --> 00:17:11,750 que necesite para sus propios valores y parámetros locales. 371 00:17:11,750 --> 00:17:14,180 Dada esa definición, el hecho de que el stack, al igual 372 00:17:14,180 --> 00:17:16,644 que las bandejas de la cafetería crezcan hacía arriba y hacía abajo 373 00:17:16,644 --> 00:17:19,310 y arriba y abajo, es cómo el programa llama a las funciones y esas funciones 374 00:17:19,310 --> 00:17:22,960 regresan, ¿de dónde salen los valores basura? 375 00:17:22,960 --> 00:17:26,322 376 00:17:26,322 --> 00:17:27,599 PÚBLICO: [INAUDIBLE] 377 00:17:27,599 --> 00:17:29,640 DAVID: Las cosas viejas que estaban en esa memoria. 378 00:17:29,640 --> 00:17:31,681 Tiempo atrás hice esta afirmación radical 379 00:17:31,681 --> 00:17:34,410 de que no debemos confiar en las variables, si no pusimos 380 00:17:34,410 --> 00:17:37,450 nosotros mismos los valores en ellas, porque tienen los llamados valores basura. 381 00:17:37,450 --> 00:17:39,510 Pero eso tiene un significado muy preciso. 382 00:17:39,510 --> 00:17:41,700 Eso significa que si nosotros llamamos a una función y esta 383 00:17:41,700 --> 00:17:45,330 necesita una variable que está aquí y esto es como un minuto 384 00:17:45,330 --> 00:17:48,270 en la ejecución de nuestro programa, hay un montón de funciones diferentes 385 00:17:48,270 --> 00:17:51,900 que esa parte de la memoria podría haber usado y no usado, usado y no usado. 386 00:17:51,900 --> 00:17:56,190 Allí solo tendremos ceros y unos en algún patrón persistente. 387 00:17:56,190 --> 00:18:00,210 La computadora podría estar muy a la defensiva y cambiar 388 00:18:00,210 --> 00:18:02,430 todos los bits a cero, todo el tiempo. 389 00:18:02,430 --> 00:18:04,680 Esa podría ser una decisión de diseño razonable, 390 00:18:04,680 --> 00:18:06,389 pero resumen, C no hace eso. 391 00:18:06,389 --> 00:18:08,888 Eso llevaría mucho tiempo, en especial hace años 392 00:18:08,888 --> 00:18:10,200 cuando las computadoras eran más lentas, 393 00:18:10,200 --> 00:18:11,430 y el lenguaje no estaba bien desarrollado, 394 00:18:11,430 --> 00:18:13,210 y simplemente no era convincente hacer esto. 395 00:18:13,210 --> 00:18:15,480 Por lo que obtenemos los valores basura, los cuales casi siempre tengo 396 00:18:15,480 --> 00:18:16,920 escritos como signos de interrogación. 397 00:18:16,920 --> 00:18:17,810 Pero esa es la razón. 398 00:18:17,810 --> 00:18:21,900 Hay valores basura allí porque, son nuestros propios valores anteriores, 399 00:18:21,900 --> 00:18:23,890 o los de algunas funciones. 400 00:18:23,890 --> 00:18:27,430 Por otra parte, el heap era diferente. 401 00:18:27,430 --> 00:18:30,090 El heap es el extremo superior de la memoria 402 00:18:30,090 --> 00:18:34,470 que en cierto sentido conceptual, está encima del stack. 403 00:18:34,470 --> 00:18:35,580 Está aquí arriba. 404 00:18:35,580 --> 00:18:39,120 Es diferente en el sentido de que funciona más como almacenamiento a largo plazo. 405 00:18:39,120 --> 00:18:41,060 El stack es para el almacenamiento a corto plazo y 406 00:18:41,060 --> 00:18:43,320 se usa localmente cuando se ejecuta una función. 407 00:18:43,320 --> 00:18:45,720 Pero supongamos que nuestro programa se ejecuta por mucho tiempo, 408 00:18:45,720 --> 00:18:49,080 o queremos una función para asignar la memoria que no se usa 409 00:18:49,080 --> 00:18:51,670 y que no se convierta de inmediato en valores basura. 410 00:18:51,670 --> 00:18:53,310 En efecto, piensen en get_string. 411 00:18:53,310 --> 00:18:55,860 get_string es una función que escribimos y su propósito en la vida 412 00:18:55,860 --> 00:18:59,280 es obtener una cadena del usuario, la cual es un montón de caracteres. 413 00:18:59,280 --> 00:19:00,150 Y consideren esto. 414 00:19:00,150 --> 00:19:05,910 Si se llama a get_string y se ocupa una porción de memoria en el stack 415 00:19:05,910 --> 00:19:12,210 y yo escribo el nombre María, M-A-R-I-A y eso se vuelve un secret \0. 416 00:19:12,210 --> 00:19:16,800 ¿Dónde se almacenaron M-A-R-I-A y \0? 417 00:19:16,800 --> 00:19:20,280 ¿Esto puede, por definición, almacenarse en el stack? 418 00:19:20,280 --> 00:19:22,398 ¿Por qué? 419 00:19:22,398 --> 00:19:24,445 PÚBLICO: [INAUDIBLE] 420 00:19:24,445 --> 00:19:25,320 DAVID: Exactamente. 421 00:19:25,320 --> 00:19:29,970 Si asignamos el espacio en el stack, lo cual podríamos hacer con un arreglo, 422 00:19:29,970 --> 00:19:32,580 y luego devuelve la ubicación de esa cadena, 423 00:19:32,580 --> 00:19:35,970 lo que sería válido en cierta forma, porque nosotros 424 00:19:35,970 --> 00:19:37,830 asignaríamos la memoria. 425 00:19:37,830 --> 00:19:39,600 Para continuar, lo dibujaré así. 426 00:19:39,600 --> 00:19:44,340 Si tuviéramos una función get_string y get_string es llamada 427 00:19:44,340 --> 00:19:48,660 por main, eso significaría que get_string tiene este fragmento de memoria 428 00:19:48,660 --> 00:19:49,320 aquí. 429 00:19:49,320 --> 00:19:52,080 Y si María o yo continuamos y escribimos su nombre, 430 00:19:52,080 --> 00:19:57,270 eso asignaría espacio para M-A-R-I-A \0 431 00:19:57,270 --> 00:20:00,520 y podemos pensar que esto como un montón de bytes en ese marco. 432 00:20:00,520 --> 00:20:02,894 Entonces existen y están almacenados en la memoria. 433 00:20:02,894 --> 00:20:06,510 Así podría devolver la ubicación de este primer byte, sea cual sea. 434 00:20:06,510 --> 00:20:09,490 Tal vez esto sea un byte 10, 100 o los que sean. 435 00:20:09,490 --> 00:20:13,110 Y podría devolverle esa ubicación a main, como un valor de retorno de get_string. 436 00:20:13,110 --> 00:20:16,530 Pero en cuanto lo haga, sí, exactamente, 437 00:20:16,530 --> 00:20:19,140 técnicamente la memoria no va a ninguna parte. 438 00:20:19,140 --> 00:20:21,390 Pero ya no es confiable. 439 00:20:21,390 --> 00:20:23,190 Ahora todo eso es un valor basura. 440 00:20:23,190 --> 00:20:24,630 Pero podríamos tener suerte 441 00:20:24,630 --> 00:20:28,530 y si intentamos imprimir el valor de retorno de get_string, veremos a María, 442 00:20:28,530 --> 00:20:31,800 pero brevemente, porque la próxima vez que se llame una línea de código 443 00:20:31,800 --> 00:20:34,440 o se utilice de nuevo la memoria, el nombre de María 444 00:20:34,440 --> 00:20:36,360 podría sobrescribirse con algunos otros valores, 445 00:20:36,360 --> 00:20:39,264 porque el nombre se convierte, por definición, en un valor basura. 446 00:20:39,264 --> 00:20:41,680 Y no sabemos cuándo se volverá a usar. 447 00:20:41,680 --> 00:20:43,000 Eso no es seguro 448 00:20:43,000 --> 00:20:44,610 y esta es la razón de que heap exista. 449 00:20:44,610 --> 00:20:48,990 Si necesitamos mantener algo en la memoria por un tiempo, como se supone get_string 450 00:20:48,990 --> 00:20:54,570 lo hace, podemos asignarlo a cualquier otro lugar que no desaparezca 451 00:20:54,570 --> 00:20:56,040 hasta que nosotros mismos lo liberemos. 452 00:20:56,040 --> 00:20:59,190 La última vez presentamos un par de funciones nuevas, 453 00:20:59,190 --> 00:21:02,250 malloc para la asignación de memoria y 454 00:21:02,250 --> 00:21:04,410 existe un opuesto de ella, free, que 455 00:21:04,410 --> 00:21:08,100 necesitaremos en las series de problemas relacionados con la gestión de la memoria 456 00:21:08,100 --> 00:21:10,237 y para deshacer la asignación aquí. 457 00:21:10,237 --> 00:21:12,570 De lo contrario, terminaremos con lo que se llama una pérdida de memoria, 458 00:21:12,570 --> 00:21:14,970 la computadora se volvería lenta y se agotaría la memoria, 459 00:21:14,970 --> 00:21:16,510 porque no lo devolvemos, 460 00:21:16,510 --> 00:21:18,884 como nota aparte, hay un par de primos 461 00:21:18,884 --> 00:21:21,390 de malloc, calloc y realloc. 462 00:21:21,390 --> 00:21:24,630 calloc es genial en cuanto a que la c significa claro. 463 00:21:24,630 --> 00:21:28,900 calloc es idéntico a malloc, pero pone todo el fragmento de memoria en cero 464 00:21:28,900 --> 00:21:29,400 para nosotros. 465 00:21:29,400 --> 00:21:32,760 De modo que, si queremos inicializar para no tener ningún valor basura, 466 00:21:32,760 --> 00:21:36,750 usaremos calloc en lugar de hacerlo con un bucle for o algo 467 00:21:36,750 --> 00:21:37,530 como eso. 468 00:21:37,530 --> 00:21:40,170 Realloc, veamos, es una función más poderosa 469 00:21:40,170 --> 00:21:43,860 nos permite tomar un fragmento de la memoria y expandirlo. 470 00:21:43,860 --> 00:21:46,470 En un momento veremos lo que eso significa. 471 00:21:46,470 --> 00:21:49,150 Pero con este poder viene una gran responsabilidad, 472 00:21:49,150 --> 00:21:52,260 vimos que las cosas salen terriblemente mal para Binky 473 00:21:52,260 --> 00:21:54,390 cuando se usan mal las direcciones de la memoria. 474 00:21:54,390 --> 00:21:57,870 Recordemos que vimos brevemente este programa gracias al video de Nick 475 00:21:57,870 --> 00:21:59,070 de Stanford. 476 00:21:59,070 --> 00:22:02,720 Veamos qué representan estas líneas del código. 477 00:22:02,720 --> 00:22:07,530 Aquí y aquí declaro dos variables, x y y 478 00:22:07,530 --> 00:22:11,760 En términos generales ¿Qué es lo que almacenarán? 479 00:22:11,760 --> 00:22:14,190 Ubicaciones de enteros. 480 00:22:14,190 --> 00:22:16,180 Eso es todo lo que sucede allí. 481 00:22:16,180 --> 00:22:18,390 Esta es una línea del código que vimos la última vez, x = malloc (sizeof(int)); 482 00:22:18,390 --> 00:22:21,334 la cual dice, llama a malloc, para que asigne cierta cantidad de memoria. 483 00:22:21,334 --> 00:22:22,500 ¿Cuánta memoria queremos? 484 00:22:22,500 --> 00:22:24,420 Cualquiera que sea el tamaño de int. 485 00:22:24,420 --> 00:22:28,800 Las probabilidades son cuatro, tal vez ocho, tal vez un poco de ambos 486 00:22:28,800 --> 00:22:32,550 o algún múltiplo de dos o de cuatro. 487 00:22:32,550 --> 00:22:34,332 ¿qué devolvemos aquí? 488 00:22:34,332 --> 00:22:36,540 Un fragmento de memoria o específicamente, su ubicación y nosotros 489 00:22:36,540 --> 00:22:40,620 lo almacenamos en x. Esta línea: *x = 42 dice, ve a esa ubicación 490 00:22:40,620 --> 00:22:43,320 y coloca allí el número especial 42. 491 00:22:43,320 --> 00:22:47,730 La próxima línea *y = 13, sin dudarlo dice, ve a la ubicación en y 492 00:22:47,730 --> 00:22:50,190 y coloca allí el desafortunado número 13. 493 00:22:50,190 --> 00:22:54,480 Pero ahí es donde Binky tuvo un accidente porque 494 00:22:54,480 --> 00:22:56,580 ¿qué estaba dentro de y en ese momento? 495 00:22:56,580 --> 00:22:59,418 496 00:22:59,418 --> 00:23:00,294 PÚBLICO: [INAUDIBLE] 497 00:23:00,294 --> 00:23:02,251 DAVID: La memoria no le permitió tocarlo. 498 00:23:02,251 --> 00:23:02,790 ¿Por qué? 499 00:23:02,790 --> 00:23:05,654 Sean más precisos. 500 00:23:05,654 --> 00:23:13,094 PÚBLICO: [INAUDIBLE] 501 00:23:13,094 --> 00:23:14,010 DAVID: Están muy cerca. 502 00:23:14,010 --> 00:23:17,339 En última instancia eso explicará el síntoma ¿pero? 503 00:23:17,339 --> 00:23:19,155 PÚBLICO: [INAUDIBLE] 504 00:23:19,155 --> 00:23:20,030 DAVID: Exactamente. 505 00:23:20,030 --> 00:23:21,740 No pedí más memoria. 506 00:23:21,740 --> 00:23:24,320 Así que por defecto, aunque parezca extraño, 507 00:23:24,320 --> 00:23:27,410 int *y significa dame espacio para una ubicación. 508 00:23:27,410 --> 00:23:31,460 Significa dame cuatro u ocho bytes de memoria RAM. 509 00:23:31,460 --> 00:23:35,020 Pero ¿por definición, qué hay dentro de una variable? 510 00:23:35,020 --> 00:23:35,980 Únicamente valores basura. 511 00:23:35,980 --> 00:23:38,960 Habrá un número allí y estos son nuestras ubicaciones. 512 00:23:38,960 --> 00:23:41,126 Por lo que parecerá que allí hay una ubicación. 513 00:23:41,126 --> 00:23:43,470 Técnicamente, es correcto decir, ve allí, 514 00:23:43,470 --> 00:23:46,550 pero es como seguir un mapa en el que no tenemos idea hacia dónde vamos. 515 00:23:46,550 --> 00:23:49,220 Podríamos recorrer la orilla de algún lugar 516 00:23:49,220 --> 00:23:51,050 y ahí es cuando las cosas salen mal. 517 00:23:51,050 --> 00:23:54,437 Esta era la visualización que Nick realizó con plastimación. 518 00:23:54,437 --> 00:23:56,270 Si tenemos esto y parece que no 519 00:23:56,270 --> 00:23:58,380 importa si el asterisco está a la izquierda o a la derecha, justo aquí. 520 00:23:58,380 --> 00:24:00,410 Pero por convención lo pondremos en el lado derecho, 521 00:24:00,410 --> 00:24:01,640 junto a la variable. 522 00:24:01,640 --> 00:24:04,970 El int *x e int *y, es como si dijéramos, 523 00:24:04,970 --> 00:24:08,780 dame un fragmento de memoria o de arcilla para cada variable. 524 00:24:08,780 --> 00:24:12,230 Y él encerró la pequeña punta de flecha en la cadena 525 00:24:12,230 --> 00:24:13,672 porque había memoria para eso. 526 00:24:13,672 --> 00:24:15,380 No apunta hacia ningún lado en específico. 527 00:24:15,380 --> 00:24:17,660 En este momento es un valor basura. 528 00:24:17,660 --> 00:24:20,280 Este fue el siguiente capítulo de la historia. 529 00:24:20,280 --> 00:24:23,960 Asignarle un espacio al int, aquí dibujado en arcilla blanca. 530 00:24:23,960 --> 00:24:27,744 Y por la asignación, Nick dice que x, la cual de nuevo es un puntero, 531 00:24:27,744 --> 00:24:29,660 señalará ese fragmento de la memoria. 532 00:24:29,660 --> 00:24:31,250 De modo que ya no es un valor basura 533 00:24:31,250 --> 00:24:32,840 y señala hacia algún lugar en específico. 534 00:24:32,840 --> 00:24:35,360 Por eso Nick fue capaz de decir, ve allí, 535 00:24:35,360 --> 00:24:38,650 sigue la flecha y coloca allí el número 42, 536 00:24:38,650 --> 00:24:42,530 pero la siguiente línea del código salió terriblemente mal, 537 00:24:42,530 --> 00:24:45,550 porque no apuntaba hacia ningún lado. 538 00:24:45,550 --> 00:24:49,820 Nick intentó decir ve allí y coloca el 13, pero allí no hay nada, de modo que 539 00:24:49,820 --> 00:24:50,900 la computadora se bloquea. 540 00:24:50,900 --> 00:24:54,650 Una falla en la segmentación, significa que tocamos un segmento de la memoria 541 00:24:54,650 --> 00:24:57,530 que no deberíamos tener, porque tratamos de ir a algún lado 542 00:24:57,530 --> 00:24:59,600 donde solo hay valores basura. 543 00:24:59,600 --> 00:25:03,050 Recordemos que para arreglarlo, la solución sería esto, 544 00:25:03,050 --> 00:25:05,900 si en vez de eso retrocedemos para arreglar a Binky 545 00:25:05,900 --> 00:25:10,820 y decimos que y = x; eso no asigna espacio extra. 546 00:25:10,820 --> 00:25:16,371 Solo nos dice que el punto y esta en el mismo fragmento de memoria que x, 547 00:25:16,371 --> 00:25:18,120 porque nuevamente, x y y solo son direcciones. 548 00:25:18,120 --> 00:25:22,520 Si la dirección en la memoria es 100, x será 100 y y será 100. 549 00:25:22,520 --> 00:25:24,920 Ambos apuntan al mismo fragmento de arcilla blanca. 550 00:25:24,920 --> 00:25:29,360 Cuando él utiliza a *y obtiene 13 y eso indica, ve allí 551 00:25:29,360 --> 00:25:30,590 y actualiza el número. 552 00:25:30,590 --> 00:25:32,390 Por eso el 42 se convirtió en el 13. 553 00:25:32,390 --> 00:25:36,170 Es algo muy similar a nuestro ejemplo de capitalización, 554 00:25:36,170 --> 00:25:41,510 cuando señalamos las cadenas en el mismo fragmento de la memoria. 555 00:25:41,510 --> 00:25:47,720 ¿hay alguna pregunta sobre el stack o sobre lo que vimos en Binky, el heap? 556 00:25:47,720 --> 00:25:50,360 malloc asigna la memoria del heap, 557 00:25:50,360 --> 00:25:53,870 pero cada vez que declaramos variables locales o arreglos 558 00:25:53,870 --> 00:25:56,120 dentro de una función, eso termina en el stack. 559 00:25:56,120 --> 00:25:59,660 Hasta ahora malloc, calloc o realloc son las únicas herramientas 560 00:25:59,660 --> 00:26:03,080 que nos dan acceso a la porción de memoria que representamos como arcilla blanca 561 00:26:03,080 --> 00:26:07,760 aquí y como lo vimos en la parte de arriba de nuestro diagrama. 562 00:26:07,760 --> 00:26:08,370 ¿Alguna pregunta? 563 00:26:08,370 --> 00:26:10,450 Sí. 564 00:26:10,450 --> 00:26:19,366 PÚBLICO: [INAUDIBLE] 565 00:26:19,366 --> 00:26:20,490 DAVID: Buena pregunta. 566 00:26:20,490 --> 00:26:23,540 Tengamos en cuenta que x y y son los mismos tipos de datos. 567 00:26:23,540 --> 00:26:25,310 Ambos son punteros para ubicaciones. 568 00:26:25,310 --> 00:26:28,010 Por eso, si establecemos a uno, debe ser igual al otro 569 00:26:28,010 --> 00:26:32,570 y tenemos que almacenar el valor que está en uno, dentro del otro. 570 00:26:32,570 --> 00:26:34,700 De lo contrario, sería como poner un número entero 571 00:26:34,700 --> 00:26:37,640 dentro de un puntero, lo cual no es del todo correcto a pesar de que 572 00:26:37,640 --> 00:26:39,330 técnicamente ambos son números. 573 00:26:39,330 --> 00:26:43,460 Esta y = x; dice que cualquiera sea la ubicación de x, 574 00:26:43,460 --> 00:26:47,690 pongamos la misma ubicación en y, no dice nada acerca de ir a esa ubicación. 575 00:26:47,690 --> 00:26:51,410 Es similar a fotocopiar un mapa, pero sin seguir 576 00:26:51,410 --> 00:26:52,340 ese mapa aún. 577 00:26:52,340 --> 00:26:56,090 Hasta esta línea, la cual dice, sigue la copia del mapa 578 00:26:56,090 --> 00:26:58,630 y nos conduce a la misma ubicación. 579 00:26:58,630 --> 00:26:59,708 ¿Sí? 580 00:26:59,708 --> 00:27:05,870 PÚBLICO: [INAUDIBLE] 581 00:27:05,870 --> 00:27:09,690 DAVID: Si regresamos, en C solo podemos regresar un valor. 582 00:27:09,690 --> 00:27:13,590 Así que estaremos en un aprieto porque en teoría, queremos regresar dos valores, 583 00:27:13,590 --> 00:27:14,090 ¿cierto? 584 00:27:14,090 --> 00:27:16,700 Tanto a como b, queremos volverlos b y a. Existen 585 00:27:16,700 --> 00:27:19,820 maneras en las que podemos trabajar para que regresen dos valores 586 00:27:19,820 --> 00:27:20,319 y verlos. 587 00:27:20,319 --> 00:27:23,150 Pero en resumen, es mucho más fácil decirlo que hacerlo. 588 00:27:23,150 --> 00:27:25,830 En Python sería mucho más fácil, 589 00:27:25,830 --> 00:27:28,550 Pero lo malo de C es que no podemos regresar varios valores. 590 00:27:28,550 --> 00:27:31,800 Y en este caso eso nos ata de manos. 591 00:27:31,800 --> 00:27:34,860 OK probablemente esto tenga relación con otras cosas, han 592 00:27:34,860 --> 00:27:37,637 escuchado sobre este sitio web, que es sumamente útil cuando 593 00:27:37,637 --> 00:27:40,470 tratamos de aprender un lenguaje nuevo, o en el mundo real 594 00:27:40,470 --> 00:27:42,287 tratamos de resolver algún problema, porque esta es 595 00:27:42,287 --> 00:27:45,120 una comunidad con personas maravillosas, que publican preguntas y respuestas, 596 00:27:45,120 --> 00:27:48,570 y se enlazan mediante referencias convencionales para que entendamos 597 00:27:48,570 --> 00:27:50,590 el porqué de alguna respuesta. 598 00:27:50,590 --> 00:27:53,920 Pero esto tiene un significado muy técnico, stack overflow. 599 00:27:53,920 --> 00:27:56,310 Y stack, por supuesto, ahora es un concepto que conocemos. 600 00:27:56,310 --> 00:28:00,630 Y podemos imaginar que algo como esta imagen, en definitiva 601 00:28:00,630 --> 00:28:07,230 saldrá muy mal si llamamos a tantas funciones, que nos quedemos 602 00:28:07,230 --> 00:28:07,920 sin memoria, 603 00:28:07,920 --> 00:28:10,252 o que ni siquiera se ejecuten como tal. 604 00:28:10,252 --> 00:28:12,960 ¿A la larga, qué podríamos afectar si seguimos llamando a una función, 605 00:28:12,960 --> 00:28:15,590 después una función, después de una función? 606 00:28:15,590 --> 00:28:16,200 El heap. 607 00:28:16,200 --> 00:28:17,866 Entonces ocurrirán cosas malas. 608 00:28:17,866 --> 00:28:21,120 Si nuestros marcos del stack y sus variables locales 609 00:28:21,120 --> 00:28:24,480 son tan numerosos que comenzamos a sobrescribir la memoria del heap 610 00:28:24,480 --> 00:28:29,380 los valores que asignamos con malloc se destruirían. 611 00:28:29,380 --> 00:28:32,590 Esta no es la mejor decisión sobre el diseño, pero es la realidad. 612 00:28:32,590 --> 00:28:35,040 Esto solo se reduce mediante el uso de un compilador que 613 00:28:35,040 --> 00:28:37,980 nos permita notar esto, o si no utilizamos 614 00:28:37,980 --> 00:28:39,820 más memoria de la que necesitamos. 615 00:28:39,820 --> 00:28:44,170 Ahora, el stack overflow, tiene un significado muy técnico aquí, 616 00:28:44,170 --> 00:28:45,690 al igual que el heap overflow, 617 00:28:45,690 --> 00:28:47,640 stack overflow significa que sobrecargamos el stack, 618 00:28:47,640 --> 00:28:50,610 llamamos tantas malditas funciones, que tocamos la memoria 619 00:28:50,610 --> 00:28:51,130 que no debíamos. 620 00:28:51,130 --> 00:28:52,630 heap overflow sería todo lo contrario, 621 00:28:52,630 --> 00:28:54,505 es cuando seguimos llamando a malloc y malloc y malloc 622 00:28:54,505 --> 00:28:56,460 y el heap sobrecarga al stack. 623 00:28:56,460 --> 00:28:59,526 Porque para bien o para mal, el stack aumenta de esta manera 624 00:28:59,526 --> 00:29:00,900 y el heap aumenta de esta manera. 625 00:29:00,900 --> 00:29:03,600 Hasta que con el tiempo se golpearán entre sí. 626 00:29:03,600 --> 00:29:07,470 Esta es la manera más sencilla de decir desbordamiento de búfer. 627 00:29:07,470 --> 00:29:11,517 El búfer es un fragmento de la memoria que almacena datos o valores 628 00:29:11,517 --> 00:29:13,350 y nosotros, las personas en el mundo real seguro escuchamos 629 00:29:13,350 --> 00:29:16,740 de esto en algún vídeo, en YouTube o en diversos reproductores de vídeos. 630 00:29:16,740 --> 00:29:19,407 Si alguna vez vimos la expresión buffering ta-ta-ta, 631 00:29:19,407 --> 00:29:20,740 es la cosa más exasperante, 632 00:29:20,740 --> 00:29:22,800 cuando algo está por suceder en la película o espectáculo que estamos viendo 633 00:29:22,800 --> 00:29:25,710 y la maldita cosa empieza a cargar y cargar y cargar. 634 00:29:25,710 --> 00:29:26,830 ¿Qué significa esto? 635 00:29:26,830 --> 00:29:28,980 Bueno, el reproductor de vídeo, YouTube u otra cosa, 636 00:29:28,980 --> 00:29:32,090 tiene un fragmento de la memoria, el cual podemos pensar como un arreglo 637 00:29:32,090 --> 00:29:34,527 y cargados en ese arreglo están los ceros y los unos 638 00:29:34,527 --> 00:29:36,610 que conforman la película o el programa de TV que estamos viendo, 639 00:29:36,610 --> 00:29:38,443 y que a su vez se descargaron del Internet. 640 00:29:38,443 --> 00:29:41,640 Con suerte, la velocidad del Internet será más rápida 641 00:29:41,640 --> 00:29:43,530 que la reproducción de la película 642 00:29:43,530 --> 00:29:46,710 y aunque estemos en el minuto 10 del video, 643 00:29:46,710 --> 00:29:50,460 es de esperar que la computadora descargará del minuto 10 al 11 644 00:29:50,460 --> 00:29:52,649 para que acumulemos los bytes en el búfer 645 00:29:52,649 --> 00:29:54,690 durante un minuto entero y así podamos mirarlo 646 00:29:54,690 --> 00:29:57,090 incluso si nuestra conexión a Internet falla. 647 00:29:57,090 --> 00:30:01,290 Cuando el video se almacenó en el búfer, tenemos este arreglo de memoria 648 00:30:01,290 --> 00:30:04,410 y hemos visto o mirado todos los bytes en él 649 00:30:04,410 --> 00:30:06,030 y el búfer ahora está vacío, 650 00:30:06,030 --> 00:30:07,650 pero también puede ocurrir lo contrario. 651 00:30:07,650 --> 00:30:11,070 si intentamos descargar más bytes de los que caben en la memoria, 652 00:30:11,070 --> 00:30:13,680 tal vez podríamos poner los minutos del video en algún lugar 653 00:30:13,680 --> 00:30:15,780 que no pertenezca a nuestra computadora. 654 00:30:15,780 --> 00:30:19,230 O si llamamos demasiadas funciones, o a malloc demasiadas veces, 655 00:30:19,230 --> 00:30:21,810 es probable que sobrecarguemos el fragmento de memoria asignada. 656 00:30:21,810 --> 00:30:23,310 Así que los búferes están por todos lados 657 00:30:23,310 --> 00:30:26,580 y de hecho, una cadena tal como la conocemos es un búfer, 658 00:30:26,580 --> 00:30:28,530 es un arreglo de memoria y con suerte 659 00:30:28,530 --> 00:30:32,520 solo pondrá tantos caracteres en esa cadena, 660 00:30:32,520 --> 00:30:34,600 como puedan alojarse en ese fragmento de memoria. 661 00:30:34,600 --> 00:30:36,150 ¿Qué cosas pueden salir mal? 662 00:30:36,150 --> 00:30:37,920 Este es un pequeño ejemplo inventado, pero 663 00:30:37,920 --> 00:30:39,753 viene con un par de gráficos para pintar 664 00:30:39,753 --> 00:30:44,430 una imagen, de cómo los enemigos hackean los sistemas 665 00:30:44,430 --> 00:30:48,180 que están escritos en lenguajes como C. Aquí tenemos un programa rápido, 666 00:30:48,180 --> 00:30:49,800 vamos a #include 667 00:30:49,800 --> 00:30:53,730 abajo tenemos a int main, que toma argumentos de la línea de comandos. 668 00:30:53,730 --> 00:30:56,220 Observen que esta función: foo(argv[1]); no hace verificación de errores. 669 00:30:56,220 --> 00:30:57,240 Es bastante tonta, 670 00:30:57,240 --> 00:31:01,350 solo llama una función foo y pasa a un argv[1]. 671 00:31:01,350 --> 00:31:03,540 La idea aquí es que este es un programa en el que 672 00:31:03,540 --> 00:31:06,750 si tomamos un argumento de la línea de comandos, una palabra después del nombre 673 00:31:06,750 --> 00:31:09,900 del programa, nos llevará directamente al programa foo. 674 00:31:09,900 --> 00:31:10,440 OK. 675 00:31:10,440 --> 00:31:12,030 A continuación, ¿qué hace foo? 676 00:31:12,030 --> 00:31:17,220 Acepta como entrada una cadena void foo (char *bar) y la llamaremos bar, 677 00:31:17,220 --> 00:31:23,077 luego asigna un arreglo en el stack llamado c de tamaño 12: char c[12]; 678 00:31:23,077 --> 00:31:25,410 E incluso si nunca antes hemos visto esta función, 679 00:31:25,410 --> 00:31:29,490 tal vez podamos deducir de su nombre memcpy, algo como copia de la memoria. 680 00:31:29,490 --> 00:31:33,420 Entonces, esto se va a copiar en esta memoria, sea lo que sea, 681 00:31:33,420 --> 00:31:36,750 en esta memoria, hasta esta cantidad de bytes. 682 00:31:36,750 --> 00:31:42,540 Si escribo María como el argumento de la línea de comando, M-A-R-I-A tiene cinco, 683 00:31:42,540 --> 00:31:45,090 eso significa que la longitud que escribí, será cinco 684 00:31:45,090 --> 00:31:52,140 y copiará cinco bytes de bar hacia C, eso es todo. 685 00:31:52,140 --> 00:31:53,640 Pero está destinado a ser solamente un monstruo, 686 00:31:53,640 --> 00:31:55,848 a fin de cuentas este programa es bastante inútil. 687 00:31:55,848 --> 00:31:59,670 Pero es como destilar un proceso en las pocas líneas del código. 688 00:31:59,670 --> 00:32:02,230 ¿Cómo se ve esto o qué está sucediendo? 689 00:32:02,230 --> 00:32:03,660 Llamamos a la función: foo(argv[1]); 690 00:32:03,660 --> 00:32:05,970 Asignamos 12 bytes: char c[12]; 691 00:32:05,970 --> 00:32:08,670 Copiamos 5 bytes en esos 12 bytes: memcpy (c, bar, strlen(bar)); 692 00:32:08,670 --> 00:32:10,140 Parece que todo está bien en la historia. 693 00:32:10,140 --> 00:32:12,670 694 00:32:12,670 --> 00:32:14,320 Pero, ¿qué sucedió en la memoria? 695 00:32:14,320 --> 00:32:18,360 Aquí hay una foto amplificada y muy bien coloreada del stack. 696 00:32:18,360 --> 00:32:19,920 Así que el stack va de esta manera. 697 00:32:19,920 --> 00:32:21,480 El heap aumenta de esta manera. 698 00:32:21,480 --> 00:32:25,320 Esto técnicamente nos muestra cómo se distribuyen las cosas en el stack. 699 00:32:25,320 --> 00:32:27,900 Simplifico el mundo al dibujar cosas 700 00:32:27,900 --> 00:32:31,430 como x, y, a y b, pero siguen un cierto orden. 701 00:32:31,430 --> 00:32:33,800 Y específicamente, si tenemos una variable local 702 00:32:33,800 --> 00:32:35,660 llamada bar, la cual hicimos para esta función, 703 00:32:35,660 --> 00:32:38,060 esta irá aquí abajo. 704 00:32:38,060 --> 00:32:41,776 Si luego declaramos un arreglo llamado c, irá directamente aquí arriba. 705 00:32:41,776 --> 00:32:43,150 Y estos son de tamaño proporcional, 706 00:32:43,150 --> 00:32:43,910 este tiene cuatro bytes 707 00:32:43,910 --> 00:32:45,118 y este será de 12 bytes, 708 00:32:45,118 --> 00:32:47,870 todo tiene un tamaño proporcional. 709 00:32:47,870 --> 00:32:50,550 Luego, no entraremos en muchos detalles 710 00:32:50,550 --> 00:32:53,420 pero si te gustan estas cosas, CS 61 y otros cursos lo explorarán, 711 00:32:53,420 --> 00:32:57,140 pero otra cosa que siempre estuvo guardada en el stack, 712 00:32:57,140 --> 00:33:01,080 en secreto, es lo que se llama una dirección de retorno. 713 00:33:01,080 --> 00:33:05,390 Cuando main llama a swap, es como entregarle las llaves del coche 714 00:33:05,390 --> 00:33:06,320 a otra persona. 715 00:33:06,320 --> 00:33:08,210 Es algo como swap, ve a hacer lo tuyo. 716 00:33:08,210 --> 00:33:12,290 Pero main tiene que decirle a swap o a cualquier función que llame, 717 00:33:12,290 --> 00:33:17,600 cómo devolver su fragmento de memoria, para que la ejecución se reanude con main 718 00:33:17,600 --> 00:33:20,090 tan pronto como swap termine de ejecutarse. 719 00:33:20,090 --> 00:33:22,280 Y no es su propia memoria de pila. 720 00:33:22,280 --> 00:33:25,500 ¿Recuerdan la parte superior de la memoria que describí como el segmento de texto? 721 00:33:25,500 --> 00:33:28,040 ¿Todos los ceros y unos que conforman nuestro programa? 722 00:33:28,040 --> 00:33:32,360 Cuando main llama a swap o a alguna otra función, 723 00:33:32,360 --> 00:33:35,630 introduce su propia dirección de retorno, la ubicación correcta de los ceros 724 00:33:35,630 --> 00:33:40,640 y los unos en ese segmento de texto, en cuatro o tal vez ocho bytes, 725 00:33:40,640 --> 00:33:44,382 la ubicación a la cual swap debe devolvernos las llaves, digamos. 726 00:33:44,382 --> 00:33:47,090 De otro modo, es como si main le entregara las llaves a otra función 727 00:33:47,090 --> 00:33:49,881 y luego nunca vuelve a saber de ella y las otras líneas del código de main, 728 00:33:49,881 --> 00:33:51,030 nunca se ejecutan. 729 00:33:51,030 --> 00:33:55,640 En resumen, debe existir una ubicación o un mapa escondido 730 00:33:55,640 --> 00:33:59,060 en el stack, para que swap pueda devolverle el control a main. 731 00:33:59,060 --> 00:34:02,847 Pero, ¿qué sucede aquí cuando usamos esta memoria? 732 00:34:02,847 --> 00:34:05,930 Bueno, si numeramos los bytes que hay en el stack y 733 00:34:05,930 --> 00:34:09,199 eran de tamaño 12, el primero es 0 y el último es 11, 734 00:34:09,199 --> 00:34:11,570 por lo que del 0 al 11 nos da un total de 12. 735 00:34:11,570 --> 00:34:16,190 Si escribimos algo como María o de manera más general, hola, H-E-L-L-O, 736 00:34:16,190 --> 00:34:19,219 que tiene la misma longitud, técnicamente eso utiliza 6 bytes, 737 00:34:19,219 --> 00:34:21,170 por el \0 y todo está bien. 738 00:34:21,170 --> 00:34:25,070 Se ajusta cómodamente en c y tenemos espacio para respirar. 739 00:34:25,070 --> 00:34:29,429 Pero, ¿y si no escribimos MARIA o HELLO? 740 00:34:29,429 --> 00:34:35,090 ¿Qué pasa si escribimos una oración muy larga de más de 12 caracteres? 741 00:34:35,090 --> 00:34:36,860 ¿Dónde van a terminar? 742 00:34:36,860 --> 00:34:40,370 Si escribimos una cadena más larga en la línea de comandos, en argv[1], 743 00:34:40,370 --> 00:34:42,650 noten que el código tiene errores. 744 00:34:42,650 --> 00:34:46,310 Verifiquemos la longitud de la palabra que el usuario ingresó, 745 00:34:46,310 --> 00:34:50,120 copiaremos todos los bytes de bar en c. Pero ¿qué pasa 746 00:34:50,120 --> 00:34:53,400 si la longitud de la cadena que escribimos es de 13? 747 00:34:53,400 --> 00:34:55,020 ¿Qué vamos a hacer? 748 00:34:55,020 --> 00:34:59,000 Copiaremos los 13 bytes de bar en c, 749 00:34:59,000 --> 00:35:02,450 y así llenaremos todos los 12 bytes, más uno 750 00:35:02,450 --> 00:35:04,440 extra que no deberíamos tocar. 751 00:35:04,440 --> 00:35:06,350 Y si la cadena es incluso más larga que 13, 752 00:35:06,350 --> 00:35:11,610 si el enemigo escribió una oración larga, una frase, una palabra o lo que sea, 753 00:35:11,610 --> 00:35:14,000 sobrepasaremos los límites, 754 00:35:14,000 --> 00:35:15,870 de ese búfer o de ese arreglo. 755 00:35:15,870 --> 00:35:18,710 Si escribimos una palabra mucho más larga, ¿Qué aspecto tiene esto? 756 00:35:18,710 --> 00:35:23,780 como A-A-A-A-A-A-A, terminaríamos de sobrescribir estos 12 bytes, 757 00:35:23,780 --> 00:35:27,500 también estos cuatro bytes, o esos bytes verdes, sea cual fuesen, 758 00:35:27,500 --> 00:35:31,820 y lo más importante, los bytes rojos que describí como dirección de retorno. 759 00:35:31,820 --> 00:35:34,880 Ahora, A-A-A-A-A no causará ningún problema 760 00:35:34,880 --> 00:35:37,460 porque es una secuencia de caracteres aleatorios ASCII. 761 00:35:37,460 --> 00:35:39,920 Pero los caracteres al final del día son solo números, 762 00:35:39,920 --> 00:35:43,400 los números son solo bits, y los programas son solo bits. 763 00:35:43,400 --> 00:35:47,180 El peligro aquí, es que si eres un enemigo bastante sofisticado, alguien 764 00:35:47,180 --> 00:35:49,580 que conoce de programación, técnicamente 765 00:35:49,580 --> 00:35:52,430 escribirías un programa que hace algo extremadamente malo, como eliminar 766 00:35:52,430 --> 00:35:53,870 todos los archivos en un disco duro. 767 00:35:53,870 --> 00:35:55,676 O enviar spam a todos tus contactos. 768 00:35:55,676 --> 00:35:57,800 O algo por el estilo porque al final del día, 769 00:35:57,800 --> 00:36:00,800 el programa que acaba de escribir, son ceros y unos. 770 00:36:00,800 --> 00:36:04,730 Si convertimos ese programa de ceros y unos al correspondiente, 771 00:36:04,730 --> 00:36:10,010 incluso si los valores ASCII extraños, que podríamos escribir en un programa 772 00:36:10,010 --> 00:36:14,239 en la línea de comando en argv[1] al escribir los caracteres raros 773 00:36:14,239 --> 00:36:17,030 en las claves que no tendrán sentido para un humano que las lea. 774 00:36:17,030 --> 00:36:20,180 Pero esos caracteres ASCII en el contexto de un programa 775 00:36:20,180 --> 00:36:22,650 serán interpretados como un código. 776 00:36:22,650 --> 00:36:24,850 Si eres realmente bueno, 777 00:36:24,850 --> 00:36:26,350 no tanto que seas muy bueno, 778 00:36:26,350 --> 00:36:29,240 Si por mucho ensayo y error, sucede que 779 00:36:29,240 --> 00:36:32,360 al sobrescribir la dirección de retorno en un programa, 780 00:36:32,360 --> 00:36:34,580 puedes engañar a la computadora para que no regrese 781 00:36:34,580 --> 00:36:39,750 a main, pero que salte a la misma entrada que pasamos dentro del programa. 782 00:36:39,750 --> 00:36:42,930 A implica un ataque, como un código de ataque. 783 00:36:42,930 --> 00:36:46,520 Si somos inteligentes pasaríamos a un patrón apropiado de ceros 784 00:36:46,520 --> 00:36:50,600 y unos, que se convierten en ASCII para que el humano los escriba en el cursor, 785 00:36:50,600 --> 00:36:54,350 sobrescriba esta dirección de retorno y engañe al programa de computadora 786 00:36:54,350 --> 00:36:58,910 para que regrese a esta función no a main, parecida, a este byte de aquí. 787 00:36:58,910 --> 00:37:01,460 Y tal vez este byte, junto con todos estos otros, 788 00:37:01,460 --> 00:37:03,760 signifiquen, eliminar todos los archivos en el disco duro de este usuario, 789 00:37:03,760 --> 00:37:06,110 enviar spam a todos sus contactos. 790 00:37:06,110 --> 00:37:08,750 Esto es llamado explosión de desbordamiento de buffer, 791 00:37:08,750 --> 00:37:11,880 es increíblemente fatal y común, incluso en estos días. 792 00:37:11,880 --> 00:37:15,440 C no se usa comúnmente para muchos programas, pero sigue en todas partes. 793 00:37:15,440 --> 00:37:18,456 También hay otros lenguajes, como C ++, que se prestan a esto. 794 00:37:18,456 --> 00:37:20,330 Aunque esto todavía es un poco misterioso 795 00:37:20,330 --> 00:37:22,490 y no necesitamos preocuparnos demasiado por las direcciones en la pantalla, 796 00:37:22,490 --> 00:37:25,130 la amenaza fundamental aquí es que si no 797 00:37:25,130 --> 00:37:29,000 verificamos los límites de nuestros arreglos, cantidad de memoria asignada, 798 00:37:29,000 --> 00:37:32,570 y tocamos la memoria que no deberíamos, sucederían cosas muy malas. 799 00:37:32,570 --> 00:37:34,490 De hecho, le damos el control a cualquiera 800 00:37:34,490 --> 00:37:38,870 en Internet que usaría nuestro programa porque sería lo bastante inteligente 801 00:37:38,870 --> 00:37:45,491 para inyectar sus propios ceros y unos, en nuestro programa para su ejecución. 802 00:37:45,491 --> 00:37:45,990 Ok. 803 00:37:45,990 --> 00:37:49,670 Dios mío, esto es aterrador en las ciencias de la computación. 804 00:37:49,670 --> 00:37:53,247 ¿Qué haríamos para defendernos de esto más allá de no escribir errores, 805 00:37:53,247 --> 00:37:54,830 que nunca sucederían, cierto? 806 00:37:54,830 --> 00:37:57,050 Incluso los mejores y más avanzados programadores aún 807 00:37:57,050 --> 00:37:59,940 cometen errores, porque el software se vuelve cada vez más y más complicado. 808 00:37:59,940 --> 00:38:03,050 Tenemos eprintf, tenemos help50 y tenemos debug50 809 00:38:03,050 --> 00:38:05,900 pero hay muchas otras herramientas, como Valgrind 810 00:38:05,900 --> 00:38:09,320 que es una herramienta para detectar fugas de memoria en un programa 811 00:38:09,320 --> 00:38:11,190 y otros problemas relacionados con la memoria. 812 00:38:11,190 --> 00:38:14,690 Abriré este programa, memory.c, 813 00:38:14,690 --> 00:38:16,670 que se ve así. 814 00:38:16,670 --> 00:38:21,090 Veamos si no podemos desentrañar lo que falla en este programa. 815 00:38:21,090 --> 00:38:22,510 Aquí está el programa. 816 00:38:22,510 --> 00:38:26,240 817 00:38:26,240 --> 00:38:31,570 Incluye lib.h estándar, función f, función main, la función main llama a f 818 00:38:31,570 --> 00:38:32,310 y devuelve 0. 819 00:38:32,310 --> 00:38:34,060 No hay nada interesante aquí. 820 00:38:34,060 --> 00:38:35,200 ¿Qué hay en f? 821 00:38:35,200 --> 00:38:39,460 F en el lado derecho asigna espacio para 10 enteros, creo. 822 00:38:39,460 --> 00:38:45,880 Malloc devuelve la ubicación de ese fragmento en la memoria y la almacena en x, 823 00:38:45,880 --> 00:38:51,190 y la línea 8 es el error, creo. 824 00:38:51,190 --> 00:38:52,570 ¿Qué está mal en la línea 8? 825 00:38:52,570 --> 00:38:58,200 826 00:38:58,200 --> 00:39:00,150 Aquí primero. 827 00:39:00,150 --> 00:39:04,039 PÚBLICO: [INAUDIBLE] 828 00:39:04,039 --> 00:39:06,330 DAVID: Exacto, porque comenzamos a contar desde cero 829 00:39:06,330 --> 00:39:08,829 y porque le pedimos a la computadora espacio para 10 ints, 830 00:39:08,829 --> 00:39:09,930 que nos devuelve. 831 00:39:09,930 --> 00:39:14,430 Pero eso será accesible a través de [0], o como dicen, [9]. 832 00:39:14,430 --> 00:39:19,320 El [10] es como escribir un int más allá del búfer, conocido como 833 00:39:19,320 --> 00:39:20,610 una sobrecarga de búfer. 834 00:39:20,610 --> 00:39:23,610 Puede ser difícil ver esto, en especial cuando el programa no es 835 00:39:23,610 --> 00:39:27,360 tan corto como este, que está enterrado bajo una docena de líneas, cien 836 00:39:27,360 --> 00:39:29,010 líneas, miles de líneas de código. 837 00:39:29,010 --> 00:39:30,040 Las herramientas pueden ayudar. 838 00:39:30,040 --> 00:39:32,820 Proseguiré a hacer este programa con make memory. 839 00:39:32,820 --> 00:39:40,050 Continúo y ejecuto: valgrind ./memory Enter, 840 00:39:40,050 --> 00:39:43,110 el único inconveniente de este programa es que su resultado es completamente 841 00:39:43,110 --> 00:39:43,890 abrumador. 842 00:39:43,890 --> 00:39:47,910 Si no separamos algunos términos reconocibles, 843 00:39:47,910 --> 00:39:50,320 todo lo que se encuentra a la izquierda, es un poco una distracción. 844 00:39:50,320 --> 00:39:51,810 Esta es información de derechos de autor. 845 00:39:51,810 --> 00:39:54,090 Parece que las cosas interesantes suceden aquí. 846 00:39:54,090 --> 00:39:56,430 Veo el ajuste de tamaño 4, inválido. 847 00:39:56,430 --> 00:39:58,860 No estoy seguro de lo que significa todo esto, pero 848 00:39:58,860 --> 00:40:02,700 por alguna razón se relaciona con, oh, oh, línea 8 de memory.c, línea 849 00:40:02,700 --> 00:40:07,470 13, línea ocho, línea 13, parece que hay muchos errores en las mismos sitios. 850 00:40:07,470 --> 00:40:11,360 La ubicación tal y tal, cero bytes después de un bloque de sys 851 00:40:11,360 --> 00:40:14,340 40 alloc, es un poco difícil entender esto. 852 00:40:14,340 --> 00:40:18,330 Como siempre, al menos inicialmente, ejecutemos esto a través de help50 853 00:40:18,330 --> 00:40:20,280 y ver si ayudaría a desentrañar esto. 854 00:40:20,280 --> 00:40:21,900 Vemos el mismo resultado 855 00:40:21,900 --> 00:40:24,270 que reconoce algo familiar en amarillo, aquí. 856 00:40:24,270 --> 00:40:26,580 El ajuste del tamaño cuatro es inválido y resalta las líneas. 857 00:40:26,580 --> 00:40:29,010 Nuestra retroalimentación tipo TF es, parece que 858 00:40:29,010 --> 00:40:32,889 trata de modificar 4 bytes de memoria que no es nuestro, signo de interrogación? 859 00:40:32,889 --> 00:40:35,430 ¿intentamos almacenar algo más allá de los límites de un arreglo? 860 00:40:35,430 --> 00:40:38,420 Demos un vistazo más de cerca a la línea 8 de memory.c. 861 00:40:38,420 --> 00:40:40,170 Es una especie de trabalenguas, pero es 862 00:40:40,170 --> 00:40:44,110 porque practicamos leyendo cosas bastante misteriosas como esta. 863 00:40:44,110 --> 00:40:47,760 Extrajimos todos los detalles destacados, como la línea ocho de memory.c. 864 00:40:47,760 --> 00:40:53,040 la línea ocho de memory.c, como notamos, es la línea peligrosa. 865 00:40:53,040 --> 00:40:56,610 ¿Qué significaría tener un ajuste de tamaño cuatro inválido? 866 00:40:56,610 --> 00:41:01,260 Un int en el IEDE, ¿a cuántos bytes equivale? 867 00:41:01,260 --> 00:41:03,100 Cuatro, o 32 bits. 868 00:41:03,100 --> 00:41:07,560 El ajuste de tamaño 4 inválido significa que este int cero de aquí, es un int, 869 00:41:07,560 --> 00:41:10,710 es de cuatro bytes, se escribió de manera inválida, como decimos, 870 00:41:10,710 --> 00:41:11,940 en la ubicación incorrecta. 871 00:41:11,940 --> 00:41:16,060 Esta es la manera bastante concisa de Valgrind de comunicar esa idea. 872 00:41:16,060 --> 00:41:17,850 Aquí tenemos una explicación. 873 00:41:17,850 --> 00:41:19,000 ¿Cómo puedo arreglar esto? 874 00:41:19,000 --> 00:41:22,620 Si mi intención era actualizar la última área allí, 875 00:41:22,620 --> 00:41:32,610 a continuación haré: make memory, Enter, ./valgrind ./memory Enter. 876 00:41:32,610 --> 00:41:37,710 Y ahora esto es algo bueno, excepto que hicimos algunos progresos. 877 00:41:37,710 --> 00:41:39,750 Me desplazaré hacia arriba para ajustarlo más en la pantalla. 878 00:41:39,750 --> 00:41:42,840 Me deshice de ese mensaje, ajuste de tamaño cuatro inválido, 879 00:41:42,840 --> 00:41:44,910 esto tampoco suena bien. 880 00:41:44,910 --> 00:41:49,450 se perdieron 40 bytes de un bloque en el registro perdido uno de uno, 881 00:41:49,450 --> 00:41:49,950 ¿correcto? 882 00:41:49,950 --> 00:41:51,366 Necesito un poco de ayuda con eso. 883 00:41:51,366 --> 00:41:54,630 Permítanme aplicar help50 de nuevo hasta que me familiarice con la sintaxis. 884 00:41:54,630 --> 00:41:57,360 Se destacó ese fragmento de salida. 885 00:41:57,360 --> 00:41:59,520 Parece que nuestro programa filtró 40 bytes de memoria. 886 00:41:59,520 --> 00:42:02,550 ¿Olvidamos liberar la memoria que asignamos por medio de malloc? 887 00:42:02,550 --> 00:42:05,830 Echemos un vistazo más de cerca a la línea siete de memory.c. 888 00:42:05,830 --> 00:42:07,290 Hagamos exactamente eso. 889 00:42:07,290 --> 00:42:11,580 La línea 7 de memory.c, Ok, aquí es donde está malloc la memoria. 890 00:42:11,580 --> 00:42:15,930 Por comentarios en help50, al parecer, ¿qué es lo que no hice? 891 00:42:15,930 --> 00:42:16,500 Liberarla. 892 00:42:16,500 --> 00:42:18,958 La liberación es bastante sencilla, 893 00:42:18,958 --> 00:42:20,370 háganla siempre que lo recuerden. 894 00:42:20,370 --> 00:42:22,590 Lo hace con tan solo, pasar el mismo puntero. 895 00:42:22,590 --> 00:42:24,350 No necesitamos recordar cada cuándo es. 896 00:42:24,350 --> 00:42:27,190 El sistema operativo se encarga de recordar cada cuando es. 897 00:42:27,190 --> 00:42:29,730 Ahora, si hago make memory. 898 00:42:29,730 --> 00:42:35,430 Vuelvo a escribir: valgrind ./memory, Enter, un resumen apilado, 899 00:42:35,430 --> 00:42:36,560 se liberó todo el montón de bloques. 900 00:42:36,560 --> 00:42:37,740 No hay posibles fugas. 901 00:42:37,740 --> 00:42:40,020 No veo nada particularmente preocupante. 902 00:42:40,020 --> 00:42:41,460 Ahora el programa está libre de errores. 903 00:42:41,460 --> 00:42:43,530 Valgrind es otra herramienta en nuestra caja de herramientas 904 00:42:43,530 --> 00:42:46,350 que no nos ayuda a encontrar los errores lógicos, per se. 905 00:42:46,350 --> 00:42:50,130 Ayuda a encontrar errores relacionados con la memoria, que serían lógicos. 906 00:42:50,130 --> 00:42:53,670 Nos ayuda a afinarlos y verlos de una manera contraria 907 00:42:53,670 --> 00:42:57,940 como humanos, si se enterraron bajo muchas, muchas líneas de código. 908 00:42:57,940 --> 00:43:01,050 Notemos, brevemente, en la salida de Valgrin, 909 00:43:01,050 --> 00:43:04,240 en varios ejemplos, hay todos estos números raros. 910 00:43:04,240 --> 00:43:07,780 Si vuelvo a la versión original, de hace un momento, 911 00:43:07,780 --> 00:43:10,050 que estuvo lleno de errores de diferentes formas. 912 00:43:10,050 --> 00:43:13,410 Al volver a ejecutar make, y volver a ejecutar valgrind, 913 00:43:13,410 --> 00:43:15,780 veremos un montón de cosas como esta. 914 00:43:15,780 --> 00:43:21,870 En OX tal y tal, en OX tal y tal, en OX tal y tal, ¿qué denotó OX la última vez? 915 00:43:21,870 --> 00:43:23,970 El hexadecimal, que de manera breve, es una 916 00:43:23,970 --> 00:43:27,450 manera extraña de representar números, en general ubicaciones en la memoria. 917 00:43:27,450 --> 00:43:32,340 De manera específica, dice que la línea 13 de memory.c 918 00:43:32,340 --> 00:43:35,400 pasa a usar memoria en esta ubicación. 919 00:43:35,400 --> 00:43:37,917 No es tan útil para nosotros los programadores. 920 00:43:37,917 --> 00:43:39,000 Pero, es por eso que lo vemos. 921 00:43:39,000 --> 00:43:41,370 Valgrind, sin duda, es una herramienta más avanzada, 922 00:43:41,370 --> 00:43:45,330 que dice las ubicaciones en la memoria, en las herramientas e incluso en depuradores 923 00:43:45,330 --> 00:43:48,810 que tiende a escribir con notación hexadecimal como esa. 924 00:43:48,810 --> 00:43:50,700 Desde luego, que vieron hexadecimales convertidos. 925 00:43:50,700 --> 00:43:53,070 Como esos primeros tres bytes en un JPEG, 926 00:43:53,070 --> 00:43:56,310 que normalmente piensa en usar hexadecimales como este. 927 00:43:56,310 --> 00:43:59,730 A pesar de que esto parece nuevo, es exactamente la misma idea. 928 00:43:59,730 --> 00:44:02,170 Pensé que quizás provocaría con una broma 929 00:44:02,170 --> 00:44:07,140 que solo un especialista en sistemas entendería. 930 00:44:07,140 --> 00:44:10,800 Esa es una buena que da la vuelta cada año. 931 00:44:10,800 --> 00:44:13,350 Por supuesto, alude solo a estas direcciones. 932 00:44:13,350 --> 00:44:16,300 Propondré otra técnica de depuración y explicaré como, 933 00:44:16,300 --> 00:44:18,670 qué diablos pasa en el escenario hoy. 934 00:44:18,670 --> 00:44:22,080 Tenemos debug50, que es una herramienta para depurar y recorrer 935 00:44:22,080 --> 00:44:22,830 a lo largo del código. 936 00:44:22,830 --> 00:44:24,750 Y aunque esto es tonto, en realidad hay 937 00:44:24,750 --> 00:44:28,180 esta cosa en el mundo de la programación, el pato de goma de la depuración. 938 00:44:28,180 --> 00:44:31,175 Esto es, en ausencia de un TF o un CA para rebotar ideas, 939 00:44:31,175 --> 00:44:34,050 esto es en ausencia de un compañero de cuarto o compañero de cuarto alrededor 940 00:44:34,050 --> 00:44:36,390 que quiera hablar contigo sobre su código. 941 00:44:36,390 --> 00:44:40,450 Se recomienda que si tienen algún error en su programa, 942 00:44:40,450 --> 00:44:42,900 que guarden algo como esto en su escritorio. 943 00:44:42,900 --> 00:44:45,780 Y en ausencia de compañeros de cuarto y amigos 944 00:44:45,780 --> 00:44:49,620 y con suerte a puertas cerradas, hablen con el pato de goma. 945 00:44:49,620 --> 00:44:53,100 Me siento tonto diciendo esto, pero hay un artículo de Wikipedia 946 00:44:53,100 --> 00:44:54,870 sobre esto, es una cosa real. 947 00:44:54,870 --> 00:44:57,450 La idea aquí es que si alguna vez han estado en horas de oficina 948 00:44:57,450 --> 00:44:58,710 o chatean con un amigo TFer 949 00:44:58,710 --> 00:45:01,290 es como hablar de tu código y hablar sobre qué 950 00:45:01,290 --> 00:45:04,710 es lo que crees que hace tu código, muy a menudo ese acto 951 00:45:04,710 --> 00:45:08,430 de decir algo y escucharte a ti mismo decir eso puede ayudar a reforzarlo, 952 00:45:08,430 --> 00:45:10,200 lo que tu código hace. 953 00:45:10,200 --> 00:45:12,450 O si se dan cuenta verbalmente, espera un minuto. 954 00:45:12,450 --> 00:45:14,910 Lo que dije no parece alinearse con el código, 955 00:45:14,910 --> 00:45:16,685 finalmente esa bombilla se apaga. 956 00:45:16,685 --> 00:45:18,060 No tiene que ser un pato. 957 00:45:18,060 --> 00:45:20,643 Quiero decir, pueden hablar con la pared, pero eso es un poco extraño. 958 00:45:20,643 --> 00:45:24,090 Al menos esta es una personificación de tener a alguien como un colega 959 00:45:24,090 --> 00:45:25,164 para hablar. 960 00:45:25,164 --> 00:45:27,330 Hoy al final o durante el descanso por todos los medios, 961 00:45:27,330 --> 00:45:30,715 tomen un pato de goma el depurador y guárdenlo en tu estante. 962 00:45:30,715 --> 00:45:32,340 No tiene que ser tan grande. 963 00:45:32,340 --> 00:45:34,301 Esta es una técnica de depuración genuina. 964 00:45:34,301 --> 00:45:36,300 En la falta de comprensión de algo, 965 00:45:36,300 --> 00:45:39,870 no necesariamente se dirigen al discurso CS50 o a ​​las horas de oficina 966 00:45:39,870 --> 00:45:41,220 o a secciones, o similares. 967 00:45:41,220 --> 00:45:43,350 Intenten hablar consigo mismos a través de eso, 968 00:45:43,350 --> 00:45:45,180 incluso si se sienten un poco tontos. 969 00:45:45,180 --> 00:45:47,520 Si se sienten tontos, solo mírenlo 970 00:45:47,520 --> 00:45:49,530 y hablen consigo mismos tal vez en su cabeza. 971 00:45:49,530 --> 00:45:54,120 Ese tipo de enunciación de lo que su código hace o debería hacer 972 00:45:54,120 --> 00:45:57,516 con suerte ayudará a que las bombillas se apaguen. 973 00:45:57,516 --> 00:45:59,640 Finalmente, pueden mantenerlos en su estante 974 00:45:59,640 --> 00:46:01,655 y también quitar esa rueda de entrenamiento. 975 00:46:01,655 --> 00:46:03,780 Tomemos nuestro descanso de cinco minutos. 976 00:46:03,780 --> 00:46:08,190 Si desean, tomen un pato y volveremos con más. 977 00:46:08,190 --> 00:46:09,400 Muy bien. 978 00:46:09,400 --> 00:46:11,920 Volvimos, y seguimos pensando en la memoria. 979 00:46:11,920 --> 00:46:14,756 Esto en general se presenta como tener direcciones, 980 00:46:14,756 --> 00:46:17,380 pero, por supuesto, aclaramos un poco que tenemos 981 00:46:17,380 --> 00:46:19,540 más de un lienzo a nuestra disposición. 982 00:46:19,540 --> 00:46:21,880 Ahora, hablamos sobre tener cosas de vuelta 983 00:46:21,880 --> 00:46:23,770 para recordar en la memoria. 984 00:46:23,770 --> 00:46:25,300 Eso no necesita ser el caso. 985 00:46:25,300 --> 00:46:28,390 Como lo que ahora tenemos con los punteros y con malloc, 986 00:46:28,390 --> 00:46:31,360 este tipo de funciones son capaces de obtener memoria desde cualquier lugar 987 00:46:31,360 --> 00:46:36,050 que queremos y de alguna manera, las unimos o conectamos estas cosas. 988 00:46:36,050 --> 00:46:39,730 ¿Cómo lo hacemos con los ingredientes que tenemos? 989 00:46:39,730 --> 00:46:41,230 ¿Por qué deberíamos querer? 990 00:46:41,230 --> 00:46:43,822 Es así como representamos algo similar a un arreglo. 991 00:46:43,822 --> 00:46:46,030 Un arreglo es un fragmento contiguo de memoria 992 00:46:46,030 --> 00:46:48,730 donde almacena cosas una tras otra, tras otra, tras otra. 993 00:46:48,730 --> 00:46:52,840 Supongamos que puse seis cosas en este arreglo, seis números, uno, dos, 994 00:46:52,840 --> 00:46:54,430 tres, cuatro, cinco, seis. 995 00:46:54,430 --> 00:46:56,710 ¿Qué sucede si trato de poner siete en este arreglo? 996 00:46:56,710 --> 00:46:59,605 997 00:46:59,605 --> 00:47:01,480 ¿En qué tengo que pensar o preocuparme? 998 00:47:01,480 --> 00:47:04,524 999 00:47:04,524 --> 00:47:06,440 Tocando la memoria que no se me permite tocar. 1000 00:47:06,440 --> 00:47:08,850 Será mejor que no lo ponga aquí. 1001 00:47:08,850 --> 00:47:11,120 ¿Y si siete deben ir en este arreglo? 1002 00:47:11,120 --> 00:47:12,620 Bien, no tengo muchas opciones. 1003 00:47:12,620 --> 00:47:16,771 Si lleno el espacio, debo sobrescribir algún valor o ponerlo 1004 00:47:16,771 --> 00:47:18,770 en algún lugar donde no debería estar, y eso nunca debería 1005 00:47:18,770 --> 00:47:21,530 ser una opción porque el programa podría o se bloqueará. 1006 00:47:21,530 --> 00:47:25,080 De manera alternada, asignaría más memoria. 1007 00:47:25,080 --> 00:47:26,370 ¿Cómo hago eso? 1008 00:47:26,370 --> 00:47:29,660 Si al inicio asigné este arreglo para que fuera de tamaño seis, 1009 00:47:29,660 --> 00:47:37,428 Podría codificar y asignar un nuevo arreglo de tamaño siete y hacer, ¿qué? 1010 00:47:37,428 --> 00:47:38,790 PÚBLICO: [INAUDIBLE] 1011 00:47:38,790 --> 00:47:40,831 DAVID: Sí, agrego todos los números y siete. 1012 00:47:40,831 --> 00:47:44,040 Tomaré este arreglo, puedo darme otro en otra parte de la memoria, 1013 00:47:44,040 --> 00:47:48,136 copio los valores de antiguo al nuevo, después quizás libere el anterior. 1014 00:47:48,136 --> 00:47:50,760 Sigo con mi vida porque ahora tengo suficiente memoria. 1015 00:47:50,760 --> 00:47:52,189 Eso soluciona el problema. 1016 00:47:52,189 --> 00:47:53,980 Si lo implementamos en el código de manera correcta, 1017 00:47:53,980 --> 00:47:58,050 sería correcto, suponiendo que hay suficiente memoria en la computadora. 1018 00:47:58,050 --> 00:48:01,387 ¿Por qué, sin duda, es un mal diseño? 1019 00:48:01,387 --> 00:48:02,720 PÚBLICO: Es una pérdida de espacio. 1020 00:48:02,720 --> 00:48:05,078 DAVID: ¿Cómo qué es una pérdida de espacio? 1021 00:48:05,078 --> 00:48:09,047 PÚBLICO: [INAUDIBLE] 1022 00:48:09,047 --> 00:48:11,880 DAVID: Sí, aunque no me quedo con ambos en la historia 1023 00:48:11,880 --> 00:48:14,550 Digo, es bastante ineficiente en el sentido de que 1024 00:48:14,550 --> 00:48:18,720 uso el doble de memoria de la que necesito solo para reducirla. 1025 00:48:18,720 --> 00:48:19,740 ¿Qué otra cosa? 1026 00:48:19,740 --> 00:48:21,323 Sí. 1027 00:48:21,323 --> 00:48:24,469 PÚBLICO: [INAUDIBLE] 1028 00:48:24,469 --> 00:48:27,260 DAVID: Sí, sí quiero cambiar el tamaño del arreglo otra vez, 1029 00:48:27,260 --> 00:48:31,190 ya sea más grande o más pequeño, o si elimino elementos de la lista, 1030 00:48:31,190 --> 00:48:34,100 Tengo que asignar memoria nueva, lo cual es un desperdicio 1031 00:48:34,100 --> 00:48:36,530 y más importante, es espacio ineficiente. 1032 00:48:36,530 --> 00:48:38,830 ¿En qué otro sentido es ineficiente? 1033 00:48:38,830 --> 00:48:39,330 Tiempo, ¿por qué? 1034 00:48:39,330 --> 00:48:41,699 ¿De dónde viene el tiempo? 1035 00:48:41,699 --> 00:48:43,920 PÚBLICO: [INAUDIBLE] 1036 00:48:43,920 --> 00:48:45,860 DAVID: Esa es una notación asintótica. 1037 00:48:45,860 --> 00:48:49,330 Al copiar algo de un arreglo a otro sería en gran O ¿de qué? 1038 00:48:49,330 --> 00:48:52,434 1039 00:48:52,434 --> 00:48:53,350 Van de lado, sí. 1040 00:48:53,350 --> 00:48:55,930 Si hacemos el tamaño genérico como n, es como una gran O de N. 1041 00:48:55,930 --> 00:48:58,660 Es una operación de tiempo lineal, que no es horrible, ¿cierto? 1042 00:48:58,660 --> 00:49:00,220 N al cuadrado está mal. 1043 00:49:00,220 --> 00:49:03,910 Lineal nunca ha sido malo, pero ya sabemos que log n es mejor, 1044 00:49:03,910 --> 00:49:05,500 el tiempo constante es mejor 1045 00:49:05,500 --> 00:49:09,340 Al perder cualquier cantidad de tiempo no se siente como un diseño óptimo. 1046 00:49:09,340 --> 00:49:12,640 Que todo esté en función de los arreglos, que sean 1047 00:49:12,640 --> 00:49:16,780 de un tamaño fijo y contiguo en la memoria, de manera consecutiva. 1048 00:49:16,780 --> 00:49:19,580 Se diría que hay otro problema que podría ocurrir. 1049 00:49:19,580 --> 00:49:21,850 Que no es tanto si tienen un arreglo muy pequeño. 1050 00:49:21,850 --> 00:49:25,540 Pero, qué pasa si tienen una gran cantidad de memoria disponible 1051 00:49:25,540 --> 00:49:29,200 pero en tamaño de cinco o seis incrementos? 1052 00:49:29,200 --> 00:49:31,000 Por cualquier motivo, su computadora 1053 00:49:31,000 --> 00:49:33,916 utiliza parte de esta memoria, esta memoria, esta memoria, esta memoria, 1054 00:49:33,916 --> 00:49:36,850 y si sumamos toda la memoria disponible, hay mucho espacio libre 1055 00:49:36,850 --> 00:49:39,640 pero siempre están separados por la memoria que está en uso. 1056 00:49:39,640 --> 00:49:42,790 Tal vez esta memoria esté libre, hay un poco que está en uso. 1057 00:49:42,790 --> 00:49:44,780 Esta memoria está libre, hay un poco en uso. 1058 00:49:44,780 --> 00:49:47,380 Nuestra memoria está, entre comillas, muy fragmentada. 1059 00:49:47,380 --> 00:49:50,680 Tenemos mucha memoria disponible pero no es contigua. 1060 00:49:50,680 --> 00:49:55,420 No podemos, en este modelo, asignar un arreglo de tamaño siete si no tenemos 1061 00:49:55,420 --> 00:49:57,910 esa memoria continua disponible. 1062 00:49:57,910 --> 00:50:00,624 No es una gran preocupación dada la memoria suficiente, 1063 00:50:00,624 --> 00:50:02,290 a menos que algo pudiera surgir. 1064 00:50:02,290 --> 00:50:04,600 A continuación, presentaremos la solución. 1065 00:50:04,600 --> 00:50:06,610 Algo denominado una lista vinculada. 1066 00:50:06,610 --> 00:50:08,860 El tipo de nombre describe lo que es. 1067 00:50:08,860 --> 00:50:13,120 Es una lista de números, pero vinculada por medio de estas flechas. 1068 00:50:13,120 --> 00:50:14,440 Ya usamos estas flechas antes. 1069 00:50:14,440 --> 00:50:18,620 En las imágenes pasadas, ¿qué representamos con las flechas? 1070 00:50:18,620 --> 00:50:19,480 Sí, punteros. 1071 00:50:19,480 --> 00:50:24,070 Ahora que tenemos la expresividad de los punteros, de tipo digital podemos 1072 00:50:24,070 --> 00:50:28,220 unir nuestras estructuras de datos si gastamos un poco más de memoria. 1073 00:50:28,220 --> 00:50:30,510 No resolvimos el problema que identificamos, 1074 00:50:30,510 --> 00:50:31,510 cual fue el uso del espacio 1075 00:50:31,510 --> 00:50:33,550 Si somos tolerantes con eso y si 1076 00:50:33,550 --> 00:50:35,800 tenemos suficiente memoria a nuestra disposición y podemos 1077 00:50:35,800 --> 00:50:38,740 darnos el lujo de gastarlo, ¿por qué no almacenamos para cada número 1078 00:50:38,740 --> 00:50:42,490 no números, también el espacio para un puntero? 1079 00:50:42,490 --> 00:50:45,010 Cada una de las cajas que dibujé aquí ahora no solo 1080 00:50:45,010 --> 00:50:47,160 tienen un cuadro para el número n en sí. 1081 00:50:47,160 --> 00:50:50,830 En realidad tiene dos cajas juntas, una para n y una para algo 1082 00:50:50,830 --> 00:50:54,250 que a continuación, será un puntero 1083 00:50:54,250 --> 00:50:58,060 o de manera equivalente la ubicación del siguiente nodo, la llamaremos, 1084 00:50:58,060 --> 00:51:00,050 la siguiente caja en esta lista. 1085 00:51:00,050 --> 00:51:03,250 A pesar de que lo dibujamos aquí con mucho ingenio de izquierda a derecha, 1086 00:51:03,250 --> 00:51:05,980 técnicamente estas cajas estarían en cualquier lugar de la memoria, 1087 00:51:05,980 --> 00:51:07,955 específicamente en el montón, proseguiremos a ver. 1088 00:51:07,955 --> 00:51:09,580 Pero no tienen que estar consecutivos. 1089 00:51:09,580 --> 00:51:12,744 Por el hecho de que haya estos espacios entre los nodos 1090 00:51:12,744 --> 00:51:15,160 deliberadamente se dibuja una imagen de que estas cosas no tienen 1091 00:51:15,160 --> 00:51:16,840 estar consecutivas para no retroceder más. 1092 00:51:16,840 --> 00:51:17,830 Pueden estar en cualquier lado. 1093 00:51:17,830 --> 00:51:21,490 Ahora, supongamos que tengo estos cinco números, del nueve al 34. 1094 00:51:21,490 --> 00:51:24,400 Supongamos que quiero agregar otro número. 1095 00:51:24,400 --> 00:51:25,210 ¿Dónde los coloco? 1096 00:51:25,210 --> 00:51:27,130 Parece que no tienen espacio. 1097 00:51:27,130 --> 00:51:31,535 Pero con base en esta imagen, ¿en cuánto deducimos que diseñaremos esto? 1098 00:51:31,535 --> 00:51:32,511 PÚBLICO: [INAUDIBLE] 1099 00:51:32,511 --> 00:51:35,260 DAVID: Sí, ¿por qué no asignamos espacio para otro? 1100 00:51:35,260 --> 00:51:37,676 No ajustaría en el tablero, pero, ¿a quién le importa? 1101 00:51:37,676 --> 00:51:38,620 Podemos ponerlo aquí. 1102 00:51:38,620 --> 00:51:43,840 Coloque el nuevo número y agregue una línea, una flecha de aquí a allá. 1103 00:51:43,840 --> 00:51:47,270 Esto será lo que llamamos una lista vinculada, 1104 00:51:47,270 --> 00:51:49,060 y nos da dinamismo. 1105 00:51:49,060 --> 00:51:52,120 Nos da la capacidad de crecer o reducir la estructura de datos, direccionando 1106 00:51:52,120 --> 00:51:53,620 nuestro interés, no necesariamente el suyo. 1107 00:51:53,620 --> 00:51:57,490 Todavía es un desperdicio de espacio, pero obtenemos beneficios para ambos, 1108 00:51:57,490 --> 00:52:00,130 nuestros intereses con el tiempo son mucho mejores porque no 1109 00:52:00,130 --> 00:52:01,930 perdemos el tiempo copiando los valores. 1110 00:52:01,930 --> 00:52:03,710 Solo agregamos los valores. 1111 00:52:03,710 --> 00:52:06,520 Si queremos sumarlo o restarlo, solo hacemos tanto trabajo 1112 00:52:06,520 --> 00:52:08,320 como tratar de sumar o restar. 1113 00:52:08,320 --> 00:52:10,660 No tenemos que preocuparnos por arreglar todo. 1114 00:52:10,660 --> 00:52:12,524 Pero hay algo de complejidad aquí. 1115 00:52:12,524 --> 00:52:14,440 Y dado que tenemos un montón de estos, 1116 00:52:14,440 --> 00:52:16,150 lo que haría que los problemas en cinco fueran un poco más fáciles, 1117 00:52:16,150 --> 00:52:17,900 si aún no hemos acabado, ¿quién lo hizo? 1118 00:52:17,900 --> 00:52:21,820 ¿Conseguiremos a seis voluntarios para una demostración? 1119 00:52:21,820 --> 00:52:22,810 ¿Seis voluntarios? 1120 00:52:22,810 --> 00:52:23,410 Bien. 1121 00:52:23,410 --> 00:52:26,331 Vengan aquí, justo enfrente. 1122 00:52:26,331 --> 00:52:26,830 Muy bien. 1123 00:52:26,830 --> 00:52:30,120 Bien, vengan a aquí. 1124 00:52:30,120 --> 00:52:35,500 Ven, tenemos dos, tres, por allá, cuatro. 1125 00:52:35,500 --> 00:52:37,080 Nadie de aquí hoy. 1126 00:52:37,080 --> 00:52:38,520 Ok, Ok, cinco. 1127 00:52:38,520 --> 00:52:39,510 OK, seis. 1128 00:52:39,510 --> 00:52:40,540 Ok, seis, seis. 1129 00:52:40,540 --> 00:52:41,110 Vengan. 1130 00:52:41,110 --> 00:52:41,260 Muy bien. 1131 00:52:41,260 --> 00:52:42,730 Guardaremos esto hasta el final. 1132 00:52:42,730 --> 00:52:45,792 Chicos les daré esto, mientras tanto, estos números. 1133 00:52:45,792 --> 00:52:47,500 Si no les importa sostener los números. 1134 00:52:47,500 --> 00:52:49,660 Quiero que vayas allá a la izquierda, 1135 00:52:49,660 --> 00:52:55,990 solo ordénense a sí mismos como en la imagen en la pantalla, Ok serás 17. 1136 00:52:55,990 --> 00:52:57,370 Veamos, veamos, nueve. 1137 00:52:57,370 --> 00:52:59,110 Pude darles demasiados números. 1138 00:52:59,110 --> 00:53:04,200 Ok, separaré eso y te daré el nueve en su lugar, si es posible. 1139 00:53:04,200 --> 00:53:06,640 Y te daré, veamos. 1140 00:53:06,640 --> 00:53:07,750 ¿Tienes el 17? 1141 00:53:07,750 --> 00:53:08,822 OK, 17. 1142 00:53:08,822 --> 00:53:11,780 Sí, haré que se den la vuelta, si no les importa. 1143 00:53:11,780 --> 00:53:15,560 22, y después 26. 1144 00:53:15,560 --> 00:53:16,370 Y, ¿qué tenemos? 1145 00:53:16,370 --> 00:53:19,180 20, 34. 1146 00:53:19,180 --> 00:53:20,030 34. 1147 00:53:20,030 --> 00:53:22,690 OK, chicas ustedes serán un poco especiales. 1148 00:53:22,690 --> 00:53:27,550 ¿Quién quiere ser primera? 1149 00:53:27,550 --> 00:53:29,470 OK, así que serás primera. 1150 00:53:29,470 --> 00:53:31,732 Y, ¿quién quiere ser temporal? 1151 00:53:31,732 --> 00:53:33,190 OK, serás temporal, muy bien. 1152 00:53:33,190 --> 00:53:33,910 Vengan acá. 1153 00:53:33,910 --> 00:53:36,618 OK, vengan aquí, y si ustedes pudieran acercarse un poco más. 1154 00:53:36,618 --> 00:53:41,110 Entonces, tenemos 9, 17, 22, 26, 34, y sepárense como un pie entre ustedes. 1155 00:53:41,110 --> 00:53:45,340 Usen sus brazos izquierdos para representar y visualizar a los punteros, 1156 00:53:45,340 --> 00:53:47,397 es decir, quién está vinculado a quién. 1157 00:53:47,397 --> 00:53:49,980 OK, por qué no solo señalas, muy deliberadamente hacia abajo. 1158 00:53:49,980 --> 00:53:51,404 ¿Cuál es tu nombre? 1159 00:53:51,404 --> 00:53:51,945 NAZLI: Nazli. 1160 00:53:51,945 --> 00:53:52,170 DAVID: Nazli. 1161 00:53:52,170 --> 00:53:54,270 La mano izquierda de Nazli será un puntero nulo. 1162 00:53:54,270 --> 00:53:55,080 No está apuntando a nadie, 1163 00:53:55,080 --> 00:53:58,038 solo señala hacia el suelo, como si estuviera electrificado. 1164 00:53:58,038 --> 00:53:58,620 OK. 1165 00:53:58,620 --> 00:54:01,300 Ahora solo tenemos que tener un primer nodo. 1166 00:54:01,300 --> 00:54:02,305 ¿Cómo te llamas? 1167 00:54:02,305 --> 00:54:02,660 OLIVIA: Olivia. 1168 00:54:02,660 --> 00:54:05,550 DAVID: Olivia es un poco especial, en su papel tiene una palabra 1169 00:54:05,550 --> 00:54:06,720 y no solo un número. 1170 00:54:06,720 --> 00:54:09,480 Ella representa una variable distinta llamada primero. 1171 00:54:09,480 --> 00:54:11,940 Porque esto captura a la lista enlazada, 1172 00:54:11,940 --> 00:54:15,630 es eso que no recuerdan, a modo de la ubicación de un contiguo 1173 00:54:15,630 --> 00:54:16,620 fragmento de memoria. 1174 00:54:16,620 --> 00:54:20,500 Recuerden una lista vinculada por medio de la ubicación del primer nodo en la lista 1175 00:54:20,500 --> 00:54:21,000 vinculada. 1176 00:54:21,000 --> 00:54:21,490 Y, ¿cuál es tu nombre? 1177 00:54:21,490 --> 00:54:22,380 ACHMED: Achmed. 1178 00:54:22,380 --> 00:54:23,213 DAVID: Achmed. 1179 00:54:23,213 --> 00:54:26,427 Así que, Achmed es el primer nodo en la lista en este momento. 1180 00:54:26,427 --> 00:54:28,260 El brazo izquierdo de Olivia estará apuntando 1181 00:54:28,260 --> 00:54:32,040 a Achmed para representar que él es el primer nodo en la lista. 1182 00:54:32,040 --> 00:54:33,770 OK, ¿cuál es tu nombre? 1183 00:54:33,770 --> 00:54:34,430 JESS: Jess. 1184 00:54:34,430 --> 00:54:34,570 DAVID: Jess. 1185 00:54:34,570 --> 00:54:37,590 Usaremos a Jess en solo un momento para completar algunas operaciones. 1186 00:54:37,590 --> 00:54:42,450 Supongamos que queremos insertar algún valor en esta lista, 1187 00:54:42,450 --> 00:54:44,670 como el número 55. 1188 00:54:44,670 --> 00:54:47,800 De acuerdo, el número 55 requerirá un poco de inteligencia 1189 00:54:47,800 --> 00:54:48,300 aquí. 1190 00:54:48,300 --> 00:54:50,640 Necesito un lugar para almacenar esto. 1191 00:54:50,640 --> 00:54:51,389 Necesito un malloc. 1192 00:54:51,389 --> 00:54:52,680 Muy bien, eres una voluntaria. 1193 00:54:52,680 --> 00:54:53,070 ¿Cómo te llamas? 1194 00:54:53,070 --> 00:54:53,760 STELLA: Stella. 1195 00:54:53,760 --> 00:54:55,093 DAVID: Stella, sube. 1196 00:54:55,093 --> 00:54:57,030 Así que Stella es malloc. 1197 00:54:57,030 --> 00:55:01,344 Almacenaremos el número 55 en el nodo de Stella. 1198 00:55:01,344 --> 00:55:04,260 Si pudieras apuntar tu mano izquierda a cualquier lugar. 1199 00:55:04,260 --> 00:55:06,670 Es una especie de valor de basura. 1200 00:55:06,670 --> 00:55:08,399 Ok, gracias. 1201 00:55:08,399 --> 00:55:09,690 Otra vez, ¿cuál es tu nombre? 1202 00:55:09,690 --> 00:55:10,110 JESS: Jess. 1203 00:55:10,110 --> 00:55:10,860 DAVID: Jess. 1204 00:55:10,860 --> 00:55:13,650 OK, Jess nos ayudará a encontrar el espacio correcto. 1205 00:55:13,650 --> 00:55:17,310 Obviamente podemos ver a dónde pertenece 55 si mantenemos esto ordenado. 1206 00:55:17,310 --> 00:55:19,200 Pero las computadoras no tienen ese lujo. 1207 00:55:19,200 --> 00:55:21,300 Además, ya no tenemos acceso aleatorio. 1208 00:55:21,300 --> 00:55:25,630 No podemos solo brincar al [0], [1], [2] porque existen estos huecos entre 1209 00:55:25,630 --> 00:55:26,130 ellos. 1210 00:55:26,130 --> 00:55:28,530 Y para que quede más claro, ¿pueden todos los demás 1211 00:55:28,530 --> 00:55:32,050 dar un paso adelante o atrás para que se vea un poco raro? 1212 00:55:32,050 --> 00:55:34,986 Ya no podemos indexar en esta estructura de datos 1213 00:55:34,986 --> 00:55:36,360 porque, una vez más, no es un arreglo. 1214 00:55:36,360 --> 00:55:37,230 No es consecutivo. 1215 00:55:37,230 --> 00:55:40,021 Estas cosas podrían estar en cualquier lugar de la memoria y son los punteros 1216 00:55:40,021 --> 00:55:43,280 que están vinculando a todos juntos. 1217 00:55:43,280 --> 00:55:47,910 Jess ahora señalará al punto inicial exactamente lo mismo 1218 00:55:47,910 --> 00:55:50,610 que Olivia señala en la misma dirección o Achmed. 1219 00:55:50,610 --> 00:55:53,070 De acuerdo, ahora tenemos un poco de redundancia. 1220 00:55:53,070 --> 00:55:55,440 Pero supongamos que queremos insertar 55. 1221 00:55:55,440 --> 00:55:57,750 ¿Qué tipo de lógica, cuál es el pseudocódigo aquí para que Jess 1222 00:55:57,750 --> 00:56:02,430 encuentre la ubicación de Stella? 1223 00:56:02,430 --> 00:56:03,390 ¿Qué debería hacer Jess? 1224 00:56:03,390 --> 00:56:04,058 Sí 1225 00:56:04,058 --> 00:56:05,437 PÚBLICO: [INAUDIBLE] 1226 00:56:05,437 --> 00:56:08,020 DAVID: OK, continúa hasta que ella encuentre el puntero nulo, 1227 00:56:08,020 --> 00:56:11,940 o específicamente, hasta que encuentre el puntero nulo o la ubicación correcta 1228 00:56:11,940 --> 00:56:13,816 para este número, si queremos mantenerlo ordenado. 1229 00:56:13,816 --> 00:56:14,523 Así que hagámoslo. 1230 00:56:14,523 --> 00:56:15,840 Entonces estás señalando a Achmed. 1231 00:56:15,840 --> 00:56:19,620 El número nueve no es mayor que 55. 1232 00:56:19,620 --> 00:56:22,330 Entonces Stella proviene de Achmed. 1233 00:56:22,330 --> 00:56:24,060 ¿Qué es lo que haremos? 1234 00:56:24,060 --> 00:56:25,980 Bien, señala a María. 1235 00:56:25,980 --> 00:56:28,156 ¿Por qué sabes que señalarás a María? 1236 00:56:28,156 --> 00:56:30,340 JESS: Porque nueve es menor que 55. 1237 00:56:30,340 --> 00:56:34,150 DAVID: Nueve es menor que 55, también, Achmed no es solo la historia nueve. 1238 00:56:34,150 --> 00:56:36,990 Correcto, tienes este próximo puntero que dice 1239 00:56:36,990 --> 00:56:39,270 Jess donde está el siguiente valor para mirar. 1240 00:56:39,270 --> 00:56:43,830 Entonces su mano izquierda es el sustituto de lo que sería ++ el mundo 1241 00:56:43,830 --> 00:56:44,560 de un arreglo. 1242 00:56:44,560 --> 00:56:47,800 Recorrerás físicamente y recorrerás a lo largo de esto. 1243 00:56:47,800 --> 00:56:49,320 Entonces, señalaremos aquí al 17. 1244 00:56:49,320 --> 00:56:51,120 No es mayor que. 1245 00:56:51,120 --> 00:56:53,680 A continuación, señalamos a Arunev. 1246 00:56:53,680 --> 00:56:55,290 OK, eso es un 22. 1247 00:56:55,290 --> 00:56:56,507 Todavía no es el valor correcto. 1248 00:56:56,507 --> 00:56:57,090 Seguimos adelante. 1249 00:56:57,090 --> 00:56:58,600 ¿Cuál es tu nombre? 1250 00:56:58,600 --> 00:56:59,400 ¿Jeung Wan? 1251 00:56:59,400 --> 00:57:02,230 OK, ese no es el número correcto porque sostiene 26. 1252 00:57:02,230 --> 00:57:03,870 Y ahora, ¿te atrapamos otra vez? 1253 00:57:03,870 --> 00:57:04,860 Nazli. 1254 00:57:04,860 --> 00:57:08,610 Todavía no está bien, y ahora seguiremos su mano izquierda. 1255 00:57:08,610 --> 00:57:12,450 OK, sabemos que este tiene que ser el espacio correcto porque no 1256 00:57:12,450 --> 00:57:14,400 encontramos el espacio numérico correcto. 1257 00:57:14,400 --> 00:57:16,837 Si podemos prestarte, Stella, todo el camino hasta aquí. 1258 00:57:16,837 --> 00:57:19,170 Técnicamente, no te mueves físicamente en la memoria 1259 00:57:19,170 --> 00:57:21,520 pero esto solo mejorará la historia. 1260 00:57:21,520 --> 00:57:25,449 OK, estamos re-distribu-yendo algo. 1261 00:57:25,449 --> 00:57:27,240 ¿Qué haremos ahora con Stella 1262 00:57:27,240 --> 00:57:30,860 que encontramos la ubicación correcta? 1263 00:57:30,860 --> 00:57:32,610 Déjala aquí, OK. 1264 00:57:32,610 --> 00:57:34,680 Ahora, ella está como huérfana. 1265 00:57:34,680 --> 00:57:37,400 Ella señala a la nada y nadie la señala a ella. 1266 00:57:37,400 --> 00:57:39,082 Es un poco triste 1267 00:57:39,082 --> 00:57:40,290 Esto es perfecto. 1268 00:57:40,290 --> 00:57:41,340 Pérdida de memoria. 1269 00:57:41,340 --> 00:57:44,130 OK, entonces lo arreglaremos. 1270 00:57:44,130 --> 00:57:45,880 ¿Quién tiene el punto de quién? 1271 00:57:45,880 --> 00:57:47,020 Ok, bien. 1272 00:57:47,020 --> 00:57:50,440 Y ahora, ¿qué debería señalar Stella? 1273 00:57:50,440 --> 00:57:52,740 Desde ahora ella está al final de la lista y ella solo 1274 00:57:52,740 --> 00:57:54,974 apuntará a algún valor de basura. 1275 00:57:54,974 --> 00:57:58,140 Ella señala, para ser claros, a algún valor de basura porque cuando llamamos a 1276 00:57:58,140 --> 00:58:00,420 malloc solo obtenemos valores de basura. 1277 00:58:00,420 --> 00:58:03,376 Anulamos uno de esos valores de basura con 55 para n, 1278 00:58:03,376 --> 00:58:05,250 pero aún no se sobrescribió el puntero. 1279 00:58:05,250 --> 00:58:06,458 Entonces, ¿qué quieres hacer, Jess? 1280 00:58:06,458 --> 00:58:11,090 1281 00:58:11,090 --> 00:58:11,750 ¿A quién? 1282 00:58:11,750 --> 00:58:12,300 Está bien. 1283 00:58:12,300 --> 00:58:12,890 Está cerca. 1284 00:58:12,890 --> 00:58:18,410 ¿Cuál debería ser su valor si no hay nadie a su izquierda? 1285 00:58:18,410 --> 00:58:19,040 Debería ser nulo. 1286 00:58:19,040 --> 00:58:22,250 OK, ¿antes, cómo representamos nulo? 1287 00:58:22,250 --> 00:58:23,150 Si, exacto. 1288 00:58:23,150 --> 00:58:27,110 Nulo, ahora que tenemos una lista, y solo para arreglar las cosas, su puntero, 1289 00:58:27,110 --> 00:58:29,030 entonces, Jess es algo temporal. 1290 00:58:29,030 --> 00:58:30,940 No nos importa cuál es su valor. 1291 00:58:30,940 --> 00:58:32,190 Pero, ¿quién es importante aquí? 1292 00:58:32,190 --> 00:58:33,200 Otra vez, ¿cuál es tu nombre? 1293 00:58:33,200 --> 00:58:39,320 Olivia fue la primera y, ¿tenemos una lista que todavía está vinculada? 1294 00:58:39,320 --> 00:58:39,996 La tenemos. 1295 00:58:39,996 --> 00:58:42,620 Desde luego, tomó un poco de tiempo pasar por esto. 1296 00:58:42,620 --> 00:58:44,304 Y dije un tipo de mentira. 1297 00:58:44,304 --> 00:58:46,220 No hice esto más rápido porque, 1298 00:58:46,220 --> 00:58:49,290 ¿qué sucedió con el tiempo de ejecución de este algoritmo? 1299 00:58:49,290 --> 00:58:50,750 Todavía era un log de n. 1300 00:58:50,750 --> 00:58:51,950 Pero eso es porque, ¿qué? 1301 00:58:51,950 --> 00:58:54,390 ¿Qué propiedad traté de mantener? 1302 00:58:54,390 --> 00:58:55,260 El orden. 1303 00:58:55,260 --> 00:58:57,020 Entonces supongamos que relajo esa restricción. 1304 00:58:57,020 --> 00:58:59,870 Supongamos que no me importa que pertenezca a un orden establecido. 1305 00:58:59,870 --> 00:59:06,610 ¿Puedo hacer algo mejor que 0 de n para insertar a Stella? 1306 00:59:06,610 --> 00:59:07,490 PÚBLICO: [INAUDIBLE] 1307 00:59:07,490 --> 00:59:10,222 DAVID: OK, tiempo constante, ¿dónde puedo ponerla? 1308 00:59:10,222 --> 00:59:11,215 PÚBLICO: [INAUDIBLE] 1309 00:59:11,215 --> 00:59:12,090 DAVID: Exactamente, 1310 00:59:12,090 --> 00:59:13,798 Si no nos importa el orden establecido, 1311 00:59:13,798 --> 00:59:15,720 me habría ahorrado una gran cantidad de tiempo 1312 00:59:15,720 --> 00:59:19,890 y pudimos insertar a Stella aquí, las manos actualizadas de Olivia y las 1313 00:59:19,890 --> 00:59:21,510 manos actualizadas de Stella apuntan a Achmed. 1314 00:59:21,510 --> 00:59:22,650 Y entonces, lo repetimos. 1315 00:59:22,650 --> 00:59:23,240 Tiempo constante. 1316 00:59:23,240 --> 00:59:26,430 Y aquí, hay un ejemplo de por qué una gran O de uno no significa un paso. 1317 00:59:26,430 --> 00:59:30,276 Es tiempo constante porque es como mover la mano de Olivia y la de Stella 1318 00:59:30,276 --> 00:59:30,900 pero no la de Achmed. 1319 00:59:30,900 --> 00:59:34,530 Eso son al menos dos pasos, son siempre dos pasos. 1320 00:59:34,530 --> 00:59:37,505 ¿Podríamos obtener una ronda de aplausos para nuestros voluntarios? 1321 00:59:37,505 --> 00:59:42,360 [CHEERING] Pueden conservar tanto sus números, como estos, si lo desean. 1322 00:59:42,360 --> 00:59:43,950 Muchas gracias. 1323 00:59:43,950 --> 00:59:47,570 Tal vez esto le ayude a tu P a establecerla en cinco. 1324 00:59:47,570 --> 00:59:49,680 Oh, lo siento. 1325 00:59:49,680 --> 00:59:50,850 Está bien, gracias. 1326 00:59:50,850 --> 00:59:56,911 Esa, desde luego, es solo una operación. 1327 00:59:56,911 --> 00:59:58,410 Pudo haber otros números. 1328 00:59:58,410 --> 01:00:01,230 Si intentamos insertar cinco en el orden establecido, 1329 01:00:01,230 --> 01:00:04,049 conseguimos nuestro tiempo constante o nuestro omega de uno 1330 01:00:04,049 --> 01:00:06,840 porque en el mejor de los casos, el número terminaría al principio. 1331 01:00:06,840 --> 01:00:09,120 20, si lo hubiéramos insertado con nuestros humanos, pudieron 1332 01:00:09,120 --> 01:00:12,270 estar un poco más involucrados, porque habrían recorrido la lista 1333 01:00:12,270 --> 01:00:13,170 como lo hicimos con Jess. 1334 01:00:13,170 --> 01:00:16,710 Ella tiene que señalar a la persona detrás 1335 01:00:16,710 --> 01:00:20,340 y a la persona que tiene delante porque tiene que actualizar más manos. 1336 01:00:20,340 --> 01:00:23,760 Esto quiere decir que, el realizar inserciones o incluso eliminaciones 1337 01:00:23,760 --> 01:00:26,272 requieren de unos pocos ajustes. 1338 01:00:26,272 --> 01:00:28,230 Es como arreglar ropa, en la que intentamos 1339 01:00:28,230 --> 01:00:31,717 mantener un proceso contiguo a lo largo de todas las estructuras de datos. 1340 01:00:31,717 --> 01:00:34,050 A fin de cuentas, a pesar de que usamos punteros, 1341 01:00:34,050 --> 01:00:37,170 todo se reduce a tener esta lógica correcta. 1342 01:00:37,170 --> 01:00:41,790 Continuaré con un ejemplo de algún código sobre cómo hacer esto. 1343 01:00:41,790 --> 01:00:45,810 Proseguiré, abriré la lista 0.c 1344 01:00:45,810 --> 01:00:48,400 y echaré un vistazo sobre cómo funciona esto. 1345 01:00:48,400 --> 01:00:54,780 En la lista 0.c tenemos el siguiente código. 1346 01:00:54,780 --> 01:00:59,262 Primero, en main, obtenemos del usuario un número positivo. 1347 01:00:59,262 --> 01:01:02,470 Agitaré mis manos, porque esto es algo así como la vieja escuela. 1348 01:01:02,470 --> 01:01:05,470 Usamos un bucle while para obtener un número positivo del usuario. 1349 01:01:05,470 --> 01:01:07,060 Yo lo llamo capacity. 1350 01:01:07,060 --> 01:01:10,940 Este es un ejemplo de cómo obtenerlo del usuario, al llamarlo capacity. 1351 01:01:10,940 --> 01:01:14,040 Capacity, significa el tamaño máximo posible para una estructura de datos. 1352 01:01:14,040 --> 01:01:15,690 Eso sería un término artístico. 1353 01:01:15,690 --> 01:01:19,740 Por la semana dos del curso, 1354 01:01:19,740 --> 01:01:24,510 asignamos un arreglo para ints de muchos ints de capacidad. 1355 01:01:24,510 --> 01:01:26,010 También, afortunadamente es familiar. 1356 01:01:26,010 --> 01:01:27,330 Aún no hay punteros. 1357 01:01:27,330 --> 01:01:28,450 No hay nada demasiado elegante. 1358 01:01:28,450 --> 01:01:32,584 Estoy asignando un arreglo de tamaño con base en lo que un humano escribió. 1359 01:01:32,584 --> 01:01:34,500 Aquí es donde se pone un poco interesante. 1360 01:01:34,500 --> 01:01:38,427 El propósito de este programa es solicitarle al usuario muchos números 1361 01:01:38,427 --> 01:01:39,510 una y otra y otra vez. 1362 01:01:39,510 --> 01:01:44,350 Puedo escribir 1, 2, 3 o 5, 17, 20, 22, y así sucesivamente. 1363 01:01:44,350 --> 01:01:47,200 Y construir un arreglo de números y memoria, 1364 01:01:47,200 --> 01:01:50,830 pero tropezaré con el problema que identificamos hace un momento. 1365 01:01:50,830 --> 01:01:51,990 Aquí vamos. 1366 01:01:51,990 --> 01:01:54,240 Inicializo el tamaño a cero porque inicialmente no hay 1367 01:01:54,240 --> 01:01:55,650 nada en la estructura. 1368 01:01:55,650 --> 01:01:58,590 Si bien, el tamaño es inferior a mi capacidad, mientras que el tamaño actual 1369 01:01:58,590 --> 01:02:02,500 es menor que el máximo, por así decirlo, haga lo siguiente. 1370 01:02:02,500 --> 01:02:04,620 Primero, obtendré un número del usuario. 1371 01:02:04,620 --> 01:02:07,590 El objetivo es insertar este número en esta lista. 1372 01:02:07,590 --> 01:02:09,780 Ahora haré una verificación de sanidad rápida. 1373 01:02:09,780 --> 01:02:14,250 Verificaré y me aseguraré de que este número ya esté, o no, en la lista, 1374 01:02:14,250 --> 01:02:15,930 porque no quiero tener duplicados. 1375 01:02:15,930 --> 01:02:16,350 ¿Por qué? 1376 01:02:16,350 --> 01:02:16,950 Simplemente porque 1377 01:02:16,950 --> 01:02:19,500 Quiero que esta sea una lista muy limpia, sin duplicados. 1378 01:02:19,500 --> 01:02:24,120 Este bucle de código, tal vez de la semana uno, semana dos, semana tres, 1379 01:02:24,120 --> 01:02:28,620 es solo un ejemplo de iterar a lo largo de un arreglo, buscando el número, 1380 01:02:28,620 --> 01:02:31,500 y si es así, recordaré que lo encontré con un booleano, 1381 01:02:31,500 --> 01:02:35,170 así que, encontré una respuesta o no, con una variable booleana. 1382 01:02:35,170 --> 01:02:35,670 OK. 1383 01:02:35,670 --> 01:02:37,044 Eso es todo lo que hace este código. 1384 01:02:37,044 --> 01:02:38,400 Todavía no hay magia. 1385 01:02:38,400 --> 01:02:41,940 Ahora, aquí es donde sucede la parte interesante de la historia. 1386 01:02:41,940 --> 01:02:48,650 Si el número no se encontró en la lista, aquí estará cómo por una semana o dos, 1387 01:02:48,650 --> 01:02:51,630 agregamos un número al final de un arreglo. 1388 01:02:51,630 --> 01:02:55,530 Porque, si el tamaño inicial es cero, los números [0] 1389 01:02:55,530 --> 01:02:57,090 es donde debe ir el primer número. 1390 01:02:57,090 --> 01:03:00,434 Si el tamaño inicial es uno en este punto, los números [1] 1391 01:03:00,434 --> 01:03:01,850 es donde debe ir el primer número. 1392 01:03:01,850 --> 01:03:04,200 Y entonces, debería incrementar el tamaño. 1393 01:03:04,200 --> 01:03:08,130 Aquí hay un problema, porque una vez que imprimo estos números 1394 01:03:08,130 --> 01:03:12,270 y el programa termina. Puedo ingresar tantos números 1395 01:03:12,270 --> 01:03:16,620 como hay disponibles, como la capacidad que tengo. 1396 01:03:16,620 --> 01:03:18,390 Por lo tanto, es un poco limitado. 1397 01:03:18,390 --> 01:03:20,660 ¿Y si quiero hacerlo un poco mejor que esto? 1398 01:03:20,660 --> 01:03:25,050 En list1.c que introduce material nuevo, o al menos una aplicación 1399 01:03:25,050 --> 01:03:27,480 de los temas esta semana y la última. 1400 01:03:27,480 --> 01:03:32,010 Aquí en la línea nueve es técnicamente cómo puedo asignar 1401 01:03:32,010 --> 01:03:35,730 un arreglo antes de saber el tamaño del mismo. 1402 01:03:35,730 --> 01:03:38,610 Un arreglo, recuerden, es un fragmento de memoria 1403 01:03:38,610 --> 01:03:42,300 identificado por alguna palabra, como números o estudiantes o cualquier cosa. 1404 01:03:42,300 --> 01:03:45,270 Pero, hemos visto que hay una especie de equivalencia, donde 1405 01:03:45,270 --> 01:03:48,720 si un arreglo es un fragmento de la memoria, se puede referir a el 1406 01:03:48,720 --> 01:03:51,940 por su ubicación, la dirección de su primer byte como una cadena. 1407 01:03:51,940 --> 01:03:54,690 Esto en la línea nueve es un poco nuevo, 1408 01:03:54,690 --> 01:03:56,040 pero es como esa idea. 1409 01:03:56,040 --> 01:03:58,710 Dame un puntero llamado numbers pero inicialízalo como nulo. 1410 01:03:58,710 --> 01:04:00,290 No hay espacio para el número. 1411 01:04:00,290 --> 01:04:03,210 Pero este puntero, por lo tanto, no apunta a ningún fragmento de memoria. 1412 01:04:03,210 --> 01:04:05,940 Sería como si Olivia se parara aquí incómodamente sin nadie 1413 01:04:05,940 --> 01:04:10,050 a quién señalar porque solo asignamos espacio para el primer puntero, 1414 01:04:10,050 --> 01:04:12,540 no para todos los demás en el escenario. 1415 01:04:12,540 --> 01:04:14,970 Su capacidad predeterminada es cero. 1416 01:04:14,970 --> 01:04:18,270 El resto del programa es bastante similar. 1417 01:04:18,270 --> 01:04:21,820 Continúo y le pregunto al usuario infinitamente un número. 1418 01:04:21,820 --> 01:04:22,612 Verifico si hay errores. 1419 01:04:22,612 --> 01:04:24,361 Si leemos la documentación 1420 01:04:24,361 --> 01:04:26,875 para obtener int, devolverá una constante especial llamada INT_MAX 1421 01:04:26,875 --> 01:04:29,610 si el usuario se detiene para escribir la entrada. 1422 01:04:29,610 --> 01:04:32,070 Aquí verifico con un bucle booleano, 1423 01:04:32,070 --> 01:04:35,010 si este número está o no en la lista, igual que antes. 1424 01:04:35,010 --> 01:04:37,740 Aquí es donde usaré algunas nuevas funciones. 1425 01:04:37,740 --> 01:04:43,610 Si el número no se encontró en la lista, y el tamaño de la lista 1426 01:04:43,610 --> 01:04:47,850 ya es igual a su capacidad, es decir, si está lleno. 1427 01:04:47,850 --> 01:04:50,420 Conceptualmente, ¿qué tengo que hacer ahora? 1428 01:04:50,420 --> 01:04:53,229 Si tengo un arreglo cuyo propósito en la vida, como lo hicimos anteriormente, 1429 01:04:53,229 --> 01:04:54,020 ¿solo aumentará? 1430 01:04:54,020 --> 01:04:57,130 1431 01:04:57,130 --> 01:04:58,500 Necesito agregarle espacio. 1432 01:04:58,500 --> 01:05:00,420 Necesito agregar espacio, como propusimos. 1433 01:05:00,420 --> 01:05:03,211 Aunque esto es una especie de debilidad, porque es un poco ineficiente, 1434 01:05:03,211 --> 01:05:04,500 así es como podemos hacerlo. 1435 01:05:04,500 --> 01:05:10,500 Puedo llamar a realloc, nombrando al arreglo cuya memoria 1436 01:05:10,500 --> 01:05:12,030 quiero reasignar. 1437 01:05:12,030 --> 01:05:15,540 Solo digo a realloc ahora cuánto espacio quiero. 1438 01:05:15,540 --> 01:05:19,330 Este es el tamaño del int, cuatro bytes. (sizeof(int)) 1439 01:05:19,330 --> 01:05:20,940 Y este es el número de bytes que quiero. (size + 1) 1440 01:05:20,940 --> 01:05:25,830 Cualquiera que sea el tamaño actual, realloc me dará un byte más. 1441 01:05:25,830 --> 01:05:29,760 Y luego realloc se asigna a numbers, 1442 01:05:29,760 --> 01:05:32,172 y verifico si es nulo o no. 1443 01:05:32,172 --> 01:05:33,630 Lo mantengo un poco simple. 1444 01:05:33,630 --> 01:05:36,588 Agregaríamos verificaciones de errores, pero, ¿qué significa lo que realloc 1445 01:05:36,588 --> 01:05:37,180 hace? 1446 01:05:37,180 --> 01:05:39,900 Realloc es bastante genial porque si pasamos a realloc, 1447 01:05:39,900 --> 01:05:43,426 un puntero a un fragmento de memoria que es de este tamaño, realloc 1448 01:05:43,426 --> 01:05:45,300 buscará en la memoria de su computadora y si 1449 01:05:45,300 --> 01:05:47,760 ve un fragmento de memoria más grande, 1450 01:05:47,760 --> 01:05:51,420 se encargará de copiar todo para usted. 1451 01:05:51,420 --> 01:05:54,990 Después, regresó a la ubicación del nuevo fragmento de memoria 1452 01:05:54,990 --> 01:05:56,470 y liberó el antiguo para nosotros. 1453 01:05:56,470 --> 01:05:57,900 También hace el intercambio. 1454 01:05:57,900 --> 01:06:01,200 Todavía es tiempo lineal, pero así es como lo usaríamos 1455 01:06:01,200 --> 01:06:07,630 sin asignar, liberar y usar un bucle for como lo describimos anteriormente. 1456 01:06:07,630 --> 01:06:10,870 Podemos continuar y poner el número en la lista como antes. 1457 01:06:10,870 --> 01:06:13,380 Lo único nuevo aquí, aunque lo estamos pasando rápido, 1458 01:06:13,380 --> 01:06:14,970 es que así es como llamamos a realloc. 1459 01:06:14,970 --> 01:06:16,974 Pasamos un puntero que apunta previamente 1460 01:06:16,974 --> 01:06:18,390 a un fragmento de memoria o incluso nulo. 1461 01:06:18,390 --> 01:06:18,899 Está bien. 1462 01:06:18,899 --> 01:06:20,940 Si lo pasamos en un puntero que señala nulo, 1463 01:06:20,940 --> 01:06:23,981 le devolverá la ubicación de solo un byte, y la siguiente vez 1464 01:06:23,981 --> 01:06:26,910 dos bytes, tres bytes y cuatro bytes. 1465 01:06:26,910 --> 01:06:30,180 Con listas vinculadas, las cosas se ponen un poco más interesantes. 1466 01:06:30,180 --> 01:06:33,440 Y la sintaxis será un poco extraña, pero veamos. 1467 01:06:33,440 --> 01:06:37,770 Podemos implementar a cada uno de nuestros voluntarios humanos 1468 01:06:37,770 --> 01:06:38,670 un código. 1469 01:06:38,670 --> 01:06:41,400 A cada uno de ellos lo llamé nodo, nodo es un término artístico en CS. 1470 01:06:41,400 --> 01:06:44,740 Se refiere a cierta estructura de datos que contiene cierta información. 1471 01:06:44,740 --> 01:06:48,030 Cada uno de ellos sostenía un número, que llamamos int. 1472 01:06:48,030 --> 01:06:50,100 Cada uno de ellos, es un poco raro, 1473 01:06:50,100 --> 01:06:53,820 tenía una mano izquierda llamada siguiente, que pretendía apuntar a alguien 1474 01:06:53,820 --> 01:06:55,950 que se parecía a ellos estructuralmente. 1475 01:06:55,950 --> 01:06:59,871 La idea aquí es que no queremos tener otra estructura 1476 01:06:59,871 --> 01:07:01,620 dentro de una estructura, de lo contrario haría 1477 01:07:01,620 --> 01:07:05,550 que sucediera algo similar a las muñecas rusas infinitas. 1478 01:07:05,550 --> 01:07:08,730 En su lugar, quiere decir que cada una de estas estructuras 1479 01:07:08,730 --> 01:07:12,840 tiene un puntero hacia otra persona que se parece a ella estructuralmente. 1480 01:07:12,840 --> 01:07:16,930 Así es como obtenemos la metáfora del brazo izquierdo implementada en el código. 1481 01:07:16,930 --> 01:07:20,100 Eso solo define un nodo, uno de nuestros voluntarios. 1482 01:07:20,100 --> 01:07:24,810 Así es como implementaríamos a Olivia en una línea de código. 1483 01:07:24,810 --> 01:07:28,440 Olivia era ella misma un puntero hacia un nodo. 1484 01:07:28,440 --> 01:07:29,850 Ella no tenía un número, ¿cierto? 1485 01:07:29,850 --> 01:07:31,300 Su cartel solo decía primero, 1486 01:07:31,300 --> 01:07:33,040 ella no sostenía un número. 1487 01:07:33,040 --> 01:07:35,130 Entonces, no necesitamos una estructura completa para Olivia, 1488 01:07:35,130 --> 01:07:38,970 solo necesitamos un puntero unido a una de esas estructuras de nodos. 1489 01:07:38,970 --> 01:07:41,850 Inicialmente ella solo se paró aquí, así que 1490 01:07:41,850 --> 01:07:43,840 se dice que ella fue nula desde el inicio. 1491 01:07:43,840 --> 01:07:47,730 El resto de este código es sobre malloc-ing, o alguien como Stella 1492 01:07:47,730 --> 01:07:52,620 que actualizó a Olivia y usó a Jess para actualizar los punteros 1493 01:07:52,620 --> 01:07:53,280 temporalmente. 1494 01:07:53,280 --> 01:07:55,900 Veamos cómo se ve esto en el código. 1495 01:07:55,900 --> 01:07:59,760 Aunque es cierto, solo le pediré al usuario los números. 1496 01:07:59,760 --> 01:08:03,460 Como antes, verificaré los errores de la misma manera. 1497 01:08:03,460 --> 01:08:04,870 Aquí es un poco diferente. 1498 01:08:04,870 --> 01:08:09,660 Este es el bloque de código con el que compruebo si mi lista enlazada actual ya 1499 01:08:09,660 --> 01:08:11,760 tiene el número que intento insertar. 1500 01:08:11,760 --> 01:08:15,150 Pero recuerden, le quitamos la expresividad de los corchetes. 1501 01:08:15,150 --> 01:08:16,560 Ya no podemos hacer eso. 1502 01:08:16,560 --> 01:08:18,840 Ahora tengo que hacerlo con punteros. 1503 01:08:18,840 --> 01:08:19,945 Así que, aquí vamos. 1504 01:08:19,945 --> 01:08:23,490 Con mis cuatro bucles, inicializo un puntero, Jess, 1505 01:08:23,490 --> 01:08:26,710 para apuntar a lo mismo que apuntaba Olivia, números. 1506 01:08:26,710 --> 01:08:28,941 Así que de nuevo, Jess también era solo un puntero. 1507 01:08:28,941 --> 01:08:30,149 Ella no sostenía un número. 1508 01:08:30,149 --> 01:08:33,689 Ella estaba sosteniendo un PTR, por lo que era solo un puntero 1509 01:08:33,689 --> 01:08:36,390 que apuntaba a lo mismo que Olivia. 1510 01:08:36,390 --> 01:08:40,410 Aquí estamos diciendo, siempre y cuando Jess no sea igual a nulo, 1511 01:08:40,410 --> 01:08:43,800 siempre que Jess no se aleje del escenario, 1512 01:08:43,800 --> 01:08:45,359 haz lo siguiente. 1513 01:08:45,359 --> 01:08:46,529 ¿Qué quiero hacer? 1514 01:08:46,529 --> 01:08:48,149 Y esta sintaxis es nueva. 1515 01:08:48,149 --> 01:08:51,630 Vimos al inicio el operador punto, 1516 01:08:51,630 --> 01:08:54,300 que dice, toma una estructura de datos, por ejemplo estudiantes 1517 01:08:54,300 --> 01:08:56,380 y entra con el operador punto. 1518 01:08:56,380 --> 01:08:58,470 Obtén su nombre y su dormitorio. 1519 01:08:58,470 --> 01:09:00,990 Eso fue porque la primera demostración de hoy no usó punteros. 1520 01:09:00,990 --> 01:09:02,490 solo utilizó estructuras. 1521 01:09:02,490 --> 01:09:05,250 Ahora estamos utilizando estructuras y punteros 1522 01:09:05,250 --> 01:09:07,740 y entonces la sintaxis cambia solo un poquito. 1523 01:09:07,740 --> 01:09:10,920 Cuando tienes un puntero que es un puntero a una estructura 1524 01:09:10,920 --> 01:09:14,160 y quieres seguir ese puntero e ir a esa estructura, 1525 01:09:14,160 --> 01:09:18,720 la única sintaxis en C que tal vez corresponda con esa realidad o concepto 1526 01:09:18,720 --> 01:09:22,140 es este operador de flecha, lo cual significa seguir la mano izquierda, 1527 01:09:22,140 --> 01:09:25,240 ver la estructura y conseguir ese número. 1528 01:09:25,240 --> 01:09:30,660 Entonces, si el número del voluntario es igual al número que Jess estaba buscando, 1529 01:09:30,660 --> 01:09:32,649 sigue y dice que lo encontrado es verdad. 1530 01:09:32,649 --> 01:09:36,870 De lo contrario, actualiza a Jess o al puntero a igual 1531 01:09:36,870 --> 01:09:39,939 sin importar a lo que apunte su mano izquierda. 1532 01:09:39,939 --> 01:09:42,630 Entonces, si Jess estaba señalando temporalmente aquí, 1533 01:09:42,630 --> 01:09:46,140 entonces ella se actualizaría apuntando allí. 1534 01:09:46,140 --> 01:09:48,270 Y eso es todo lo que hace este código. 1535 01:09:48,270 --> 01:09:51,660 Jess comienza a señalar a lo que apuntaba su mano izquierda. 1536 01:09:51,660 --> 01:09:54,390 Se mueve físicamente en el escenario. 1537 01:09:54,390 --> 01:09:56,975 Y bien, ahora es cuando las cosas se ponen feas. 1538 01:09:56,975 --> 01:09:59,850 Y haremos esto en otra dirección, porque creo que está mejor 1539 01:09:59,850 --> 01:10:02,340 hecha y a un ritmo más lento para nosotros. 1540 01:10:02,340 --> 01:10:05,490 Y veremos este tipo de cosas en la sección y más allá. 1541 01:10:05,490 --> 01:10:07,710 Así es como asignó el espacio para un nuevo nodo. 1542 01:10:07,710 --> 01:10:11,730 Cuando dije malloc Stella, es esta línea de código, la 45. 1543 01:10:11,730 --> 01:10:17,820 Malloc espacio para el tamaño de un nodo y almacenarlo en la persona 1544 01:10:17,820 --> 01:10:19,030 que Stella incorporó. 1545 01:10:19,030 --> 01:10:21,780 De lo contrario, si no hay suficiente memoria, si algo sale mal, 1546 01:10:21,780 --> 01:10:23,220 devuelve uno. 1547 01:10:23,220 --> 01:10:25,900 Mientras tanto, así es como agregamos el número a la lista. 1548 01:10:25,900 --> 01:10:30,450 Así que eso es exactamente lo que Jess actuó. 1549 01:10:30,450 --> 01:10:37,350 Primero le dimos a Stella su número, que es la línea 52. 1550 01:10:37,350 --> 01:10:40,177 Técnicamente le dijimos que apuntara a un valor basura, 1551 01:10:40,177 --> 01:10:41,510 así que he mejorado el código desde entonces. 1552 01:10:41,510 --> 01:10:46,120 Entonces la línea 53 sería como decirle a Stella, señala aquí, no acá, 1553 01:10:46,120 --> 01:10:48,789 y eso solo es limpiar la omisión de la última vez. 1554 01:10:48,789 --> 01:10:50,580 Y luego aquí tenemos el mismo tipo de código 1555 01:10:50,580 --> 01:10:52,380 de nuevo, un bucle de cuatro que se ve un poco raro 1556 01:10:52,380 --> 01:10:55,834 pero es como actualizar la mano mientras recorre la lista. 1557 01:10:55,834 --> 01:10:57,750 Y aquí es donde ocurre la parte interesante. 1558 01:10:57,750 --> 01:11:01,930 Al final de nuestra historia, Jess manipuló los brazos de nuestro voluntario. 1559 01:11:01,930 --> 01:11:08,250 Entonces, if not pointer next, que es una forma críptica de decir, 1560 01:11:08,250 --> 01:11:10,890 if (ptr ->next == NULL) 1561 01:11:10,890 --> 01:11:14,220 Entonces, si Jess ha encontrado el final de la lista, 1562 01:11:14,220 --> 01:11:18,060 ve y actualiza a quien sea que esté apuntando con la 1563 01:11:18,060 --> 01:11:21,810 mano izquierda para señalar a Stella, el nuevo nodo. 1564 01:11:21,810 --> 01:11:26,280 Luego sale porque ya hemos terminado. 1565 01:11:26,280 --> 01:11:28,500 Así que sintácticamente, esto es difícil y problemático 1566 01:11:28,500 --> 01:11:31,870 establecer cinco nos dará la oportunidad de pasar por un código muy similar. 1567 01:11:31,870 --> 01:11:34,380 Pero por ahora, dense cuenta de que todo lo que estamos haciendo 1568 01:11:34,380 --> 01:11:37,380 es en vez de simplemente usar una aritmética muy simple, más uno, más uno, 1569 01:11:37,380 --> 01:11:40,950 más uno, solo estamos siguiendo estas flechas, siguiendo estas flechas. 1570 01:11:40,950 --> 01:11:43,270 Y el tipo de sintaxis que usaremos para eso 1571 01:11:43,270 --> 01:11:45,849 solo es esta, que no es muy legible a primera vista. 1572 01:11:45,849 --> 01:11:48,390 Por eso enfatizo, si son personas más visuales, 1573 01:11:48,390 --> 01:11:51,390 los tipos de manipulación de mano y cambios de brazo 1574 01:11:51,390 --> 01:11:55,800 que estábamos haciendo físicamente aquí con nuestros voluntarios. 1575 01:11:55,800 --> 01:11:57,551 Y luego, nuevamente, imprimimos [INAUDIBLE]. 1576 01:11:57,551 --> 01:11:59,258 Lo último que haré notar y que 1577 01:11:59,258 --> 01:12:01,500 aplicarán en la serie de problemas cinco, es como pueden 1578 01:12:01,500 --> 01:12:03,120 liberar una lista completa de números. 1579 01:12:03,120 --> 01:12:05,580 Simplemente felicité a nuestros voluntarios y todos 1580 01:12:05,580 --> 01:12:07,142 dejaron el escenario, siendo liberados. 1581 01:12:07,142 --> 01:12:10,100 Si quisiéramos que fuera más metódico, podríamos usar un bucle de cuatro 1582 01:12:10,100 --> 01:12:12,141 pero aquí elegí un bucle while, porque es 1583 01:12:12,141 --> 01:12:13,710 un diseño un poco más sucinto sabio. 1584 01:12:13,710 --> 01:12:18,510 Aquí estaba nuestro puntero, un puntero temporal que apuntaba a los números. 1585 01:12:18,510 --> 01:12:21,420 Y aquí puedo decir, mientras el puntero no sea nulo, porque si fuera nulo 1586 01:12:21,420 --> 01:12:22,530 mi trabajo estaría hecho. 1587 01:12:22,530 --> 01:12:26,220 Y aquí digo, actualiza este valor siguiente para que sea igual 1588 01:12:26,220 --> 01:12:28,550 al que le siga en la lista. 1589 01:12:28,550 --> 01:12:31,290 Libera al que actualmente esté en la lista 1590 01:12:31,290 --> 01:12:33,360 y luego actualiza el siguiente puntero. 1591 01:12:33,360 --> 01:12:36,750 De nuevo, no se preocupen mucho por los detalles de nivel inferior. 1592 01:12:36,750 --> 01:12:41,730 Solo den por hecho que ahora tenemos una forma de implementarlo 1593 01:12:41,730 --> 01:12:45,420 en el código, la intuición de nivel superior que deriva 1594 01:12:45,420 --> 01:12:46,980 de este tipo de estructura de datos. 1595 01:12:46,980 --> 01:12:53,280 Pero no se preocupen aún por el código en sí. 1596 01:12:53,280 --> 01:12:57,480 Ahora tenemos la capacidad para unir estructuras de datos de esta forma. 1597 01:12:57,480 --> 01:12:59,640 El aspecto positivo es que ahora obtenemos dinamismo, ¿cierto? 1598 01:12:59,640 --> 01:13:01,590 Ya no estamos estancados pintando por nosotros mismos 1599 01:13:01,590 --> 01:13:04,650 en la esquina proverbial con arreglos que no asignan suficiente memoria. 1600 01:13:04,650 --> 01:13:07,950 O por el contrario, desperdiciando memoria con demasiadas asignaciones 1601 01:13:07,950 --> 01:13:09,630 para no lidiar con el problema. 1602 01:13:09,630 --> 01:13:11,550 Pero pagamos un precio con la lista vinculada. 1603 01:13:11,550 --> 01:13:15,750 Obtenemos dinamismo y podemos agregar o restar un nodo de manera más eficiente, 1604 01:13:15,750 --> 01:13:18,480 y solo tenemos que actualizar los punteros en un tiempo constante. 1605 01:13:18,480 --> 01:13:22,020 Pero gastamos más memoria en todos estos mugrosos indicadores. 1606 01:13:22,020 --> 01:13:24,120 Y francamente, el código es más complejo. 1607 01:13:24,120 --> 01:13:27,900 Recuerden la primera o segunda semana, el tiempo humano, el tiempo del programador 1608 01:13:27,900 --> 01:13:29,550 son recursos valiosos. 1609 01:13:29,550 --> 01:13:32,670 Y hacer algo más difícil y que consume más tiempo implementarlo 1610 01:13:32,670 --> 01:13:34,440 podría no ser un precio que quieran pagar. 1611 01:13:34,440 --> 01:13:36,669 Incluso chateaba ayer con un colega 1612 01:13:36,669 --> 01:13:39,210 sobre cómo en la escuela de posgrado solía tomar atajos, 1613 01:13:39,210 --> 01:13:41,140 especialmente a altas horas de la noche cuando escribía un código. 1614 01:13:41,140 --> 01:13:45,390 Y a veces escribía deliberadamente un código realmente malo 1615 01:13:45,390 --> 01:13:47,280 que podía tomar hasta ocho horas para analizar 1616 01:13:47,280 --> 01:13:50,790 algunos datos para un proyecto de investigación porque, ¿saben? 1617 01:13:50,790 --> 01:13:54,960 Me di cuenta de que era más rápido escribir un código incorrecto, mal diseñado, 1618 01:13:54,960 --> 01:13:57,090 tomará ocho horas porque en esas ocho horas 1619 01:13:57,090 --> 01:13:59,310 francamente podía irme a dormir. 1620 01:13:59,310 --> 01:14:03,180 Ahora diría que fue solo porque mi asesor no me calificaba 1621 01:14:03,180 --> 01:14:05,900 la corrección del diseño y el estilo. 1622 01:14:05,900 --> 01:14:09,900 Pero es la manifestación de un recurso muy real 1623 01:14:09,900 --> 01:14:12,990 y no recomiendo que tomen atajos por el momento, 1624 01:14:12,990 --> 01:14:16,110 ya que uno de los objetivos de estar en un curso es mejorar en el diseño. 1625 01:14:16,110 --> 01:14:18,110 Pero a fin de cuentas y en el mundo real, 1626 01:14:18,110 --> 01:14:20,790 incluso el equipo de CS50 y yo tomamos decisiones constantemente. 1627 01:14:20,790 --> 01:14:23,040 Bueno, sí, podríamos mejorar esta función de help50 1628 01:14:23,040 --> 01:14:24,810 pero tomaría una semana hacerlo. 1629 01:14:24,810 --> 01:14:27,930 O simplemente podemos agregar una línea adicional de código y tenerlo listo ya. 1630 01:14:27,930 --> 01:14:28,920 Y sería una compensación. 1631 01:14:28,920 --> 01:14:30,974 Esto es lo que hace que el código sea bueno y malo. 1632 01:14:30,974 --> 01:14:33,390 Y cuando comenzamos a tomar atajos, 1633 01:14:33,390 --> 01:14:36,300 empezamos a acumula lo que se llamaría deuda técnica. 1634 01:14:36,300 --> 01:14:38,310 Y las deudas tienden a no ser algo muy bueno. 1635 01:14:38,310 --> 01:14:41,040 Eso habla del precio que se pagará a largo plazo 1636 01:14:41,040 --> 01:14:43,415 porque podría tomar más tiempo este verano, al equipo y a mí, 1637 01:14:43,415 --> 01:14:45,150 volver y limpiar todo eso. 1638 01:14:45,150 --> 01:14:46,941 Y Dios no lo quiera, durante la noche esto sucedió 1639 01:14:46,941 --> 01:14:50,010 con más frecuencia de lo que debería admitir, mi código tenía errores y fue rescatado 1640 01:14:50,010 --> 01:14:53,330 a las 2:00 a. m., al levantarme ocho horas después pensando, mis datos están listos. 1641 01:14:53,330 --> 01:14:54,330 Y no. 1642 01:14:54,330 --> 01:14:56,230 Debí hacerlo bien la primera vez, 1643 01:14:56,230 --> 01:14:58,850 así hubiese podido ejecutar el código una y otra vez. 1644 01:14:58,850 --> 01:15:01,670 Entonces, ¿qué más obtenemos de esta habilidad 1645 01:15:01,670 --> 01:15:03,740 de tener punteros en las estructuras de datos? 1646 01:15:03,740 --> 01:15:06,280 Aquí les muestro esta imagen del comedor de Mather. 1647 01:15:06,280 --> 01:15:08,660 La tapa representa la noción de bandejas 1648 01:15:08,660 --> 01:15:10,760 y hemos usado la pila en un nivel muy bajo 1649 01:15:10,760 --> 01:15:12,801 y esotérico para hablar sobre la administración de la memoria, 1650 01:15:12,801 --> 01:15:15,800 que no es tan útil para que resolvamos problemas. 1651 01:15:15,800 --> 01:15:17,300 Pero la estructura de datos es... 1652 01:15:17,300 --> 01:15:21,410 En informática hay una estructura de datos conocida como pila o stack. 1653 01:15:21,410 --> 01:15:23,630 Y su computadora, ya sea Mac o PC, lo usan constantemente 1654 01:15:23,630 --> 01:15:27,650 para administrar funciones y memoria, pero podemos usarlo también 1655 01:15:27,650 --> 01:15:29,300 para varias aplicaciones. 1656 01:15:29,300 --> 01:15:32,910 Podemos implementar una estructura de datos en las que hay dos operaciones. 1657 01:15:32,910 --> 01:15:34,940 Convencionalmente se les llama push y pop. 1658 01:15:34,940 --> 01:15:36,040 Aunque es como sumar y restar. 1659 01:15:36,040 --> 01:15:38,539 Pueden llamarlo como quieran pero la mayoría de los programadores 1660 01:15:38,539 --> 01:15:39,980 lo llaman push y pop. 1661 01:15:39,980 --> 01:15:44,390 Push es como agregar una bandeja a la pila y pop es como quitarle otra. 1662 01:15:44,390 --> 01:15:46,910 Pero es tal como su nombre lo indica con la pila, 1663 01:15:46,910 --> 01:15:53,480 La característica de una pila es que es un ejemplo de estructura de datos LIFO, 1664 01:15:53,480 --> 01:15:57,470 LIFO significa "last in first out", último en entrar, primero en salir, 1665 01:15:57,470 --> 01:15:58,650 Ahora, ¿qué significa esto? 1666 01:15:58,650 --> 01:16:02,492 Bueno, si uno de los empleados del comedor viene con una bandeja nueva 1667 01:16:02,492 --> 01:16:05,450 que acaba de ser limpiada y la pone en la parte superior de la pila, 1668 01:16:05,450 --> 01:16:09,110 ¿Cuál es la que un ser humano normal agarraría primero? 1669 01:16:09,110 --> 01:16:10,930 La última en entrar, ¿verdad? 1670 01:16:10,930 --> 01:16:13,700 Sería extraño y difícil ponerse de rodillas 1671 01:16:13,700 --> 01:16:16,850 y sacar la de abajo, aunque sería más justo, ¿no? 1672 01:16:16,850 --> 01:16:20,750 Como esa pequeña bandeja de abajo que ha esperado más tiempo para ser utilizada, 1673 01:16:20,750 --> 01:16:25,610 pero está por debajo del peso de toda la pila, literalmente. 1674 01:16:25,610 --> 01:16:28,127 Sin embargo, así es como funcionaría una pila. 1675 01:16:28,127 --> 01:16:30,460 Y ahora pueden implementarla de varias maneras. 1676 01:16:30,460 --> 01:16:33,290 Y aquí es donde el mundo se vuelve interesante en programación, 1677 01:16:33,290 --> 01:16:36,380 es donde hay esta distinción entre el diseño 1678 01:16:36,380 --> 01:16:39,410 de estructuras de datos y los detalles de implementación de bajo nivel. 1679 01:16:39,410 --> 01:16:42,540 Una pila es como la describí, una estructura de datos LIFO. 1680 01:16:42,540 --> 01:16:45,320 Push y pop, último en entrar, primero en salir. 1681 01:16:45,320 --> 01:16:46,340 Eso es todo. 1682 01:16:46,340 --> 01:16:48,660 Cómo lo implementarían, puede ser de varias maneras. 1683 01:16:48,660 --> 01:16:54,530 Por ejemplo, podrían implementar una pila como un tipo de datos C, personalizado, 1684 01:16:54,530 --> 01:16:57,680 que tiene un arreglo de números para esta capacidad, donde esta 1685 01:16:57,680 --> 01:17:00,920 es una gran constante como 100 o 1000, sin importar cuántas bandejas quiero 1686 01:17:00,920 --> 01:17:04,010 almacenar, siempre y cuando realice un seguimiento del número 1687 01:17:04,010 --> 01:17:07,400 de bandejas que hay, de modo que siempre me asegure que su tamaño es inferior 1688 01:17:07,400 --> 01:17:08,690 o igual a la capacidad. 1689 01:17:08,690 --> 01:17:11,630 Solo para estar seguro de que no intenté meter demasiadas bandejas allí. 1690 01:17:11,630 --> 01:17:14,450 Pero ¿cuál es un inconveniente de esta implementación 1691 01:17:14,450 --> 01:17:17,080 en la pila de bandejas de Mather House? 1692 01:17:17,080 --> 01:17:20,900 1693 01:17:20,900 --> 01:17:23,750 PÚBLICO: [INAUDIBLE] 1694 01:17:23,750 --> 01:17:25,250 DAVID: Espacio limitado, exactamente. 1695 01:17:25,250 --> 01:17:29,110 Apliqué conscientemente un hardcode a la capacidad de ser un valor fijo. 1696 01:17:29,110 --> 01:17:33,780 Entonces, si compramos una bandeja nueva o una caja completa de bandejas, 1697 01:17:33,780 --> 01:17:35,020 podría no encajar allí, ¿cierto? 1698 01:17:35,020 --> 01:17:37,964 Una vez que agote este espacio restante, necesito formar una nueva pila 1699 01:17:37,964 --> 01:17:39,380 o necesito guardarlas en otro lugar. 1700 01:17:39,380 --> 01:17:40,780 Me quedé sin espacio. 1701 01:17:40,780 --> 01:17:43,950 Así que tal vez esta es una buena decisión de diseño porque refleja la realidad. 1702 01:17:43,950 --> 01:17:47,130 O tal vez es estúpida porque ahora ya no puedo almacenar más bandejas 1703 01:17:47,130 --> 01:17:49,260 cuando llegan por envío. 1704 01:17:49,260 --> 01:17:50,520 Podría resolver eso. 1705 01:17:50,520 --> 01:17:53,096 Sabemos, gracias a nuestro breve ejemplo de hace un momento, 1706 01:17:53,096 --> 01:17:54,720 que podríamos hacer que nuestro arreglo sea dinámico. 1707 01:17:54,720 --> 01:17:57,330 No preasignarlo para que tenga capacidad de tamaño. 1708 01:17:57,330 --> 01:18:00,270 Simplemente declarar que es un puntero que finalmente 1709 01:18:00,270 --> 01:18:03,090 señalara el espacio tal vez para una, 100 bandejas, 1710 01:18:03,090 --> 01:18:08,280 1000 bandejas, o quizás 1001 bandejas si redistribuimos el espacio una y otra vez. 1711 01:18:08,280 --> 01:18:11,280 Y cuando comiencen a escribir códigos que involucren a otras personas, ya sea 1712 01:18:11,280 --> 01:18:15,090 para algún proyecto escolar, un proyecto personal o el mundo real, 1713 01:18:15,090 --> 01:18:16,860 es aquí donde la vida también se vuelve más interesante, 1714 01:18:16,860 --> 01:18:20,910 porque siempre y cuando ustedes y yo, si mi colega decide, OK, 1715 01:18:20,910 --> 01:18:23,670 Voy a exponer push y pop como las operaciones. 1716 01:18:23,670 --> 01:18:25,230 Implementaré push y pop. 1717 01:18:25,230 --> 01:18:28,350 No tienen que preocuparse por los detalles de implementación 1718 01:18:28,350 --> 01:18:30,450 de bajo nivel en mis propias decisiones de diseño. 1719 01:18:30,450 --> 01:18:33,120 Solo tienen que leer mi documentación y 1720 01:18:33,120 --> 01:18:37,650 no importa cómo lo implementé porque lo he separado para ustedes 1721 01:18:37,650 --> 01:18:39,000 y les he dado solo una API. 1722 01:18:39,000 --> 01:18:42,630 Push and pop sería una API, una interfaz de programación de aplicaciones. 1723 01:18:42,630 --> 01:18:44,880 Todo lo que necesitan saber es que pueden confiar 1724 01:18:44,880 --> 01:18:46,710 que implementaré push y pop. 1725 01:18:46,710 --> 01:18:50,756 Y puede que no les guste, a fin de cuentas, si limito su espacio, 1726 01:18:50,756 --> 01:18:53,130 pero para entenderlo necesitan leer la documentación, 1727 01:18:53,130 --> 01:18:56,610 para que sepan qué funciones proporciona mi implementación. 1728 01:18:56,610 --> 01:19:00,960 Esto, por supuesto, es la ridiculez que se produce cada año, más o menos, 1729 01:19:00,960 --> 01:19:03,000 por la cual las personas hacen fila para comprar un iPhone. 1730 01:19:03,000 --> 01:19:06,840 Ahora, ¿por qué sería malo si Apple utilizara una pila cuando las personas 1731 01:19:06,840 --> 01:19:10,330 llegan a las 3:00 a. m. para comprar sus iPhones? 1732 01:19:10,330 --> 01:19:12,800 Sí. 1733 01:19:12,800 --> 01:19:14,306 PÚBLICO: [INAUDIBLE] 1734 01:19:14,306 --> 01:19:15,180 DAVID: Exactamente, 1735 01:19:15,180 --> 01:19:17,388 La persona que llegó al último conseguiría primero su teléfono, 1736 01:19:17,388 --> 01:19:19,650 lo cual sería fantástico para esa persona. 1737 01:19:19,650 --> 01:19:21,730 pero sería muy injusto para todos los demás. 1738 01:19:21,730 --> 01:19:24,660 Así que Apple, como la mayoría de tiendas, si tienen este problema, usan 1739 01:19:24,660 --> 01:19:30,750 colas o filas como una estructura de datos FIFO, primero en entrar, primero en salir. 1740 01:19:30,750 --> 01:19:34,260 Donde la primera persona en la fila obtiene primero su iPhone. 1741 01:19:34,260 --> 01:19:37,160 Entonces, ¿cómo pueden implementar esas operaciones o esa API? 1742 01:19:37,160 --> 01:19:40,750 Podríamos llamarlo nq y dq, o sumar y restar, lo que sea, 1743 01:19:40,750 --> 01:19:42,180 pero estos son los términos especializados. 1744 01:19:42,180 --> 01:19:43,830 Y podemos implementarlos de la siguiente manera. 1745 01:19:43,830 --> 01:19:48,521 Una cola puede necesitar solo un poco más de información que capacidad y tamaño 1746 01:19:48,521 --> 01:19:49,020 solamente. 1747 01:19:49,020 --> 01:19:51,420 Tienen que recordar quién está al frente, potencialmente, 1748 01:19:51,420 --> 01:19:53,790 para que cuando esa persona se salga de la fila, 1749 01:19:53,790 --> 01:19:56,490 no tengan que mover todos los datos del arreglo 1750 01:19:56,490 --> 01:19:58,232 al igual que los humanos caminan hacia adelante. 1751 01:19:58,232 --> 01:19:59,190 Eso sería una pérdida de tiempo 1752 01:19:59,190 --> 01:20:01,320 cada vez que alguien esté listo para comprar su teléfono, 1753 01:20:01,320 --> 01:20:04,320 ¿Por qué n-1 personas tienen que dar un paso adelante? 1754 01:20:04,320 --> 01:20:08,850 ¿Por qué no les traen el teléfono y se ahorra ese uso ineficiente del tiempo? 1755 01:20:08,850 --> 01:20:12,150 O podríamos hacerlo así, más como una estructura de datos dinámica. 1756 01:20:12,150 --> 01:20:13,770 Y no haremos el código aquí, 1757 01:20:13,770 --> 01:20:17,080 pero vimos el ejemplo en nuestra lista cero, uno, 1758 01:20:17,080 --> 01:20:20,790 y dos códigos, cómo podríamos comenzar con un arreglo de tamaño fijo, 1759 01:20:20,790 --> 01:20:24,930 hacerlo dinámico con malloc y realloc, y cómo podríamos 1760 01:20:24,930 --> 01:20:28,980 volverlo dinámico con una lista vinculada, aunque con intercambios de tiempo 1761 01:20:28,980 --> 01:20:29,970 y espacio. 1762 01:20:29,970 --> 01:20:33,686 Les traigo un genial video corto que pensé en compartir con ustedes, en el que Jack 1763 01:20:33,686 --> 01:20:36,810 aprende los hechos sobre las colas y las pilas, que distinguen a estas dos 1764 01:20:36,810 --> 01:20:39,660 estructuras de datos de un modo que plasma una imagen más clara sobre el modo 1765 01:20:39,660 --> 01:20:40,230 en que son distintos. 1766 01:20:40,230 --> 01:20:42,230 Atenuemos las luces durante 60 segundos, más o menos. 1767 01:20:42,230 --> 01:20:49,354 1768 01:20:49,354 --> 01:20:50,020 [REPRODUCCIÓN DE VIDEO] 1769 01:20:50,020 --> 01:20:52,930 Había una vez en la ciudad un tipo llamado Jack. 1770 01:20:52,930 --> 01:20:56,350 Cuando de hacer amigos se trataba, Jack no tenía habilidad. 1771 01:20:56,350 --> 01:20:59,260 Así que Jack fue a hablar con el chico más popular. 1772 01:20:59,260 --> 01:21:01,880 A su amigo Lu fue a ver y le preguntó: ¿qué puedo hacer? 1773 01:21:01,880 --> 01:21:04,480 Lu vio que su amigo estaba realmente afligido. 1774 01:21:04,480 --> 01:21:06,970 Bueno, dijo Lu, solo mira cómo estás vestido. 1775 01:21:06,970 --> 01:21:09,730 ¿No tienes ropa decente con apariencia diferente? 1776 01:21:09,730 --> 01:21:10,690 Sí, dijo Jack. 1777 01:21:10,690 --> 01:21:11,860 Sí tengo, la verdad. 1778 01:21:11,860 --> 01:21:14,320 Ven a mi casa y verás qué es lo que pasa. 1779 01:21:14,320 --> 01:21:17,260 Entonces fueron a su casa y Jack le mostró a Lu la caja 1780 01:21:17,260 --> 01:21:20,270 que usaba para fines, de guardar camisas, pantalones y calcetines. 1781 01:21:20,270 --> 01:21:23,350 Lu dijo, veo que tienes toda tu ropa en una pila. 1782 01:21:23,350 --> 01:21:25,870 ¿Por qué no usas otra cosa, de vez en cuando de esta fila? 1783 01:21:25,870 --> 01:21:29,050 Jack dijo, bueno, cuando me quito los calcetines y la ropa, 1784 01:21:29,050 --> 01:21:31,810 los lavo y los guardo en la caja, antes de que se hagan una sopa, 1785 01:21:31,810 --> 01:21:34,260 Luego llega la mañana y me levanto, 1786 01:21:34,260 --> 01:21:37,470 voy a la caja y tomo la ropa que está en lo más alto. 1787 01:21:37,470 --> 01:21:40,120 Lu rápidamente se dio cuenta del problema que tenía Jack. 1788 01:21:40,120 --> 01:21:43,150 El guardaba la ropa, los CD y los libros en un stack, 1789 01:21:43,150 --> 01:21:45,460 cuando tomaba algo para leer o ropa interior, 1790 01:21:45,460 --> 01:21:48,130 elegía el libro o la ropa que estaba en la parte superior. 1791 01:21:48,130 --> 01:21:50,430 Luego, cuando la desocupaba, la ponía de vuelta en su lugar, 1792 01:21:50,430 --> 01:21:52,990 y ese de vuelta significaba, el mismo sitio de donde la fue a tomar. 1793 01:21:52,990 --> 01:21:55,510 Conozco la solución, dijo Lu triunfante. 1794 01:21:55,510 --> 01:21:58,090 En usar una cola, debes aprender a ubicarte. 1795 01:21:58,090 --> 01:22:00,880 Lu tomó la ropa de Jack y en un armario la colgó, 1796 01:22:00,880 --> 01:22:03,730 cuando la terminó de vaciar la caja simplemente tiró. 1797 01:22:03,730 --> 01:22:07,480 Jack, cuando el día esté por finalizar pon tu ropa siempre a la izquierda 1798 01:22:07,480 --> 01:22:09,066 cuando ya no la vayas a usar. 1799 01:22:09,066 --> 01:22:10,815 Entonces, por la mañana cuando veas el sol brillar 1800 01:22:10,815 --> 01:22:14,440 la ropa de la derecha debes tomar, donde la fila veas acabar. 1801 01:22:14,440 --> 01:22:17,410 ¿No lo ves ?, dijo Lu, será muy agradable ser tú. 1802 01:22:17,410 --> 01:22:20,790 Te pondrás todo una vez antes que ponerte algo dos veces al revés. 1803 01:22:20,790 --> 01:22:23,640 Y con todas las colas en su armario y estante, no hechas bolas, 1804 01:22:23,640 --> 01:22:26,680 Jack comenzó a sentirse muy seguro con su forma de vestirse, 1805 01:22:26,680 --> 01:22:30,157 y fue todo gracias a Lu y a sus colas hechas como las harías tú. 1806 01:22:30,157 --> 01:22:30,740 [FINALIZA LA REPRODUCCIÓN] 1807 01:22:30,740 --> 01:22:34,460 DAVID: Pero eso no quiere decir que las colas lo son todo 1808 01:22:34,460 --> 01:22:36,032 y que las pilas son una mala estructura de datos. 1809 01:22:36,032 --> 01:22:37,990 En realidad, cada una tiene sus propias aplicaciones. 1810 01:22:37,990 --> 01:22:40,990 Y, de hecho, un uso común para pilas, más allá de la administración de memoria, 1811 01:22:40,990 --> 01:22:44,350 como lo discutimos hace un par de semanas, cuando comenzamos a explorar HTML y 1812 01:22:44,350 --> 01:22:47,342 programación web, verán que ese HTML, en sí, 1813 01:22:47,342 --> 01:22:49,300 es el idioma en el que se escriben las páginas web 1814 01:22:49,300 --> 01:22:51,520 que pronto podrán escribir, si no es que ya lo hacen. 1815 01:22:51,520 --> 01:22:55,030 Este es un lenguaje que en realidad tiene una jerarquía anidada, 1816 01:22:55,030 --> 01:23:00,040 la cual, mediante un navegador, podría usar una pila para analizar el HTML 1817 01:23:00,040 --> 01:23:03,940 que compone una página web, a fin de determinar, por ejemplo, si es correcta o no. 1818 01:23:03,940 --> 01:23:07,330 Pero hay muchas herramientas que ahora podemos agregar al kit de herramientas. 1819 01:23:07,330 --> 01:23:10,270 Y a pesar de que veremos cada una de ellas brevemente, todas 1820 01:23:10,270 --> 01:23:13,450 son derivadas de estos dos principios simples, la capacidad para llegar 1821 01:23:13,450 --> 01:23:17,170 a estructuras de datos personalizados, dentro de los cuales son punteros, 1822 01:23:17,170 --> 01:23:19,630 o la habilidad de unir una cosa a otra. 1823 01:23:19,630 --> 01:23:22,840 Aquí hay un ejemplo de lo que un especialista en sistemas llamaría árbol. 1824 01:23:22,840 --> 01:23:25,360 En el nodo de aquí hemos dibujado círculos, solo porque sí. 1825 01:23:25,360 --> 01:23:29,080 Pero los nodos en un árbol son muy parecidos a un árbol genealógico, donde 1826 01:23:29,080 --> 01:23:32,470 cada nodo tiene cero o más hijos o descendientes, tal vez 1827 01:23:32,470 --> 01:23:35,140 un padre u otros antepasados. 1828 01:23:35,140 --> 01:23:38,110 Y entonces llamaremos cosas como el primer nodo 1829 01:23:38,110 --> 01:23:42,010 en la parte superior de una estructura de datos llamada árbol, la raíz del árbol, 1830 01:23:42,010 --> 01:23:44,440 aunque crezca hacia abajo como este, como un árbol genealógico. 1831 01:23:44,440 --> 01:23:48,340 A cualquier cosa en la parte inferior del árbol que solo tenga flechas hacia dentro 1832 01:23:48,340 --> 01:23:51,380 se les llamará hijos u hojas del árbol. 1833 01:23:51,380 --> 01:23:55,010 Y esta podría ser una forma de diseñar datos de manera útil. 1834 01:23:55,010 --> 01:23:57,970 De hecho, si recuerdan cuando teníamos cosas o números 1835 01:23:57,970 --> 01:24:01,660 como este, siempre que lidiábamos con números, palabras o Mikes Smiths, 1836 01:24:01,660 --> 01:24:04,690 simplemente los ordenábamos de izquierda a derecha en un arreglo 1837 01:24:04,690 --> 01:24:08,720 y luego lo buscábamos en la gran O del fin de los tiempos linealmente, de izquierda 1838 01:24:08,720 --> 01:24:09,220 a derecha. 1839 01:24:09,220 --> 01:24:10,810 ¿Pero fue mejor cuando usamos qué? 1840 01:24:10,810 --> 01:24:13,450 1841 01:24:13,450 --> 01:24:16,750 Búsqueda binaria, pero para la búsqueda binaria tendría que ser un arreglo 1842 01:24:16,750 --> 01:24:19,270 y necesitaría estar ordenado. 1843 01:24:19,270 --> 01:24:22,120 Y el problema con el que jamás me enfrenté fue que nunca 1844 01:24:22,120 --> 01:24:24,520 agregué otra página a la guía telefónica. 1845 01:24:24,520 --> 01:24:27,070 En realidad, nunca tratamos de añadir más números a nuestro arreglo. 1846 01:24:27,070 --> 01:24:30,700 Y, sin embargo, hoy identificamos estos problemas tan evidentes con los arreglos, 1847 01:24:30,700 --> 01:24:33,532 que pareciera que nos tienen arrinconados. 1848 01:24:33,532 --> 01:24:36,490 Si asignamos demasiado espacio, lo usamos todo, luego maldecimos 1849 01:24:36,490 --> 01:24:38,860 y deseamos agregar más al arreglo. 1850 01:24:38,860 --> 01:24:44,110 Entonces, ¿cómo podemos aún diseñar datos en forma ordenada, 1851 01:24:44,110 --> 01:24:46,450 aprovechar algo así como el tiempo logarítmico y dividir 1852 01:24:46,450 --> 01:24:50,740 y vencer, pero obtener el beneficio diario del dinamismo mediante el cual 1853 01:24:50,740 --> 01:24:54,670 podemos hacer crecer la estructura de datos y reducirla de forma gradual, 1854 01:24:54,670 --> 01:24:58,330 sin tener que reasignar repentinamente toda la estructura? 1855 01:24:58,330 --> 01:25:01,120 Bueno, en vez de presentar estos números, que están convenientemente 1856 01:25:01,120 --> 01:25:05,050 numerados como múltiplos de 11, es decir, 22, 33, 55, 1857 01:25:05,050 --> 01:25:07,960 ¿qué pasa si los presentamos así en la memoria? 1858 01:25:07,960 --> 01:25:11,590 No miraremos al código para hacer esto, pero piensen en cada uno de estos círculos 1859 01:25:11,590 --> 01:25:15,340 como una estructura, una estructura de datos, dentro de la cual hay 1860 01:25:15,340 --> 01:25:18,940 un int n, ¿y cuántos punteros aparentemente? 1861 01:25:18,940 --> 01:25:21,820 1862 01:25:21,820 --> 01:25:23,220 Siete en total en la pantalla. 1863 01:25:23,220 --> 01:25:25,560 Pero, ¿qué tal dentro de cada nodo, como este de aquí? 1864 01:25:25,560 --> 01:25:27,630 Hay un número n, 55. 1865 01:25:27,630 --> 01:25:28,330 ¿Y qué más? 1866 01:25:28,330 --> 01:25:29,850 ¿Cuántos punteros? 1867 01:25:29,850 --> 01:25:30,914 Solo dos. 1868 01:25:30,914 --> 01:25:33,330 Dos como máximo, porque las hojas al parecer 1869 01:25:33,330 --> 01:25:34,980 son cero por definición. 1870 01:25:34,980 --> 01:25:38,640 Y técnicamente, si no hubiera agregado 22, tal vez podría haber solo un niño. 1871 01:25:38,640 --> 01:25:42,960 Esto es lo que llamamos un árbol binario porque cada nodo tiene 1872 01:25:42,960 --> 01:25:45,330 como máximo dos niños, 0, 1 o 2. 1873 01:25:45,330 --> 01:25:48,900 Y es un árbol de búsqueda binario porque tiene una propiedad especial, 1874 01:25:48,900 --> 01:25:55,110 es muy buscable, porque si vemos cualquier nodo, su hijo izquierdo es más pequeño. 1875 01:25:55,110 --> 01:25:58,180 Y si vemos a cualquier nodo, su hijo derecho es más grande. 1876 01:25:58,180 --> 01:26:00,210 Y esa es una definición recursiva, por así decirlo. 1877 01:26:00,210 --> 01:26:04,020 Podemos ver cualquier nodo que tenga el árbol y esa definición es verdadera, 1878 01:26:04,020 --> 01:26:06,660 incluso en las hojas, porque es una especie de declaración vacía 1879 01:26:06,660 --> 01:26:09,600 decir que es mayor que su hijo izquierdo si no hay un hijo izquierdo. 1880 01:26:09,600 --> 01:26:12,220 Es algo trivialmente cierto. 1881 01:26:12,220 --> 01:26:14,550 Entonces, ¿qué tiene de bueno esta estructura de datos? 1882 01:26:14,550 --> 01:26:17,700 Bueno, supongamos que quiero buscar el número 22. 1883 01:26:17,700 --> 01:26:21,840 Como nuestra lista vinculada, y como Olivia es el primer puntero especial, 1884 01:26:21,840 --> 01:26:24,330 un árbol binario en la memoria de una computadora simplemente 1885 01:26:24,330 --> 01:26:28,050 tiene un puntero especial, llamado root o first, o como sea que quieran llamarlo. 1886 01:26:28,050 --> 01:26:31,770 Y si queremos buscar 22. al igual que Olivia y Jess, 1887 01:26:31,770 --> 01:26:32,700 podríamos ver aquí. 1888 01:26:32,700 --> 01:26:35,130 Y decir, hmm, 55 es mayor que 22. 1889 01:26:35,130 --> 01:26:37,080 Entonces, ¿qué camino debo seguir? 1890 01:26:37,080 --> 01:26:37,877 El de la izquierda, obviamente. 1891 01:26:37,877 --> 01:26:39,960 Y aquí, ya saben, si estuviéramos haciendo esto visualmente 1892 01:26:39,960 --> 01:26:42,120 podríamos cortar ese subárbol completamente. 1893 01:26:42,120 --> 01:26:45,210 Y verían que la mitad del problema es arrancado como con la guía telefónica. 1894 01:26:45,210 --> 01:26:48,130 22 versus 33, por supuesto que este es mayor. 1895 01:26:48,130 --> 01:26:50,080 Así que vamos aquí y lo encontramos. 1896 01:26:50,080 --> 01:26:52,204 Y en resumen, eso no fue lineal 1897 01:26:52,204 --> 01:26:54,120 porque no estábamos buscando todos los nodos. 1898 01:26:54,120 --> 01:26:57,240 Y si conceptualmente estábamos cortando el árbol a la mitad, 1899 01:26:57,240 --> 01:26:59,910 y a la mitad, y a la mitad cada vez que nos fuimos a la izquierda o a la derecha, 1900 01:26:59,910 --> 01:27:04,080 ¿Cuál debería ser el tiempo de ejecución de búsqueda en un árbol de búsqueda binario? 1901 01:27:04,080 --> 01:27:07,410 Log base 2 de n, o simplemente logarítmico como ya hemos visto. 1902 01:27:07,410 --> 01:27:10,510 No es necesario que siempre esté tan bellamente equilibrado. 1903 01:27:10,510 --> 01:27:12,370 Eso se elige de forma bastante deliberada. 1904 01:27:12,370 --> 01:27:15,150 Pueden ocurrir situaciones perversas donde simplemente cambia 1905 01:27:15,150 --> 01:27:17,220 en una larga lista vinculada. 1906 01:27:17,220 --> 01:27:18,900 Pero aún será un árbol de búsqueda binario. 1907 01:27:18,900 --> 01:27:21,900 Estaba mal construido, pero si al menos mantenemos un equilibrio como este, 1908 01:27:21,900 --> 01:27:23,190 podríamos obtener algunos beneficios. 1909 01:27:23,190 --> 01:27:27,171 Y así es como implementaríamos el número entero que proponen y dos nodos, 1910 01:27:27,171 --> 01:27:28,920 En vez de llamarlo simplemente next, 1911 01:27:28,920 --> 01:27:32,100 lo llamaré de un modo más útil semánticamente, left y right. 1912 01:27:32,100 --> 01:27:35,550 Y noten que struct node es solo un puntero llamado left, 1913 01:27:35,550 --> 01:27:37,614 o que struct node es un puntero llamado right. 1914 01:27:37,614 --> 01:27:39,030 Y así es como implementamos esto. 1915 01:27:39,030 --> 01:27:43,380 ¿Y qué creen que tienen las hojas como valores para izquierda y derecha? 1916 01:27:43,380 --> 01:27:46,230 Las hojas del árbol no tenían hijos, por definición, 1917 01:27:46,230 --> 01:27:48,041 ¿cuál es el valor de izquierda y derecha? 1918 01:27:48,041 --> 01:27:48,540 Nulo. 1919 01:27:48,540 --> 01:27:53,380 Entonces están simplemente apuntando hacia el piso como valores cero, nulos. 1920 01:27:53,380 --> 01:27:56,160 Por lo tanto, no vamos a escribir el código para esto ahora, 1921 01:27:56,160 --> 01:27:59,820 pero podemos aprovechar las ideas del cero débil. 1922 01:27:59,820 --> 01:28:01,240 Divide y vencerás, búsqueda binaria. 1923 01:28:01,240 --> 01:28:04,020 Podemos aprovechar lo que vimos la semana pasada, las ideas sobre estructuras de esta 1924 01:28:04,020 --> 01:28:07,050 la memoria dinámica y el heap para 1925 01:28:07,050 --> 01:28:10,140 comenzar a construir estructuras de datos como esta, que ahora nos dan dinamismo 1926 01:28:10,140 --> 01:28:12,540 que puede crecer y reducirse según sea necesario. 1927 01:28:12,540 --> 01:28:14,640 Ahora que han visto el código, aquí podría 1928 01:28:14,640 --> 01:28:18,780 hacerse la implementación de una función para el árbol de búsqueda binaria 1929 01:28:18,780 --> 01:28:22,584 que, dadas las raíces del árbol, encuentre para nosotros verdadero o falso, 1930 01:28:22,584 --> 01:28:24,000 ya sea que haya o no algo adentro. 1931 01:28:24,000 --> 01:28:27,090 Entonces, quiero buscar un número n en este árbol. 1932 01:28:27,090 --> 01:28:29,760 Esto que está aquí es, de nuevo, un puntero a la raíz 1933 01:28:29,760 --> 01:28:34,350 al igual que Olivia era un puntero al primer nodo en la lista vinculada. 1934 01:28:34,350 --> 01:28:37,205 Entonces, si el árbol es nulo, devuelve falso porque es 1935 01:28:37,205 --> 01:28:38,580 una pregunta tonta. 1936 01:28:38,580 --> 01:28:41,250 Si no pasa ningún árbol, claramente no está allí. 1937 01:28:41,250 --> 01:28:42,030 Entonces devuelve falso. 1938 01:28:42,030 --> 01:28:46,200 Es nuestro caso especial para garantizar que no nos sumerjamos demasiado. 1939 01:28:46,200 --> 01:28:49,650 Pero aquí hay una aplicación genial de una idea anterior. 1940 01:28:49,650 --> 01:28:55,740 Si n es menor que n en el nodo actual del árbol 1941 01:28:55,740 --> 01:28:58,950 y recuerden que la flecha simplemente dice: ve y mira a n, 1942 01:28:58,950 --> 01:29:02,430 sabemos que queremos mirar hacia el lado izquierdo del árbol. 1943 01:29:02,430 --> 01:29:07,002 Entonces, ¿tenemos un algoritmo para buscar un árbol según un valor específico? 1944 01:29:07,002 --> 01:29:09,210 Lo que sucede es que ese árbol ahora es más pequeño porque 1945 01:29:09,210 --> 01:29:11,340 es la mitad del árbol que está a la izquierda. 1946 01:29:11,340 --> 01:29:12,230 Lo tenemos. 1947 01:29:12,230 --> 01:29:15,960 Tenemos una función llamada búsqueda, la cual toma un número como entrada 1948 01:29:15,960 --> 01:29:17,786 y toma un árbol como puntero. 1949 01:29:17,786 --> 01:29:19,410 No tiene que ser el árbol completo. 1950 01:29:19,410 --> 01:29:23,550 Puede ser un subárbol porque, una vez más, un árbol se define de manera recursiva, 1951 01:29:23,550 --> 01:29:27,340 ya que, cada niño de la izquierda y de la derecha puede tener hijos. 1952 01:29:27,340 --> 01:29:29,790 Entonces, es un árbol más pequeño, pero sigue siendo un árbol. 1953 01:29:29,790 --> 01:29:31,170 Así que puedo responder a esa pregunta. 1954 01:29:31,170 --> 01:29:34,920 Si n es menor que el valor n propio del nodo actual, 1955 01:29:34,920 --> 01:29:39,690 Puedo regresar la respuesta a la búsqueda de llamadas del mismo número, 1956 01:29:39,690 --> 01:29:41,670 pero pasando justo por la mitad izquierda del árbol. 1957 01:29:41,670 --> 01:29:45,780 Entonces es como la versión en árbol de romper la guía telefónica a la mitad 1958 01:29:45,780 --> 01:29:48,120 y buscar solo en la mitad izquierda. 1959 01:29:48,120 --> 01:29:51,750 Y quizás podamos adivinar, si seguimos en este punto, 1960 01:29:51,750 --> 01:29:53,970 si n es mayor que el nodo actual, 1961 01:29:53,970 --> 01:29:56,100 buscaremos a la derecha. 1962 01:29:56,100 --> 01:29:57,300 Y así serían tres casos. 1963 01:29:57,300 --> 01:30:00,630 ¿Cuál es el cuarto caso posible? 1964 01:30:00,630 --> 01:30:03,030 Sí, si n es igual al nodo actual. 1965 01:30:03,030 --> 01:30:06,060 Y en ese caso, de modo trivial devolverá verdadero. 1966 01:30:06,060 --> 01:30:07,770 Eso es algo hermoso. 1967 01:30:07,770 --> 01:30:10,230 No tiene una sola perspectiva. 1968 01:30:10,230 --> 01:30:12,600 No es obvio cómo funciona a primera vista. 1969 01:30:12,600 --> 01:30:15,999 Y no es necesariamente cómodo si no se utiliza tanto la recursividad. 1970 01:30:15,999 --> 01:30:17,790 Pero lo que es bello de esto, en especial, 1971 01:30:17,790 --> 01:30:20,290 es que, si nos deshacemos de las tontas llaves y de un montón de cosas, 1972 01:30:20,290 --> 01:30:22,180 no es realmente intelectualmente interesante, 1973 01:30:22,180 --> 01:30:26,330 reducimos el problema a tan solo estas líneas de código. 1974 01:30:26,330 --> 01:30:28,780 Comprueba si es nulo, devuelve falso. 1975 01:30:28,780 --> 01:30:31,630 Comprueba si es menor que, solo recursa a la izquierda. 1976 01:30:31,630 --> 01:30:33,880 Comprueba si es mayor que, recursa a la derecha. 1977 01:30:33,880 --> 01:30:35,410 De lo contrario, lo encontraste. 1978 01:30:35,410 --> 01:30:39,370 Es la misma idea o pensamiento que nuestro enfoque de divide y vencerás 1979 01:30:39,370 --> 01:30:41,890 en el caso de la guía telefónica que recién implementamos 1980 01:30:41,890 --> 01:30:46,700 utilizando árboles o nodos unidos entre sí en un árbol. 1981 01:30:46,700 --> 01:30:47,900 ¿Sí? 1982 01:30:47,900 --> 01:30:51,580 PÚBLICO: [INAUDIBLE] 1983 01:30:51,580 --> 01:30:56,320 DAVID: Árbol, flecha, n, recuerden que "tree" es un puntero a un nodo, 1984 01:30:56,320 --> 01:31:00,340 al igual que Olivia era un puntero a un nodo en una lista vinculada, 1985 01:31:00,340 --> 01:31:02,560 eso sería como tener a Olivia aquí parada y en vez 1986 01:31:02,560 --> 01:31:05,890 de señalar a una fila de estudiantes, señalara a un árbol de estudiantes 1987 01:31:05,890 --> 01:31:07,540 que se abre en abanico de esta manera. 1988 01:31:07,540 --> 01:31:09,670 Entonces árbol, podríamos llamarlo como queramos, 1989 01:31:09,670 --> 01:31:13,430 solo se me ocurrió llamarlo así, lo representa. 1990 01:31:13,430 --> 01:31:18,229 Y mientras tanto, el árbol que queda sería como si Olivia apuntara a un nodo aquí. 1991 01:31:18,229 --> 01:31:20,770 De hecho, si Olivia señala la raíz del árbol, 1992 01:31:20,770 --> 01:31:24,040 el árbol a la izquierda implicaría ver hacia la mitad izquierda del árbol 1993 01:31:24,040 --> 01:31:25,660 o hacia la mitad derecha del árbol. 1994 01:31:25,660 --> 01:31:28,990 Si nuestros voluntarios fueran mostrados en el escenario como un abanico, 1995 01:31:28,990 --> 01:31:31,310 como un árbol en vez de una lista. 1996 01:31:31,310 --> 01:31:34,690 Entonces hemos visto muchos algoritmos que podrían 1997 01:31:34,690 --> 01:31:36,520 tener cualquier cantidad de estos tiempos de ejecución. 1998 01:31:36,520 --> 01:31:38,830 Y hasta ahora el mejor tiempo de ejecución 1999 01:31:38,830 --> 01:31:42,044 ha sido el de los algoritmos más sofisticados. 2000 01:31:42,044 --> 01:31:43,960 Pero hemos visto un tiempo constante aquí y allá. 2001 01:31:43,960 --> 01:31:46,420 E incluso ahora si queremos insertarlo en una lista vinculada 2002 01:31:46,420 --> 01:31:48,190 y no nos importa realmente el orden, 2003 01:31:48,190 --> 01:31:52,870 podemos conectar el nuevo valor justo después de Olivia y antes de Achmed, 2004 01:31:52,870 --> 01:31:54,160 y obtener nuestro tiempo constante. 2005 01:31:54,160 --> 01:31:57,790 Pero ¿no sería genial si más operaciones fueran constantes en el tiempo? 2006 01:31:57,790 --> 01:32:00,790 ¿Un paso, dos pasos, tres pasos o algún número finito? 2007 01:32:00,790 --> 01:32:04,240 Y podemos lograrlo con un poco de razonamiento. 2008 01:32:04,240 --> 01:32:07,840 Podemos aprovechar otro tipo de idea familiar de la siguiente manera. 2009 01:32:07,840 --> 01:32:12,340 Por ejemplo, aquí tenemos algunos naipes inusualmente grandes, 2010 01:32:12,340 --> 01:32:15,280 que solo conocerán si ponen en Google "jumbo cards" 2011 01:32:15,280 --> 01:32:17,620 y las buscan en Amazon. 2012 01:32:17,620 --> 01:32:20,260 Supongamos que quiero ordenar este mazo de cartas, 2013 01:32:20,260 --> 01:32:23,320 Para eso podría pasar el mazo de uno en uno 2014 01:32:23,320 --> 01:32:26,380 y ordenarlas, tanto por su palo, como clubes y corazones 2015 01:32:26,380 --> 01:32:28,180 como por sus números también. 2016 01:32:28,180 --> 01:32:30,680 Pero si son como yo, probablemente intentarán 2017 01:32:30,680 --> 01:32:32,260 simplificar un poco el problema. 2018 01:32:32,260 --> 01:32:35,937 Entonces, si ven al rey de espadas que puse aquí, 2019 01:32:35,937 --> 01:32:37,770 el nueve de espadas que pongo acá, 2020 01:32:37,770 --> 01:32:39,120 y el 10 de espadas, casualmente, 2021 01:32:39,120 --> 01:32:40,453 que pondré allá. 2022 01:32:40,453 --> 01:32:42,790 Entonces, ¿probablemente haré lo mismo que con los corazones? 2023 01:32:42,790 --> 01:32:46,030 Saben, creo que no voy a pasar de una a la vez, 2024 01:32:46,030 --> 01:32:48,340 sino que voy a clasificar cada una de las cartas. 2025 01:32:48,340 --> 01:32:51,714 Aquí está el as de tréboles, así que voy a hacer un tercer montón, 2026 01:32:51,714 --> 01:32:52,880 aquí hay un par de diamantes, 2027 01:32:52,880 --> 01:32:53,921 y esa será mi cuarta pila, 2028 01:32:53,921 --> 01:32:57,340 luego voy a repetir esto, pues es un simple algoritmo 2029 01:32:57,340 --> 01:33:00,040 que me hará la vida un poco más fácil en tan solo unos instantes, 2030 01:33:00,040 --> 01:33:05,440 una vez que todo esté en la pila correcta. 2031 01:33:05,440 --> 01:33:08,860 Pero esto es una noción general de lo que llamamos hashing. 2032 01:33:08,860 --> 01:33:11,470 Y no voy a terminar porque sorpresa, sorpresa, 2033 01:33:11,470 --> 01:33:13,480 vamos a tener 13 cartas en cada pila. 2034 01:33:13,480 --> 01:33:17,110 Pero esta es una noción más esencial del hashing. 2035 01:33:17,110 --> 01:33:20,710 Tomamos como entrada algo de la lista de entradas, 2036 01:33:20,710 --> 01:33:23,080 lo observamos y tomamos una decisión basada en eso. 2037 01:33:23,080 --> 01:33:26,530 Y en este caso, mi valor hash va a ser cero, uno, dos, tres, 2038 01:33:26,530 --> 01:33:28,840 dos porque entrará en la pila de corazones. 2039 01:33:28,840 --> 01:33:30,151 ¿Y qué es una función hash? 2040 01:33:30,151 --> 01:33:32,650 Solo es una función en el código o en mi cerebro que 2041 01:33:32,650 --> 01:33:36,820 toma una decisión con base en la salida y genera un valor hash que, 2042 01:33:36,820 --> 01:33:40,030 en este caso, será esa pila, esa pila, esa pila, esa pila, 2043 01:33:40,030 --> 01:33:43,180 o si queremos ser más precisos, cero, uno, dos, tres, 2044 01:33:43,180 --> 01:33:45,880 Si esas cuatro pilas se implementan, serán como cuatro arreglos 2045 01:33:45,880 --> 01:33:47,410 o algún tipo de pilas. 2046 01:33:47,410 --> 01:33:49,630 Parece que estoy haciendo una pila de cartas. 2047 01:33:49,630 --> 01:33:50,440 Todavía no termino. 2048 01:33:50,440 --> 01:33:52,510 Si quiero ordenar esto más tarde, 2049 01:33:52,510 --> 01:33:54,880 todavía tendré que ordenar cada una de las pilas de 13. 2050 01:33:54,880 --> 01:33:57,379 Pero de algún modo facilite un poco el problema 2051 01:33:57,379 --> 01:34:00,220 en el sentido de que lo extendí hacia cuatro problemas equivalentes, 2052 01:34:00,220 --> 01:34:03,020 pero el ingrediente clave aquí es la noción de hash. 2053 01:34:03,020 --> 01:34:06,580 Si alguna vez han visto a un profesor o asistente lidiar con esto 2054 01:34:06,580 --> 01:34:09,670 al final de una clase donde usan cuadernos azules, si todo un grupo de estudiantes 2055 01:34:09,670 --> 01:34:12,070 al final de la hora, va y comienza a entregar sus cuadernos azules 2056 01:34:12,070 --> 01:34:13,180 se vuelve un completo desastre. 2057 01:34:13,180 --> 01:34:16,217 Y si el asistente o el profesor quisieran organizarlos, 2058 01:34:16,217 --> 01:34:17,800 podrían hacer un montón de pilas. 2059 01:34:17,800 --> 01:34:19,300 Todos los apellidos con L irían allí, 2060 01:34:19,300 --> 01:34:20,080 las E irían acá, 2061 01:34:20,080 --> 01:34:21,100 las F irían allá 2062 01:34:21,100 --> 01:34:24,010 y en este caso se ordenarían alfabéticamente sobre la marcha, lo cual 2063 01:34:24,010 --> 01:34:25,600 facilitaría la resolución de este problema. 2064 01:34:25,600 --> 01:34:27,020 Eso es una función hash. 2065 01:34:27,020 --> 01:34:29,230 Se toma como entrada el nombre de un estudiante, 2066 01:34:29,230 --> 01:34:31,540 se observa la primera letra de su apellido, 2067 01:34:31,540 --> 01:34:34,270 y se decide si entra en el cubo cero, uno 2068 01:34:34,270 --> 01:34:37,662 o tal vez en la 25 si realmente se usó un hash con base en el alfabeto inglés. 2069 01:34:37,662 --> 01:34:40,120 Así que el hash es algo que todos hemos utilizado, aunque nunca 2070 01:34:40,120 --> 01:34:42,530 le hayamos puesto ese nombre. 2071 01:34:42,530 --> 01:34:44,530 Entonces, ¿cómo podemos aprovechar este tipo de ingrediente 2072 01:34:44,530 --> 01:34:47,980 y acercarnos más al santo grial de las estructuras de datos, que 2073 01:34:47,980 --> 01:34:49,780 serían un tiempo constante para todo? 2074 01:34:49,780 --> 01:34:53,230 Como nada de esto lineal, nada es tiempo logarítmico. 2075 01:34:53,230 --> 01:34:57,637 Entonces, supongamos que tenemos un arreglo o una tabla, así lo llamaremos. 2076 01:34:57,637 --> 01:35:00,220 Llamaré a esto una tabla hash porque quiero aprovechar 2077 01:35:00,220 --> 01:35:01,930 la idea de esta función hash. 2078 01:35:01,930 --> 01:35:06,760 Y supongamos que lo que quiero almacenar ahí son solo cosas como nombres 2079 01:35:06,760 --> 01:35:08,530 y que quiero almacenar el nombre 2080 01:35:08,530 --> 01:35:11,840 de Alice, porque ella devolvió su examen primero. 2081 01:35:11,840 --> 01:35:17,230 Entonces aquí podría tener de [0] hasta [25] o, en general, n-1. 2082 01:35:17,230 --> 01:35:19,616 Así que habría 26 cubos en total. 2083 01:35:19,616 --> 01:35:21,240 ¿Dónde creen que podría a Alice? 2084 01:35:21,240 --> 01:35:24,140 2085 01:35:24,140 --> 01:35:26,090 Tal vez usaría con ella el hash cero porque de Alice 2086 01:35:26,090 --> 01:35:27,800 usaríamos su nombre, no su apellido, porque parece 2087 01:35:27,800 --> 01:35:29,130 que jamás ha tenido un apellido. 2088 01:35:29,130 --> 01:35:31,310 Entonces, su nombre, Alice[0] va allí. 2089 01:35:31,310 --> 01:35:32,900 Luego es Bob quien devuelve su examen. 2090 01:35:32,900 --> 01:35:34,530 ¿Dónde va él? 2091 01:35:34,530 --> 01:35:39,200 en [1] y luego tal vez siga Brendan. 2092 01:35:39,200 --> 01:35:39,710 Diablos. 2093 01:35:39,710 --> 01:35:40,981 No hay lugar para el examen de Brendan. 2094 01:35:40,981 --> 01:35:41,480 ¿Por qué? 2095 01:35:41,480 --> 01:35:43,917 Porque su hash tiene el mismo valor. 2096 01:35:43,917 --> 01:35:44,750 Esas cosas pueden suceder. 2097 01:35:44,750 --> 01:35:46,640 El hash puede tener el mismo valor 2098 01:35:46,640 --> 01:35:47,990 y aquí no habría un gran problema. 2099 01:35:47,990 --> 01:35:49,698 Puedo seguir recibiendo diamantes, diamantes y diamantes, 2100 01:35:49,698 --> 01:35:51,770 lo cual está bien porque la estructura de datos crece. 2101 01:35:51,770 --> 01:35:54,140 Pero es un arreglo, al parecer. 2102 01:35:54,140 --> 01:35:56,540 Y podría poner a Alice aquí, podría poner a Bob acá, 2103 01:35:56,540 --> 01:35:58,490 pero también debería poner a Brendan acá. 2104 01:35:58,490 --> 01:36:02,150 Pero no quiero devolver el examen a Bob solo para aceptar el de Brendan. 2105 01:36:02,150 --> 01:36:03,646 Entonces, ¿dónde podría poner a Brendan? 2106 01:36:03,646 --> 01:36:06,770 Tal vez haga trampa y lo ponga aquí porque hay espacio, ¿verdad? 2107 01:36:06,770 --> 01:36:08,930 Todo es gratuito en esta historia hasta el momento. 2108 01:36:08,930 --> 01:36:11,150 Pero luego llega Charlie. 2109 01:36:11,150 --> 01:36:12,350 ¿Qué hacemos con Charlie? 2110 01:36:12,350 --> 01:36:14,660 Ahora Brendan está donde debería estar Charlie. 2111 01:36:14,660 --> 01:36:18,105 Creo que tenemos un lío aquí, pero tengo mucho espacio libre 2112 01:36:18,105 --> 01:36:21,230 y es probable que no tenga un estudiante, sin ofender, cuyo nombre comience 2113 01:36:21,230 --> 01:36:24,565 con la Z o la X, o... algunas de las menos probables estadísticamente. 2114 01:36:24,565 --> 01:36:25,940 Entonces, ¿por qué no usamos esos espacios? 2115 01:36:25,940 --> 01:36:28,640 Podríamos, pero este es un ejemplo algorítmico 2116 01:36:28,640 --> 01:36:32,270 de sondeo lineal, donde linealmente, de arriba hacia abajo, se explora 2117 01:36:32,270 --> 01:36:34,700 la estructura de datos para buscar espacio y dejar caer 2118 01:36:34,700 --> 01:36:37,010 los valores en el primer sitio disponible. 2119 01:36:37,010 --> 01:36:40,280 E inicialmente es agradable, limpio, amigable y eficiente 2120 01:36:40,280 --> 01:36:42,680 porque si después quiero buscar el examen de Alice, bum, 2121 01:36:42,680 --> 01:36:44,180 estará en la cima de la pila 2122 01:36:44,180 --> 01:36:45,860 y Bob, bum, será el segundo en la pila. 2123 01:36:45,860 --> 01:36:48,860 Pero Charlie, no estoy seguro dónde debería estar. 2124 01:36:48,860 --> 01:36:51,260 Así que finalmente, este enfoque del sondeo lineal 2125 01:36:51,260 --> 01:36:55,130 es eficiente en cuanto al espacio, ya que empaqueta todo en la estructura de datos, 2126 01:36:55,130 --> 01:36:57,770 pero con el tiempo se convierte en algo lineal. 2127 01:36:57,770 --> 01:37:01,210 Si Alice entrega al último su examen, debido a la naturaleza del espacio, 2128 01:37:01,210 --> 01:37:02,960 podría terminar en la parte inferior de la pila 2129 01:37:02,960 --> 01:37:05,720 y eso no facilitaría encontrarla posteriormente. 2130 01:37:05,720 --> 01:37:09,560 Entonces, ¿qué ocurre si cambiamos la estructura de los datos 2131 01:37:09,560 --> 01:37:12,980 y usamos elementos de hoy y del pasado? 2132 01:37:12,980 --> 01:37:17,480 Usemos, solo porque sí, un arreglo de punteros dibujados verticalmente. 2133 01:37:17,480 --> 01:37:22,054 Y luego, ¿Por qué no insertamos los nombres de los estudiantes a la derecha? 2134 01:37:22,054 --> 01:37:25,220 Es el fragmento de un texto que explora exactamente esta estructura de datos. 2135 01:37:25,220 --> 01:37:27,830 Se llama tabla hash, no con sondeo lineal, sino con 2136 01:37:27,830 --> 01:37:32,090 un encadenamiento separado, según el cual la estructura de datos, la tabla hash, 2137 01:37:32,090 --> 01:37:34,370 técnicamente es un arreglo. 2138 01:37:34,370 --> 01:37:36,980 Esta vez se aumentó a 31, porque el ejemplo del libro era 2139 01:37:36,980 --> 01:37:40,170 sobre días del mes para cumpleaños. 2140 01:37:40,170 --> 01:37:43,790 Entonces, la estructura de datos no solo tiene un arreglo, sino, ¿qué otra 2141 01:37:43,790 --> 01:37:47,030 estructura de datos combina con eso? 2142 01:37:47,030 --> 01:37:48,710 Es una especie de lista enlazada. 2143 01:37:48,710 --> 01:37:53,561 Lo bueno aquí es que S Adams, Adams, comienza con A en nuestra historia. 2144 01:37:53,561 --> 01:37:56,060 Ahora están usando cumpleaños, si leen esto en el contexto. 2145 01:37:56,060 --> 01:37:58,400 Pero supongamos que Adams es el único cuyo cumpleaños 2146 01:37:58,400 --> 01:37:59,720 es el segundo de algún mes. 2147 01:37:59,720 --> 01:38:01,880 Bueno, podría terminar aquí. 2148 01:38:01,880 --> 01:38:05,480 Y no hay mucho problema si alguien más tiene el mismo cumpleaños en este ejemplo, 2149 01:38:05,480 --> 01:38:08,960 porque podemos recorrer la lista, como lo hicimos con Jess, 2150 01:38:08,960 --> 01:38:11,750 y simplemente enlazarlos al final de esta estructura de datos. 2151 01:38:11,750 --> 01:38:14,930 O podemos insertarlos desde el principio 2152 01:38:14,930 --> 01:38:19,610 y usar algunos cambios constantes de tiempo a la izquierda para ubicarlos. 2153 01:38:19,610 --> 01:38:25,370 Sin embargo, la estructura de datos ya no es solo un arreglo. 2154 01:38:25,370 --> 01:38:32,280 Es una colección de 31 cubos, cuatro pilas, 26 pilas, 31 pilas, 2155 01:38:32,280 --> 01:38:34,430 pero cada una de esas pilas puede crecer verticalmente 2156 01:38:34,430 --> 01:38:37,190 por así decirlo, o en este caso lateralmente porque estamos 2157 01:38:37,190 --> 01:38:39,120 implementando la idea de estas estructuras de datos 2158 01:38:39,120 --> 01:38:42,200 usando ahora una lista vinculada real. 2159 01:38:42,200 --> 01:38:45,170 ¿Entonces por qué esto es mejor o peor? 2160 01:38:45,170 --> 01:38:49,220 Bueno, ¿hay algún límite sobre cuántos estudiantes pueden devolver sus exámenes 2161 01:38:49,220 --> 01:38:50,930 o celebrar cumpleaños? 2162 01:38:50,930 --> 01:38:54,320 No, porque seguimos creciendo cada vez más y más y más. 2163 01:38:54,320 --> 01:38:56,551 ¿Por qué eso es algo bueno? 2164 01:38:56,551 --> 01:38:59,300 Si quiero buscar a alguien, si sé que su nombre comienza 2165 01:38:59,300 --> 01:39:01,130 con la A, o si en el ejemplo del cumpleaños, sé 2166 01:39:01,130 --> 01:39:03,050 sé que su cumpleaños es el segundo del mes, 2167 01:39:03,050 --> 01:39:06,280 Sé, de forma determinista, que no importa 2168 01:39:06,280 --> 01:39:09,630 en cuál cubo estén en el arreglo. 2169 01:39:09,630 --> 01:39:13,490 Podrían estar en una larga cadena de gente con nombres o cumpleaños similares. 2170 01:39:13,490 --> 01:39:16,490 Pero van a estar allí de manera determinista, predecible, 2171 01:39:16,490 --> 01:39:17,240 una y otra vez. 2172 01:39:17,240 --> 01:39:22,130 Y lo bello de esto es que, si mi función hash está bien implementada, es uniforme, 2173 01:39:22,130 --> 01:39:26,600 por así decirlo estadísticamente, entonces sería bueno si casi todas estas cadenas 2174 01:39:26,600 --> 01:39:27,910 tuvieran casi la misma longitud 2175 01:39:27,910 --> 01:39:30,802 Sería lamentable si esta cadena fuera enorme 2176 01:39:30,802 --> 01:39:33,260 y que luego cualquier otra cadena fuera más corta solo porque tiene 2177 01:39:33,260 --> 01:39:35,370 una oportunidad para mejorar el diseño. 2178 01:39:35,370 --> 01:39:39,080 Entonces, en términos reales, una tabla hash, cuando se implementa así, 2179 01:39:39,080 --> 01:39:43,700 debería disminuir en este caso concreto por un factor de casi 31, 2180 01:39:43,700 --> 01:39:45,560 el tiempo que tarda en encontrar a alguien 2181 01:39:45,560 --> 01:39:49,190 Entonces el tiempo es 1 dividido por 31 porque si todas las cadenas tuvieran casi 2182 01:39:49,190 --> 01:39:53,510 la misma longitud, se dividiría el conjunto de datos en 4 pilas, 26 pilas, 2183 01:39:53,510 --> 01:39:57,830 31 pilas, cada una de las cuales es una cuarta o 126, 2184 01:39:57,830 --> 01:40:01,980 o 131 del tamaño del conjunto de datos completo. 2185 01:40:01,980 --> 01:40:04,640 Ahora asintóticamente, hace un par de semanas, 2186 01:40:04,640 --> 01:40:07,130 eso era algorítmicamente irrelevante. 2187 01:40:07,130 --> 01:40:10,440 Es una gran O de la misma cosa, por así decirlo. 2188 01:40:10,440 --> 01:40:13,700 Pero en términos reales, si se tiene tomar un cuarto de tiempo, 2189 01:40:13,700 --> 01:40:16,220 126 la cantidad de tiempo, 131 el tiempo real 2190 01:40:16,220 --> 01:40:19,070 nos ahorra tiempo en nuestros relojes. 2191 01:40:19,070 --> 01:40:21,890 Así en tiempos humanos reales ahorrará tiempo. 2192 01:40:21,890 --> 01:40:24,890 Y, de hecho, lo que verán en la serie de problemas cinco, en el cual implementarán 2193 01:40:24,890 --> 01:40:27,824 su primer corrector ortográfico, verán que eso es 2194 01:40:27,824 --> 01:40:29,240 lo que estamos tratando de optimizar 2195 01:40:29,240 --> 01:40:32,900 De hecho, como un adelanto antes de ver nuestra estructura de datos final, 2196 01:40:32,900 --> 01:40:35,660 serán desafiados como parte de este problema establecido opcionalmente 2197 01:40:35,660 --> 01:40:38,660 si desea participar y competir en el la pizarra. 2198 01:40:38,660 --> 01:40:40,847 Una vez que su código esté funcionando por check 50, podrán 2199 01:40:40,847 --> 01:40:44,180 ejecutar un comando separado de check 50 para publicarlo en el panel principal 2200 01:40:44,180 --> 01:40:44,680 aquí. 2201 01:40:44,680 --> 01:40:47,300 Y ahora, diablos, Brian nos está dando a Doug y a mí 2202 01:40:47,300 --> 01:40:49,790 porque su implementación del corrector ortográfico 2203 01:40:49,790 --> 01:40:55,490 toma solo 4.81 segundos y 7.4 kilobytes contra mis 82 megabytes 2204 01:40:55,490 --> 01:40:59,930 de memoria al implementar un corrector ortográfico sobre todas las palabras. 2205 01:40:59,930 --> 01:41:03,162 ¿Pero cómo se decide la forma de minimizar el espacio o el tiempo, 2206 01:41:03,162 --> 01:41:05,120 y cómo se atenúan algunas de las compensaciones? 2207 01:41:05,120 --> 01:41:08,000 Bueno, consideremos una estructura de datos final. 2208 01:41:08,000 --> 01:41:13,564 Quizás es la más sofisticada y ocupa más espacio, 2209 01:41:13,564 --> 01:41:15,230 y hace que sea difícil pintar en la pantalla. 2210 01:41:15,230 --> 01:41:16,700 Pero supongamos que hicimos esto. 2211 01:41:16,700 --> 01:41:20,660 Supongamos que tratamos de almacenar los nombres en nuestra estructura de datos. 2212 01:41:20,660 --> 01:41:23,142 Podríamos hacerlo con un arreglo de muchas cadenas, 2213 01:41:23,142 --> 01:41:25,100 y podríamos hacer búsquedas lineales, y Brian o Doug 2214 01:41:25,100 --> 01:41:28,490 o yo podríamos usar la búsqueda lineal en la gran O y encontrar la que deseen. 2215 01:41:28,490 --> 01:41:29,510 Eso no es muy bueno. 2216 01:41:29,510 --> 01:41:32,840 De algún modo podríamos usar la búsqueda binaria si usáramos un árbol o un arreglo 2217 01:41:32,840 --> 01:41:34,170 pero mantuviéramos los nombres ordenados. 2218 01:41:34,170 --> 01:41:35,240 Sabemos que podemos hacerlo mejor. 2219 01:41:35,240 --> 01:41:38,030 Así como encontramos a Mike Smith bastante rápido en la semana cero. 2220 01:41:38,030 --> 01:41:41,240 Pero, ¿y si pudiéramos encontrar nombres en tiempo constante? 2221 01:41:41,240 --> 01:41:44,990 Por lo tanto, no importa cuántas palabras hay en el árbol y no importa 2222 01:41:44,990 --> 01:41:47,930 cuántas palabras hay en el diccionario en general, 2223 01:41:47,930 --> 01:41:50,872 ¿todavía invierto la misma cantidad de tiempo para encontrar a alguien? 2224 01:41:50,872 --> 01:41:53,330 ¿Y no se hace más y más largo entre más nombres agreguemos? 2225 01:41:53,330 --> 01:41:59,480 Así que aquí hay un tipo de árbol que chistosamente se llama trie, TRIE, 2226 01:41:59,480 --> 01:42:02,700 un fragmento de la palabra "retrieval", lo cual es extraño porque es "retrieval" 2227 01:42:02,700 --> 01:42:06,290 no "retrival", pero esto es un trie, TRIE. 2228 01:42:06,290 --> 01:42:10,351 Cada uno de los nodos de un trie, esencialmente, son un arreglo en sí. 2229 01:42:10,351 --> 01:42:13,100 Técnicamente son una estructura con algo más dentro de ellos. 2230 01:42:13,100 --> 01:42:15,950 Y lo verán en el recorrido que Zamyla preparó. 2231 01:42:15,950 --> 01:42:19,580 Pero cada uno de los nodos del trie es un arreglo. 2232 01:42:19,580 --> 01:42:23,660 Cada uno de esos elementos de arreglos es un puntero a otro arreglo de ese tipo. 2233 01:42:23,660 --> 01:42:27,710 Y la forma en que se almacenan palabras en un trie no es con caracteres, 2234 01:42:27,710 --> 01:42:30,290 sino implícitamente con punteros. 2235 01:42:30,290 --> 01:42:33,650 Entonces, si queremos poner el nombre de alguien como Maxwell aquí, 2236 01:42:33,650 --> 01:42:38,960 hacemos un hash en este trie usando la primera letra del nombre de Maxwell, 2237 01:42:38,960 --> 01:42:40,040 la cual, por supuesto es m. 2238 01:42:40,040 --> 01:42:45,470 Y ese será el elemento 13 del arreglo en mi arreglo de 26 elementos 2239 01:42:45,470 --> 01:42:46,190 que tengo aquí. 2240 01:42:46,190 --> 01:42:48,800 Voy a cambiar ese puntero, originalmente nulo, 2241 01:42:48,800 --> 01:42:50,850 para que sea un puntero a otro nodo. 2242 01:42:50,850 --> 01:42:54,230 Y luego haré un hash con la segunda letra del nombre de Maxwell, que es A, 2243 01:42:54,230 --> 01:42:58,130 y asignaré un puntero a otro arreglo. 2244 01:42:58,130 --> 01:43:01,770 Y luego repetiré ese proceso para cada letra que tenga su nombre. 2245 01:43:01,770 --> 01:43:04,910 Así que el hash en la primera letra, la segunda letra, la tercera letra, cada vez 2246 01:43:04,910 --> 01:43:07,290 que lo hago me lleva a un nuevo arreglo. 2247 01:43:07,290 --> 01:43:10,340 Lo que no se muestra aquí es que cada una de estas matrices es de tamaño 26. 2248 01:43:10,340 --> 01:43:12,440 Sería atroz verlo en la pantalla. 2249 01:43:12,440 --> 01:43:14,270 Entonces usa demasiada memoria, 2250 01:43:14,270 --> 01:43:18,330 pero al final, hay un símbolo especial dibujado aquí, es un símbolo delta, 2251 01:43:18,330 --> 01:43:21,180 pero puede ser cualquier cosa, solo significa que Maxwell se detiene aquí. 2252 01:43:21,180 --> 01:43:22,790 Hay una palabra aquí. 2253 01:43:22,790 --> 01:43:26,210 Entonces, ¿cuántos pasos se necesitan para encontrar un nombre en el árbol? 2254 01:43:26,210 --> 01:43:32,480 Bueno, para encontrar a Maxwell es M-A-X-W-E-L-L. Entonces son siete pasos. 2255 01:43:32,480 --> 01:43:36,080 Para María sería M-A-R-I-A. Son cinco pasos. 2256 01:43:36,080 --> 01:43:40,010 Por lo tanto, sigue dependiendo de la cantidad de letras que haya en el nombre. 2257 01:43:40,010 --> 01:43:43,130 Pero si hay mil millones de nombres en este diccionario, 2258 01:43:43,130 --> 01:43:48,280 según esta definición, ¿cuántos pasos más se necesitan para encontrar a Maxwell? 2259 01:43:48,280 --> 01:43:50,254 M-A-X-W-E-L-L. 2260 01:43:50,254 --> 01:43:52,670 Y si hay mil millones de nombres en este diccionario, 2261 01:43:52,670 --> 01:43:54,590 ¿cuánto tiempo tomaría encontrar a Maxwell? 2262 01:43:54,590 --> 01:43:57,500 M-A-X-W-E-L-L, es invariante. 2263 01:43:57,500 --> 01:44:00,590 Y si suponemos que ningún nombre humano será muy largo, 2264 01:44:00,590 --> 01:44:03,920 es efectivamente constante si son 10 caracteres, quizás 30 caracteres 2265 01:44:03,920 --> 01:44:04,950 o lo que sea. 2266 01:44:04,950 --> 01:44:09,830 Es efectivamente constante, significa que un trie da un tiempo constante de búsqueda 2267 01:44:09,830 --> 01:44:15,500 o la gran O de uno, lo que significa que es la estructura de datos más rápida. 2268 01:44:15,500 --> 01:44:18,226 Pero, por supuesto, se paga un precio con más memoria. 2269 01:44:18,226 --> 01:44:21,350 Sé que ya nos pasamos por un minuto, pero dejen los molesto con lo último. 2270 01:44:21,350 --> 01:44:24,350 Verán con Zamyla la implementación de esta estructura de datos. 2271 01:44:24,350 --> 01:44:27,230 Pero ahora comenzamos la transición, especialmente si están 2272 01:44:27,230 --> 01:44:29,730 algo preocupados porque estamos llegando a la mitad del semestre, 2273 01:44:29,730 --> 01:44:30,350 como diciendo, ¡oh, cielos! 2274 01:44:30,350 --> 01:44:31,890 Las cosas se vuelven cada vez más sofisticadas. 2275 01:44:31,890 --> 01:44:34,640 Y ahorita estamos en la cima de una colina, porque después de la serie de problemas 2276 01:44:34,640 --> 01:44:38,916 cinco haremos la transición a HTML, CSS, Python, JavaScript 2277 01:44:38,916 --> 01:44:40,040 y programación web en general. 2278 01:44:40,040 --> 01:44:43,844 Y la próxima semana veremos cómo funciona el Internet. 2279 01:44:43,844 --> 01:44:44,510 [REPRODUCCIÓN DE VIDEO] 2280 01:44:44,510 --> 01:44:46,760 [MÚSICA DE FONDO] 2281 01:44:46,760 --> 01:44:49,780 2282 01:44:49,780 --> 01:44:59,176 Llegó con un mensaje, con un protocolo propio. 2283 01:44:59,176 --> 01:45:02,302 2284 01:45:02,302 --> 01:45:04,472 [MÚSICA DE FONDO] 2285 01:45:04,472 --> 01:45:12,190 2286 01:45:12,190 --> 01:45:18,040 Llegó a un mundo de crueles firewalls, descifrando enrutadores y sorteando peligros 2287 01:45:18,040 --> 01:45:21,670 peores que la muerte. 2288 01:45:21,670 --> 01:45:22,630 Es rápido. 2289 01:45:22,630 --> 01:45:23,950 Es fuerte. 2290 01:45:23,950 --> 01:45:26,310 Es TCPIP 2291 01:45:26,310 --> 01:45:28,685 y tiene tu dirección. 2292 01:45:28,685 --> 01:45:31,370 2293 01:45:31,370 --> 01:45:32,987 GUERREROS DE LA RED. 2294 01:45:32,987 --> 01:45:33,570 [FINALIZA LA REPRODUCCIÓN] 2295 01:45:33,570 --> 01:45:33,980 DAVID: Muy bien. 2296 01:45:33,980 --> 01:45:35,430 Todo eso y más la próxima semana. 2297 01:45:35,430 --> 01:45:37,240 Nos vemos pronto.