Etiqueta: Universidad

Adiós POO

Esta vez he tenido suerte, tras haber estado estudiando Programación Orientada a Objetos y sufriendo con sus prácticas interminables herencias, polimorfismos y enlaces dinámicos puedo decir que he aprobado. El exámen de esta asignatura consta de 20 preguntas tipo test que puntuan sobre 4, más una parte práctica de 4 preguntas donde hay que explicar términos mediante teoría y ejemplificaciones sobre 6.

La verdad es que con un 4 ya hacía media y podía aprobar, pero más vale el bonito 6,9 que he sacado de nota final. Ahora falta esperar a la media, que rondará el 7,7. Así que nada, se que esto no le importa a demasiada gente pero soy feliz, me he quitado una de las asignaturas más difíciles de segundo a la primera :)

3 comentarios 2 Febrero, 2010

POO: Conceptos básicos

La Programación Orientada a Objetos surge en 1967 de la mano del Norwegian Computer Center y su “Simula”. Para hablar de un lenguaje de programación orientado a objetos hemos de hacer referencia a la abstracción, es decir, a la omisión de detalles o aspectos de una estructura o artefacto con el fin de resaltar más claramente otros detalles. Es la abstracción lo que define un lenguaje orientado a objetos. De este modo, en estos podemos encontrar distintos mecanismos como la ocultación de información y el encapsulamiento (separación estricta entre interfaz o qué hace e implementación o cómo se hace).

Mediante los mecanismos de abstracción llegamos al paradigma orientado a objetos. Un paradigma es una serie de normas mediante las cuales se representa o entiende la realidad, en este caso aplicados a la programación. El Paradigma Orientado a Objetos es la metodología de desarrollo de aplicaciones organizadas como colecciones cooperativas de objetos, los cuales instancian clases, que a su vez se ordenan en jerarquías de clases que se relacionan mediante herencia.

Durante las últimas dos décadas la POO ha adquirido una gran popularidad debido a diversos factores tales como su fácil escalabilidad y su sencilla comprensión utilizando los mecanismos de abstracción simulando problemas de la vida real y razonando con metáforas. Por otra parte se han desarrollado grandes y potentes herramientas OO, tales como librerías, IDEs, etc.

Pero, además de todo lo mencionado, hay algo más importante que se debe saber sobre la POO, y es su “mundo”. Con la OO se presenta ante el programador, acostumbrado al paradigma imperativo o lógico, un nuevo mundo que se estructura en:

Agentes y comunidades: un programa OO se estructura como una comunidad de agentes que interactúan (objetos), de este modo cada uno de ellos tiene un rol en la comunidad y es utilizado por otros miembros de la misma.

Mensajes y métodos: cada objetos recibe mensajes sobre lo que debe hacer para posteriormente elegir el método mediante el cual hacerlo. Cada mensaje puede ser interpretado de distinto modo dependiendo del receptor.

Responsabilidades: son el comportamiento de los objetos. En la POO no preguntamos lo qué podemos hacer a las estructuras de datos, si no que preguntamos qué pueden hacer ellas por nosotros.

Objetos y clases: en la OO todo es un objeto. Un objeto es una encapsulación de un estado (valores de los datos) y comportamientos (operaciones) que instancian clases y están configurados a partir de otros objetos. Los objetos se agrupan en categorías llamadas clases.

Jerarquía de clases: la jerarquía de clases se establece en la herencia. Ésta utiliza la llamada generalización, es decir, en la vida real las características de un ente superior son aplicables a uno inferior, de este modo las características de figura geométrica son aplicables a rectángulo, a círculo, a triángulo, etc. Eso es herencia.

Enlace de métodos: existen dos tipos de enlace, el estático, que se realiza durante la compilación del programa, y el dinámico, que se realiza durante su ejecución.

En resumen, según Alan Kay, toda POO debe tener las siguientes características:

  1. Todo es un objeto.
  2. Cada objeto tiene su propia memoria configurada a partir de otros objetos.
  3. Los objetos instancian clases.
  4. Todos los objetos de una misma clase pueden recibir los mismos mensajes. Las clases son el lugar donde se almacena el comportamiento y la estructura interna de los objetos.
  5. Las clases se organizan en una jerarquía de herencia.
  6. Un programa es un conjunto de objetos que se relacionan entre sí mediante el envío de mensajes.

1 comentario 30 Diciembre, 2009

La vuelta al cole

Ya no queda nada. Mañana se abre el plazo de matriculación en la Universidad de Alicante y el 14 empieza la semana de presentación de asignaturas. El día 23 se cierra el plazo y esa semana empiezan las prácticas. Que cerca queda todo ya… y yo aún con espíritu de verano haciendo el perro. Vuelven los madrugones, vuelve el estrés, vuelve el estudio, los exámenes y, en definitiva, vuelve la universidad.

