Algoritmos y Estructura de Datos · Algoritmos y Estructura de Datos Departamento de Ingeniería en...
Transcript of Algoritmos y Estructura de Datos · Algoritmos y Estructura de Datos Departamento de Ingeniería en...
Algoritmos y Estructura de Datos
Departamento de Ingeniería en Sistemas de Información Universidad Tecnológica Nacional FRBA
Ing.Roxana Leituz
18/10/2018
Material introductorio lenguaje Go – Cátedra a cargo del Dr. O. Bruno
1
Que es GO?
Go es un lenguaje de programación inspirado en C, compilado, estáticamente tipado, concurrente.
Podemos decir que “nació” en el año 2009 y está siendo utilizado por empresas como Docker,
UBER, entre otros. Los diseñadores de este lenguaje son: Rob Pike y Ken Tompson. Go fue
construido para ser utilizado como un lenguaje orientado a software de sistemas (es decir, sistemas
operativos, drivers de dispositivos), lo cual animó a desarrolladores de C y C++. Según el equipo de
Go, los desarrolladores de aplicaciones, y no los desarrolladores de software de sistemas, se han
convertido en los principales usuarios de Go. no existen dependencias a la hora de ejecutar
programas compilados con Go. No hay que preocuparse sobre si los usuarios tienen Ruby o la JVM
instalada o, si la tienen, qué versión tendrán. Por este motivo Go se está convirtiendo en un lenguaje
popular con el que desarrollar aplicaciones de línea de comandos u otro tipo de programas de
utilidades que necesiten ser distribuibles.
https://github.com/golang/go/wiki/GoUsers.
Algunas de sus principales características
Compilado: La compilación es el proceso de traducir el código fuente que escribas en un
lenguaje de más bajo nivel – puede ser ensamblador (como en el caso de Go) u otro tipo de
lenguaje intermedio (como en el caso de Java o C#)Los lenguajes compilados suelen ser
más rápidos y los ejecutables pueden funcionar sin depedencias adicionales (al
menos esto es cierto para lenguajes como C, C++ y Go, los cuales compilan directamente
en ensamblador)
Estáticamente Tipado: Estar tipado estáticamente implica que las variables deben ser de un
tipo específico (int, string, bool, []byte, etc). Esto
se consigue indicando el tipo a la hora de definir la variable o, en muchos casos, dejando al
compilador que infiera el
tipo
Concurrente: Está inspirado en CSP (Communicating sequential processes — de Charles
Antony Hoare, ganador del premio Turing en 1980).
Uso poco usual de POO: Go no usa clases, no usa herencia y el uso de interfaces se realiza
de manera implícita. Esto con el fin de mejorar el rendimiento al momento de diseñar tu
software.
Uso de paquetes: Se usan los paquetes para organizar el código. Un paquete puede tener
varios archivos “.go” que permiten definir lo que va a realizar el paquete. Para usar un
paquete en tu programa, debes importarlo.
Recolección de Basura: Los lenguajes con recolectores de basura (e.j., Ruby, Python, Java,
JavaScript, C#, Go) son capaces de realizar un seguimiento de las variables y liberarlas
cuando no se utilicen más. La recolección de basura añade overhead, pero también elimina
bugs devastadores
La sintaxis de C suele implicar que las líneas deban terminar en punto y coma y que debe haber
paréntesis que delimitan condicionales. Go acaba con estas prácticas, aunque los paréntesis se
siguen usando para controlar la precedencia de operadores.
https://golang.org/
Ejecutar Código Go en línea
2
https://play.golang.org/
En Go, el punto de entrada de un programa es una función llamada main ubicada en el paquete
main.
Imports
Go incluye ciertas funciones predefinidas, como println, las cuales pueden ser utilizadas sin
referenciar. No podemos ir muy lejos sin utilizar la librería estándar de Go y, eventualmente, sin
usar librerías de terceros. En Go, la palabra clave import se utiliza para declarar qué paquetes van a
ser utilizados por el código del fichero en el que estemos trabajando. Go es estricto en lo que
respecta a la importación de paquetes, tanto que tu código no compilará si importas un paquete
que no utilizas. la librería estándar de Go está bien documentada, ejemplo paquete fmt
https://golang.org/pkg/fmt/
Tipos de datos
Los datos lógicos pueden almacenarse en variables de tipo bool. Los valores que pueden tener son
true y false (en minúsculas). El valor cero (el valor por defecto) de las variables de tipo bool es
false. Las operaciones que se pueden realizar en Go con elementos lógicos son las siguientes:
Los números
3
Cabe desatacar que no hay un tipo float.
String
Las vemos mas abajo
Operaciones
Comparaciones
en Go es imprescindible indicar explícitamente cualquier conversión. En Go las conversiones no
devuelven errores en tiempo de ejecución. Si un valor no encaja en otro tipo, se hace una
simplificación. Por ejemplo, al pasar de un float32 a int se elimina la parte decimal.
Las conversiones se pueden utilizar para la conversión de tipos no numéricos. La sintaxis es
siempre la misma: <tipo-nuevo>(variable).
Variables y Declaraciones
Go asigna un valor por defecto a las variables. A los enteros se les asigna 0, a los booleanos false, a
los strings ""
var mivariable int
mivariable = 9000
0 con inferencia de tipos
Mivariable:=9000
4
Es importante que recuerdes que := se utiliza para declarar la variable a la vez que se le asigna
valor. ¿Por qué? Porque una variable no puede ser definida dos veces (al menos no en el mismo
ámbito). como ocurre con los imports, Go no te va a permitir tener variables sin utilizar. recuerda
que puedes usar var NOMBRE TIPO cuando declaras una variable y le asignas su valor por
defecto, NOMBRE := VALOR cuando declaras y asignas valor a una variable, y NOMBRE =
VALOR cuando asignas valor a una variable previamente declarada.
Estructuras de control
IF
La condición se escribe sin paréntesis. No sólo son opcionales, sino que la utilidad de
formateo de código Go los elimina de forma rutinaria. Al utilizar IF es imprescindible utilizar las
llaves. No tenemos la opción de no ponerlas y ejecutar sólo la siguiente instrucción. La condición IF
puede ir acompañada de una una sección ELSE.
FOR
El uso de paréntesis en el FOR es opcional. También al igual que en el caso del IF, el
formateador de código elimina los paréntesis por ser innecesarios.
For o while??
func main() {
contador := 0
for contador < 10 {
contador = contador + 1
}
fmt.Println("Hemos contado hasta", contador)
}
En el caso de Go, el WHILE sólo se trata de un caso particular de FOR; no se necesita otra palabra
reservada.
Si añadimos una operación de inicialización y una de incremento
func main() {
var contador int
for contador = 0; contador < 10; contador = contador + 1 {
//Ahora el bucle está vacío
}
fmt.Println("Hemos contado hasta", contador)
}
Ambas opcionales , exactamente igual que en C/C++.
DO.WHILE..no existe.. (la sonrisa pertenece a la profe)
Range
5
La palabra clave de rango se usa en bucles para iterar datos en estructuras de datos
(matrices, segmentos, cadenas, mapas, etc.).
1. Con matrices y segmentos, el rango proporciona índices y valores.
2. Con los mapas, el rango proporciona pares clave-valor.
3. Con la cadena, el rango proporciona el índice de cada carácter Unicode en la cadena y
sus caracteres Unicode correspondientes.
4. Si los valores de índice no son necesarios, se pueden descartar utilizando _.
func main() {
numeros := []int{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
sum := 0
for indice, valor := range numeros{
sum += valor
fmt.Print("[", indice, valor , "] ")
}
fmt.Println("\nSum es :: ", sum)
str := "Hello, World!"
for indice, c := range str {
fmt.Print("[", indice, ",", string(c), "] ")
}
}
Estructuras Una estructura es una agrupación ordenada de distintos elementos de información. Cada uno de
ellos con su propio tipo de datos correspondiente.
import "fmt"
type fichaAlumno struct {
nombre string //Nombre del alumno
humano bool //True si el alumno es humano
color int //Color del sable de luz en entero
}
func main() {
var goPadawan fichaAlumno
goPadawan.nombre = "GoPadawan"
goPadawan.humano = true
goPadawan.color = 65280
fmt.Println("Información de GoPadawan:", goPadawan)
}
Declaración de Funciones pueden devolver más de un valor
func log(message string) {}
func add(a int, b int) int {}
func power(name string) (int, bool) {}
6
Se puede usar una sintaxis abreviada si los parámetros son del mismo tipo:
func add(a, b int) int {}
Funciones Variádicas Pueden ser llamadas con cualquier número de argumentos
func sum(nums ...int){…}
sum(1, 2)
sum(1, 2, 3)…
Array
En Go los arrays están implementados dentro del lenguaje. No son objetos, ni abstracciones
externas. Forman parte intrínseca del lenguaje y su uso es muy intuitivo.
Cuando definimos un array especificamos un tipo de elemento y el número de elementos. Ambos
son inmutables y definen el tipo del array. Un array de 4 enteros es de un tipo distinto de un array
de 5 enteros.
Definiendo arrays
Vamos a definir unos cuantos arrays.
Un array sin valores. Mejor dicho: un array cuyos elementos adquieren el valor cero.
var enteros [2]int
Un array con dos elementos definidos.
var eb [2]string = [2]string{"Epi", "Blas"}
Definición corta del caso anterior.
var eb = [2]string{"Epi", "Blas"}
Definición aún más corta.
eb := [2]string{"Epi", "Blas"}
Definición sin especificar (explícitamente) el tamaño del array.
eb := [...]string{"Epi", "Blas"}
7
Como en el resto de casos, a menos que especifiquemos el valor de los elementos del array, se
inicializan con el valor cero.
Los arrays en memoria
Las variables que contienen un array ocupan en memoria el tamaño de cada elemento multiplicado
por el número de elementos. Nada más.
Habiendo visto cómo es un array, veamos cómo NO es un array:
Un array no es un puntero o una referencia
Slices
Un slice es una estructura ligera que encapsula y representa una porción de un array. Hay varias
formas de crear un slice.
puntaje := []int{1,4,293,4,9}
crea e inicializa una estructura de enteros 5 posiciones.
Otro modo es usar la función make que está sobrecargada y tiene varios objetivos.
Para declarar:
puntaje := make([]int, 10)
Crea un slice de longitud 10 y capacidad 10. Esto significa que sería válido asignar valores a
scores[0].. scores[1]…… scores[9].. recordemos que las estructuras enteras en Go se inicializan en
0. Longitud es el tamaño del slice y la capacidad es el tamaño del array subyacente
Ejemplo:
Si quisiéramos configurar por separado longitud y capacidad
puntaje := make([]int, 0, 10)
Tendríamos un slice de longitud 0 y capacidad 10.
8
Cual piensan que es la diferencia?? Que podemos y que no podemos hacer??
PRUEBEN!!
Si tiene longitud 0, como podemos utilizarlo entonces?? Necesitamos ampliar la longitud
explícitamente o utilizar alguna función que lo haga.
Modificar la longitud
puntaje = puntaje[0:5]
Esto amplía la longitud en 5, eso nos permite poner datos en las posiciones 0 a 4. El límite de la
expansión explícita es la capacidad que hayamos dado.
Expandir con append:
Nos permite ir ocupando los espacios desde la posición 0 en forma secuencial.
puntaje = append(puntaje, 5)
Almacena en la posición 0 el valor 5
Si tengo mi slice con datos en las 10 posiciones según la declaración/inicialización
puntaje := make([]int, 0, 10) y agrego un dato mas con append expandiendo el slice, cual sería la
longitud?? Y la capacidad?? Utilicen la función len para la longitud y cap para ver la capacidad.
Son iguales?? Encuentran un patrón??
Los slice tienen internamente una estructura de tipo cabecera y elementos, los elementos en las
funciones pasan por referencia, pero no así la cabecera,
La siguiente imagen muestra cómo se almacenan en memoria los slices:
9
Como se indica en la imagen, tenemos un puntero ptr que es un puntero (referencia) al
array, una longitud len que contiene un entero (positivo) con la longitud en uso, y una
capacidad cap con la capacidad máxima de este slice.
La siguiente imagen muestra un caso concreto: un trozo asociado a un array de 5
posiciones.
En este caso, el tamaño y la capacidad tienen el mismo valor, lo que significa que el trozo
está al máximo de su capacidad.
Veamos ahora un caso den el que el trozo “desecha” las primeras y últimas posiciones del
array.
Entonces como lo expandimos??
Podemos usar el make para declarar un nuevo slice mas grande y copiar los datos usando la función
copy(destino,origen).
Go tiene una función que hace esto append,
puntos = append(puntos, 4) agrega el 4 al slice
puntos = append(puntos, puntos2...) concatena el slice2 al slice original
puntos2 := append([]int(nil), puntos...) hace una copia
String
Las cadenas están compuestas de letras y números y pueden ser definidas usando comillas dobles,
son solo slices de bytes de solo lectura con un poco de soporte sintáctico adicional del lenguaje.
barra: = "/ usr / ken" [0] // produce el valor de byte '/'.
10
usr: = "/ usr / ken" [0: 4] // produce la subcadena "/ usr"
str: = string (barra) // muestra el carácter
Punteros – variables por referencia Go soporta apuntadores, lo cual nos permite pasar referencias de valores y datos entre las funciones
de nuestro programa.
El código *iptr en el cuerpo de la función dereferencía el apuntador de su dirección de memoria a el
valor actual de esa dirección. Si asignamos un valor a un apuntador dereferenciado se cambia el
valor que se está almacenando en dicha dirección de memoria.
La sintaxis &i devuelve la dirección en memoria de i, i.e. un apuntador a i.
EJ:
func zeroptr(iptr *int) {
*iptr = 0
}
func main() {
i := 1
zeroptr(&i)
fmt.Println("zeroptr:", i) /// zeroptr: 0
}
Métodos Los métodos están asociados con Estructuras.
type Persona struct {
nombre string
apellido string
edad int
}
func (p *Persona) incrementaEdad() int {
p.edad++
return p.edad
}
func main() {
me:= Persona{"Bill", "Broughton", 29, "Brown", true}
fmt.Println(me.incrementaEdad()) // Output: 30
fmt.Println(me.edad) // Output: 30
}
11
En la práctica…Búsqueda binaria
func BusquedaBinaria(data []int, value int) bool {
size := len(data)
Primero := 0
Ultimo := size - 1
medio := 0
for Primero <= Ultimo {
medio = Primero + (Ultimo - Primero)/2
if data[medio] == value {
return true
} else if data[medio] < value {
Primero = medio + 1
} else {
Ultimo = medio - 1
}
}
return false
}