De momento, he estado esta tarde viendo asignaturas para coger este año y, más o menos, ya lo tengo decidido. Pretendía cursar un año de relax, pero finalmente he decidido tomármelo en serio y hacer lo que yo creo que soy capaz de hacer. La creación del horario ha sido un show, como todos los años, es un auténtico caos elegir asignaturas de distintos cursos para que cuadre todo… eso pasa por no ir al día (quién pudiera). Así que esto es lo que me ha quedado (las prácticas están puestas de acuerdo a mi primera preferencia):

horario provisional

Cómo se ve, durante los dos cuatrimestres tengo jueves y viernes libres (ja!), pero lamentablemente no van a estar libres viendo todo lo que tengo antes. Prácticamente van a ser extensiones de clase para hacer todo el trabajo y pretender tener los fines de semana realmente libres. A ver como sale la cosa…

1 comentario 6 Septiembre, 2009

Repaso a FP2

Aquí os dejo unos breves apuntes que me sirvieron para aprobar la asignatura de Fundamentos de Programación II hace un mes (con un precioso 9 en el examen teórico). Básicamente se trata del código de los algoritmos de lectura y escritura de ficheros y de manipulación de estructuras dinámicas, es decir, lo más importante de esta asignatura de primero de la Ingeniería Técnica en Informática de Gestión de la Universidad de Alicante:

Mostrar FICHEROS »

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
void LeerFichero()
{
	ifstream fi;
	string s = "";
 
	fi.open("fichero.txt", ios::in);
 
	if(fi.is_open())
	{
		bool error = false;
		getline(fi,s);
 
		if(fi.fail() && !fi.eof()) error = true;
		while(!error && !fi.eof())
		{
			// Procesar			
 
			getline(fi,s);
			if(fi.fail() && !fi.eof()) error = true;
		}
		fi.close();
	}
}
 
void EscribirFichero() // Pasaremos por valor la variable que se escribirá, generalmente desde un bucle.
{
	ofstream fi;
 
	fi.open("fichero.txt", ios::out);
 
	if(fi.is_open())
	{
		fi << "Cadena que se escribe" << endl;
 
		fi.close();
	}
}
 
void LeerFicheroBinario()
{
	ifstream fi;
	OBJ obj; // registro donde almacenamos los datos del binario
 
	fi.open("fichero.dat", ios::in | ios::binary);
 
	if(fi.is_open())
	{
		bool error = false;
		fi.read((char *)&obj, sizeof(OBJ));
 
		if(fi.fail() && !fi.eof()) error = true;
		while(!error && !fi.eof())
		{
			// Procesar obj
 
			fi.read((char *)&obj, sizeof(OBJ));
			if(fi.fail() && !fi.eof()) error = true;
		}
		fi.close();
	}
}
 
void EscribirFicheroBinario(OBJ obj) // pasaremos por valor el registro que se escribirá, generalmente desde un bucle
{
	ofstream fi;
 
	fi.open("fichero.dat", ios::out | ios::binary);
 
	if(fi.is_open())
	{
		fi.write((char *)&obj, sizeof(OBJ));
 
		fi.close();
	}
}
 
// SEEKG A TENER EN CUENTA:
 
// Para ficheros binarios, es posible acceder a distintas partes del mismo directamente para su lectura de la siguiente forma:
 
fi.seekg((3-1)*sizeof(OBJ), ios::beg); // Si os fijáis es una simple multiplicación de la posición por el tamaño del registro de almacenamiento. Este código acceder­á a la tercera posición del fichero.
fi.read((char *)&amp;obj, sizeof(OBJ));
 
// Para su escritura es exactamente igual, pero en vez de la función seekg, se utiliza la función seekp. Hay que tener en cuenta que si la posición a la que se quiere acceder no existe, el programa alarga el fichero hasta la misma.

Mostrar ESTRUCTURAS DINÁMICAS »

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
// - LISTAS:
 
typedef struct TNodo
{
	OBJ obj;
	struct TNodo *pSig;
} NODO, *LISTA, *pNodo;
 
// Definición: LISTA li = NULL;
 
pNodo CrearNodo(OBJ obj) // Esta función puede subdividirse en CrearNodoVacio y CrearNodo, pero es tontería
{
	pNodo n = new NODO;
 
	if(n != NULL)
	{
		// Copiar contenido de obj a n->obj
		n->pSig = NULL;
	}
	return n;
}
 
bool ListaVacia(LISTA li)
{
	return(li == NULL);
}
 
void InsertarAlFinal(LISTA &li, pNodo n)
{
	pNodo e = li;
 
	if(ListaVacia(li)) li = n;
	else
	{
		while(e->pSig != NULL;)
		{
			e = e->pSig;
		}
 
		e->pSig = n; // n->pSig apunta a NULL según la función CrearNodo()
	}
}
 
void InsercionOrdenada(LISTA &li, pNodo n)
{
	pNodo e = li;
	pNodo ant = NULL;
 
	while(e != NULL && NodoMenor(e,n))
	{
		ant = e;
		e = e->pSig;
	}
 
	if(ant == NULL) // insertar al principio
	{
		n->pSig = li;
		li = n;
	}
	else if(e == NULL) // insertar al final
	{
		e->pSig = n;
	}
	else // insertar en medio
	{
		ant->pSig = n;
		n->pSig = e;
	}
}
 
void MostrarLista(LISTA li)
{
	pNodo e = li;
 
	while(e != NULL)
	{
		// Mostrar contenido de e->obj
		e = e->pSig;
	}
}
 
void BorrarLista(LISTA &li)
{
	pNodo e = NULL;
 
	while(!ListaVacia(li))
	{
		e = li;
		li = li->pSig;
		delete(e);
	}
}
 
pNodo BusquedaElemento(LISTA li, pNodo n) // en vez del nodo a buscar también se puede pasar el registro OBJ
{
	pNodo e = li;
	bool encontrado = false;
 
	while(e != NULL && !encontrado)
	{
		if(ObjetosIguales(e,n)) encontrado = true;
		else
		{
			e = e->pSig;
		}
	}
	return e; // si !encontrado, entonces devuelve NULL
}
 
pNodo BusquedaElementoOrdenado(LISTA li, pNodo n)
{
	pNodo e = li;
	pNodo retorno = NULL;
	bool encontrado = false;
 
	while(e != NULL && MenorIgual(e,n) && !encontrado) // ojo! debe de ser menor o igual, no menor únicamente, no es posible reutilizar la otra función
	{
		if(ObjetosIguales(e,n))
		{
			encontrado = true;
		}
		else
		{
			e = e->pSig;
		}
	}
 
	if(encontrado) retorno = e;
	return(retorno);
}
 
// Ambas búsquedas pueden ser modificadas a tipo booleano para que devuelvan simplemente si se ha encontrado o no, en vez del nodo
 
void BorradoElemento(LISTA &li, pNodo n) // igual que en la búsqueda
{
	pNodo e = li;
	pNodo ant = NULL; // siempre que hay que modificar la lista debemos de contemplar el anterior
	bool encontrado = false;
 
	while(e != NULL && !encontrado)
	{
		if(ObjetosIguales(e,n))
		{
			encontrado = true;
 
			if(ant == NULL)
			{
				li = li->pSig;
			}
			else
			{
				ant->pSig = e->pSig;
			}
			delete(e);
		}
		else
		{
			ant = e;
			e = e->pSig;
		}
	}
}
 
// Recordad que al finalizar el programa hay que despejar todo rastro de la lista de la memoria
 
// - PILAS
 
typedef struct TNodoPila
{
	OBJ obj;
	struct TNodoPila *pSig;
} NODOPILA, *PILA, *pNodoPila;
 
pNodoPila CrearNodo(OBJ obj)
{
	pNodoPila n = new NODOPILA;
 
	if(n != NULL)
	{
		// Copiar el contenido de obj a n->obj
		n->pSig = NULL;
	}
	return n;
}
 
bool PilaVacia(PILA p)
{
	return(p == NULL);
}
 
void Apilar(PILA &p, pNodoPila n)
{
	n->pSig = p;
	p = n;
}
 
void Desapilar(PILA &p)
{
	pNodo e = p;
 
	if(!PilaVacia(p))
	{
		p = p->pSig;
		delete(e);
	}
}
 
// - COLAS
 
typedef struct TNodoCola
{
	OBJ obj;
	struct TNodoCola *pSig;
} *pNodoCola, NODOCOLA;
 
typedef struct
{
	pNodoCola tope;
	pNodoCola ult;
} COLA;
 
void CrearCola(COLA &c)
{
	c.tope = c.ult = NULL;
}
 
bool ColaVacia(COLA c)
{
	return(c.tope == NULL);
}
 
pNodoCola CrearNodo(OBJ obj)
{
	pNodoCola n = new NODOCOLA;
 
	if(n != NULL)
	{
		// Copiar contenido de obj a n->obj
		n->pSig = NULL;
	}
	return n;
}
 
void Encolar(COLA &c, pNodoCola n)
{
	if(ColaVacia(c)) c.tope = c.ult = n;
	else
	{
		n->pSig = c.ult;
		c.ult = n;
	}
}
 
void Desencolar(COLA &amp;c)
{
	pNodoCola e = c.tope;
 
	if(!ColaVacia(c))
	{
		c.tope = c.tope->pSig;
		delete(e);
 
		if(c.tope == NULL) c.ult = NULL;
	}
}

Espero que os sirva ^^.

Dejar un comentario 29 Julio, 2009

Mapas de Karnaugh

El objetivo principal de los mapas de Karnaugh es el de simplificar operaciones en el álgebra de Boole. Para ello necesitamos llevar a cabo, lo que yo separaría, en cuatro pasos claros.

1) Comprender la operación que se te plantea.

Este paso es indispensable, consiste en saber que te va a devolver la operación estudiandola como cualquier otra (paréntesis, negadores, etc), si 1 o 0, para más tarde poder realizar la tabla de verdad correctamente.

Como ejemplo voy a poner una que hice en una práctica de IB que me viene bastante bien. La operación en cuestión te la dan en forma de sumatorio, por lo que después podríais pasarla, si queréis, a SOP (Suma de Productos) con sus minitérminos correspondientes:

f = Σ(0,1,2,5,7,8,10,13,14,15)

En este caso va a ser muy fácil hacer la tabla de verdad, ya que con 4 bits, aquellos que coincidan con los términos entre paréntesis devuelven 1 y el resto 0, pero no siempre es tan fácil, puede suceder que nos den una operación booleana, en la que tendremos, manualmente, que comprobar todos los valores para saber lo que nos devuelven.

2) Realizar una tabla de verdad de la misma.

Como ya he dicho, en este caso es muy fácil hacer la tabla de verdad porque prácticamente ya nos la dan hecha, sería así:

tbdv

Me he tomado la licencia de hacerla con el EWB que me resulta más fácil para mostrárosla. Si nos dieran directamente la operación booleana, en este caso con 4 bits, tendríamos que asignarle a cada uno el valor correspondiente y ver al final que nos da. El sumatorio que os di en el paso anterior, en forma de SOP sería:

sop

Como véis abcd tiene los valores de la tabla de verdad (0000, 0001…) y como está en SOP, los 0 están negados y los 1 no. De este modo el número 0(a)0(b)0(c)0(d) en la tabla de verdad habría que comprobarlo unicamente con el minitérmino abcd y así sucesivamente viendo lo que nos devuelve. Ahora a simplificar mediante Karnaugh.

3) Comenzar a formar el mapa de Karnaugh.

A la hora de realizar la tabla, tendremos que tener en cuenta el número de bits, en este caso 4. Para realizar el mapa de Karnaugh tendríamos que hacer una tabla de 4×4 debido a los bits, dejando ab en vertical y cd en horizontal o viceversa, si fueran 3 bits habría que hacer una de 2×4 por ejemplo. También destacar que las combinaciones posibles se ponen en Gray, pero con aprendérselas de memoria sobra. Queda así:

karnaugh

Como véis, los 1 están colocados en aquellas casillas en las cuales, viendo las combinaciones verticales (00, 01, 11…) y las horizontales (00, 01, 11…) nos dan el número que tiene un 1 en la tabla de verdad, de modo que, por ejemplo el 0000 devuelve 1, por lo tando la combinación 00(vertical) y 00(horizontal) tiene un 1 en su casilla y así respectivamente.

Tras esto tendremos que agrupar los unos en los grupos más grandes posibles siempre que sean múltiplos de 2 (grupos de 2 unos, de 4 unos, de 6 unos…), pudiendo coger, en este caso por ejemplo, los que están en las esquinas como grupo de 4 ya que puedes agrupar los de abajo del todo con los de arriba del todo como si estuvieran seguidos, al igual que de izquierda a derecha y viceversa.

4) Traducir a operación simplificada.

Este paso puede resultar el más complicado, pero una vez sabido está tirao. Ahora tenemos que volver a fijarnos en las combinaciones Gray verticales y horizontales y en los grupos realizados. Vamos a realizar por ejemplo el grupo de 4 que está en el centro del mapa de Karnaugh. Como vemos, verticalmente las combinaciones son 01 y 11 que representan en este caso a ab, pues tenemos que coger aquellas que coincidan, si coinciden en 1 se pone sin negar y si coincide en 0 pues negado, quedando pues B. A continuación nos fijamos en las combinaciones verticales que también son 11 y 01 y representan cd, como coinciden en d (11, 01), resultaria D ya que en c hay 1,0 y es distinto. De este modo ese grupo resultaría BD. Así habría que hacer con todos los grupos hasta obtener la operación simplificada al máximo, que sería f = A’B’C’+ACD’+BD+B’D’.

Así que ya está. Tened en cuenta que este mapa de Karnaugh está realizado en forma de SOP y si lo hacemos en POS habría que hacer los mismos pasos pero con 0. Espero que esto, junto a otras páginas que sirvan de complemento os haga entender como se hacen los mapas de Karnaugh.

Dejar un comentario 29 Julio, 2009


Twitter

Entradas recientes

Últimos comentarios

Lista de anime

Viendo:





En espera:




Archivo

Enlaces

Puedes enlazarme utilizando este minibanner si lo crees necesario:


http://www.byteando.com



Blogroll