lunes, 26 de mayo de 2014

4.3.1 Secuencial e indexado


Se utiliza este tipo de organización de archivo cuando existe la necesidad
tanto de accesar los registros secuencialmente, por algún valor de llave, como de
accesarlos individualmente. Un archivo secuencial indexado proporciona la
combinación de tipos de acceso que manejan un archivo secuencial y un archivo
relativo o de acceso directo.
Estructura lógica de Archivo Secuencial-Indexado
En este tipo de organización de archivos se dispone de una tabla en que
aparecen ordenados secuencialmente los números de la clave del archivo y
asociados a cada uno de ellos de da la dirección del registro correspondiente.
Registros ordenados lógicamente (mas no físicamente)

4.3 Tipos de acceso a archivos


MODIFICADORES DE ACCESO JAVA: PUBLIC, PRIVATE, PROTECTED.
Hasta ahora habíamos dicho que una subclase no tiene acceso a los campos de una superclase de acuerdo con el principio de ocultación de la información. Sin embargo, esto podría considerarse como demasiado restrictivo.
Decimos que podría considerarse demasiado restrictivo porque limita el acceso a una subclase como si se tratara de una clase cualquiera, cuando en realidad la relación de una superclase con una subclase es más estrecha que con una clase externa. Por ello en diferentes lenguajes, Java entre ellos, se usa un nivel de acceso intermedio que no es ni public ni private, sino algo intermedio que se denomina como “acceso protegido”, expresado con la palabra clave protected, que significa que las subclases sí pueden tener acceso al campo o método.
El modificador de acceso protected puede aplicarse a todos los miembros de una clase, es decir, tanto a campos como a métodos o constructores. En el caso de métodos o constructores protegidos, estos serán visibles/utilizables por las subclases y otras clases del mismo package. El acceso protegido suele aplicarse a métodos o constructores, pero preferiblemente no a campos, para evitar debilitar el encapsulamiento. En ocasiones puntuales sí resulta de interés declarar campos con acceso protegido.
La sintaxis para emplear esta palabra clave es análoga a la que usamos con las palabras public y private, con la salvedad de que protected suele usarse cuando se trabaja con herencia. Desde un objeto de una subclase podremos acceder o invocar un campo o método declarado como protected, pero no podemos acceder o invocar a campos o métodos privados de una superclase. Declara un campo de una clase como protected y en un test crea un objeto de la subclase y trata de acceder a ese campo con una invocación directa del tipo interino43.IdProfesor = “54-DY-87”.
Java admite una variante más en cuanto a modificadores de acceso: la omisión del mismo (no declarar ninguno de los modificadores public, private o protected). En la siguiente tabla puedes comparar los efectos de usar uno u otro tipo de declaración en cuanto a visibilidad de los campos o métodos:

MODIFICADOR
CLASE
PACKAGE
SUBCLASE
TODOS
public
protected
No
No especificado
No
No
private
No
No
No

4.2 Definicion de apuntador


 1. Que son los apuntadores

Un apuntador es una variable que almacena una dirección de memoria. Lo primero que se debe hacer al trabajar con apuntadores es declararlos, la forma como se declara un apuntador se muestra a continuación:
Donde1:
1 Las cosas que se encuentran entre corchetes son opcionales.
Tipo: Tipo de dato al cual se desea apuntar, puede ser un tipo de dato simple (char, int, etc) o un tipo de dato complejo como una estructura o una clase.
Modificadores del tipo: Puede contener cualquier combinación de los modificadores de tipo const, volatile y restrict.
Nombre: Nombre del apuntador.
Valor inicial: Valor inicial del apuntador.
Por ejemplo, supóngase que se declaró un puntero a una variable la cual tiene el valor de 5 tal y como se muestra a continuación:
 int theVariable = 5;
int *pPointer = &theVariable;
Como se puede apreciar el valor almacenado en el apuntador es la dirección de memoria de la variable a la cual está apuntando. Esto fue posible gracias al operador dirección (&). Con base en la figura anterior se construyó la siguiente tabla para clarificar su uso:
                                    l       Significado
                     Valor
theVariable
Contenido de theVariable
5
&theVariable
Direccion de theVariable
101
pPointer
Contenido del apuntador pPointer
101
&pPointer
Direccion del apuntador pPointer
106

Como se puede notar de la tabla anterior el valor obtenido con el operador & es la dirección en la cual se encuentra la variable en cuestión. Como una variable puede ocupar más de 1 byte, el valor resultante es el byte asociado a la dirección base de la variable.
Ahora bien, con el apuntador es posible acceder a cualquier lugar de memoria y modificar su valor. Para ello se tiene que referenciar y desreferenciar el apuntador. Esto se describe a continuación:
2. Referenciando apuntadores

Consiste en asociar el apuntador a una dirección específica, para esto se suele usar el operador & para obtener la dirección de la variable en cuestión. A continuación se muestra la forma como normalmente se hace esto:
apuntador = &variable;
También es posible referenciar un apuntador pasándole el valor que se tiene en otro apuntador. Note que no se hizo uso del operador & en este caso:
apuntador1 = apuntador2;
Todo apuntador debe inicializarse antes de usarse. Si esto no se hace, cuando intente usarlo para hacer alguna operación en memoria el programa sacara un error. Un puntero que no ha sido inicializado se conoce como Wild pointer.
En la siguiente figura se ilustra un poco mejor lo anterior:
int i,j;
int *p; //Apuntador a un entero

Hasta el momento solo se ha declarado el apuntador pero no se ha referenciado, en la siguiente figura se muestra el efecto de referenciar el apuntador: p = &i;

Es posible que varios punteros estén apuntando a un mismo lugar de memoria: int i;
int *p,*q,*r;
p = &i;
q = &i;
r = p;


3. Deseferenciando un apuntador
Para poder acceder al lugar de memoria que está siendo apuntado por el puntero y realizar operaciones de lectura y escritura sobre este el puntero se debe desreferenciar. Para ello se hace uso del operador desreferencia (*).
El valor del lugar de memoria apuntado se obtiene de la siguiente manera:
variable = *apuntador;
Ahora si lo que se desea hacer es escribir en el lugar de memoria apuntado se hace lo siguiente:
*apuntador = valor;
La siguiente figura muestra el resultado de desreferenciar un apuntador:
*p = 5;
Como se puede notar de la figura anterior, es posible modificar el valor de i desde el apuntador. Vale resaltar que todo apuntador antes de ser desreferenciado debió haber sido previamente inicializado con una dirección valida.
4. Usos de los apuntadores

Los apuntadores se usan principalmente para 3 cosas:
 Crear estructuras de datos dinámicas.
 Manejar parámetros variables pasados a funciones.
 Acceder de a los diferentes elementos de arreglos o estructuras.

A continuación se trata con más detalle cada una de estas aplicaciones.
4.1 Funciones y apuntadores
Existen dos maneras de hacer llamados a funciones, por referencia y por valor. Cuando se realiza un llamado por valor; se trabaja sobre una copia de la variable pasada como argumento y por lo tanto la variable original (la que se pasó como argumento) no se modifica. Por otro lado, cuando se realiza una llamada por referencia al estar accediendo al lugar de memoria en el que se encuentra la variable pasada como argumento es posible modificar el valor original de la variable pasada como argumento.
El paso de funciones por referencia es de extrema utilidad cuando los argumentos que se están pasando a la función son pesados ya que esto evita que se tengan que hacer copias de dichos argumentos que en el peor de los casos pueden ocasionar que el programa colapse por llenar stack. También, mediante el uso de apuntadores, es posible superar la restricción que se tiene en la cual una función no puede retornar más de un elemento; así, por medio de referencias es posible retornar un array por ejemplo.
Para indicar que una función será pasada por referencia, se emplean apuntadores en la cabecera de la función, esto porque lo que se pasa como argumento es la dirección de memoria. Por ejemplo:
tipo_retorno f(tipo_1 *pName_1,tipo_2 *pName_2,...,tipo_N *pName_N)
Para aterrizar un poco más lo anterior, supongamos esta función:
void swap(int *px, int *py) {
int temp;
cout << "Swap. Before swap, *px: " << *px <<
" *py: " << *py << endl;
temp = *px;
*px = *py;
*py = temp;
cout << "Swap. After swap, *px: " << *px <<
" *py: " << *py << endl;
}
Como se pueden notar en la definición de la función anterior, en este caso ambos argumentos son pasados por referencia.
Ahora en lo que respecta a la invocación si lo que se pasa es como parámetro es una variable como tal se debe hacer uso del operador & para obtener la dirección de dicha variable y así inicializar el apuntador que funciona como argumento. Por otro lado si lo que se está pasando es un apuntador a una variable, no es necesario usar el operador & ya que el valor almacenado en este será una dirección de memoria. La siguiente tabla ilustra esto:
Caso
Invocacion
Observaciones
Se está pasando una variable a una función que se llama por referencia
int x = 5, y = 10;
swap(&x,&y);
Es necesario usar el operador & para obtener la dirección de memoria de las variables y así poder inicializar lo apuntadores que funcionan como argumentos.
Se está pasando apuntador a una función que se llama por referencia
int x = 5, y = 10;
int *px = &x, *py;
py = &y;
swap(px,py);
Como lo que se pasan son apuntadores previamente inicializados, estos ya tienen la dirección de memoria de la variable que será pasada como argumento de la función, por lo tanto no es necesario usar el operador &.
¿Qué sucede si lo que se pasa como argumento es lo resaltado?
int x = 5, y = 10;
int *px = &x, *py;
py = &y;
swap(&px,&py);
Codifique y compile el siguiente código:
// Demuestra el uso de funciones por referencia
#include <sdtio.h>
void swap(int *x, int *y);
void swapv(int x, int y);
int main() {
int x = 5, y = 10;
printf("---------------------------------------------------\n");
printf("Llamada por valor \n");
printf("Main. Antes del swap; x: %d, y: %d \n");
swapv(x,y);
printf("Main. Despues del swap; x: %d, y: %d \n");
printf("---------------------------------------------------\n");
printf("Llamada por referencia \n");
printf("Main. Antes del swap; x: %d, y: %d \n");
swapr(&x,&y);
printf("Main. Despues del swap; x: %d, y: %d \n");
printf("---------------------------------------------------\n");
return 0;
}
void swapr(int *px, int *py) {
int temp;
printf("Swapr. Antes del swap; *px: %d, *py: %d\n",*px,*py);
temp = *px;
*px = *py;
*py = temp;
printf("Swapr. Despues del swap; *px: %d, *py: %d\n",*px,*py);
}
void swapv(int x, int y) {
int temp;
printf("Swapv. Antes del swap; x: %d, y: %d\n",x,y);
temp = x;
x = y;
y = temp;
printf("Swapv. Despues del swap; x: %d, y: %d\n",x,y);
}

4.1 Asignacion de memoria estatica y dinamica


La asignación de memoria consiste en el proceso de asignar memoria para propósitos específicos, ya sea en tiempo de compilación o de ejecución. Si es en tiempo de compilación es estática, si es en tiempo de ejecución es dinámica y si son variables locales a un grupo de sentencias se denomina automática.
La Asignación estática de memoria consiste en el proceso de asignar memoria en tiempo de compilación antes de que el programa asociado sea ejecutado, a diferencia de la asignación dinámica o la automática donde la memoria se asigna a medida que se necesita en tiempo de ejecución.2
Una aplicación de esta técnica conlleva que un módulo de programa (por ejemplo función o subrutina) declara datos estáticos de forma local, de forma que estos datos son inaccesibles desde otros módulos a menos que se les pasen referenciados como parámetros o que les sean devueltos por la función. Se mantiene una copia simple de los datos estáticos, accesible a través de llamadas a la función en la cual han sido declarados.
El uso de variables estáticas dentro de una clase en la programación orientada a objetos permite que una copia individual de tales datos se comparta entre todos los objetos de esa clase.
Las constantes conocidas en tiempo de compilación, como literales de tipo cadena, se asignan normalmente de forma estática. En programación orientada a objetos, el método usual para las tablas de clases también es la asignación estática de memoria.
En ciencia de la computación, asignación dinámica de la memoria es la asignación de almacenamiento de memoria para utilización por parte de un programa de computador durante el tiempo de ejecución de ese programa. Es una manera de distribuir la propiedad de recursos de memoria limitada entre muchas piezas de código y datos. Un objeto asignado dinámicamente permanece asignado hasta que es desasignado explícitamente, o por el programador o por un recolector de basura; esto es notablemente diferente de la asignación automática de memoria y de la asignación estática de memoria (la de las variables estáticas). Se dice que tal objeto tiene tiempo de vida dinámico.

BIBLIOGRAFIA



3.2 DECLARACION Y UTILIZACION DE ARREGLOS EN LA SOLUCION DE PROBLEMAS DE INGENIERIA ELECTRICA

3.2 DECLARACION Y UTILIZACION DE ARREGLOS EN LA SOLUCION DE PROBLEMAS DE INGENIERIA ELECTRICA

Aplicación de las matrices en circuitos eléctricos


Circuitos eléctricos
La intensidad de las corrientes y las caídas de voltaje en un circuito eléctrico se rigen por las Leyes de Kirchhoff.
LEY DE KIRCHHOFF DE LA CORRIENTE: La suma algebraica de todas las corrientes en cualquier nodo es cero.
LEY DE KIRCHHOFF DEL VOLTAJE: La suma algebraica de todos los cambios de potencial en cualquier bucle es cero.
Una aplicación frecuente de estas leyes es cuando se conoce el voltaje de la fuerza electromotriz E (que por lo general es una batería o generador) y los ohmios Rj de las resistencias, y se pide calcular la intensidad ij de las corrientes, que circulan por cada segmento del circuito.
Obsérvese que para cada elemento en el circuito hay que elegir una dirección positiva para medir la corriente que pasará a través de dicho elemento. Las elecciones se indican con flechas. Para la fuente de voltaje E se toma como positivo el sentido del polo negativo al positivo. Dicha elección condicionará también el signo de los cambios de potencial en las resistencias. El cambio de potencial a través de las resistencias será negativo cuando dicho cambio se mida en el mismo sentido que la corriente, y positivo en el caso contrario.

Ejemplo:

En los nodos A y B tenemos: i1     -i2      -i3         = 0

En el bucle L1 tenemos:        E-R1i1-R2i2-R3i3 = 0

En el bucle L2:                       R1i1-R2i2-R3i3 = 0



    
1.    Planteamiento del problema
Las matrices tienen un número cada vez más creciente de aplicaciones en la solución de problemas en Ciencia y Tecnología.
Se aplicarán aquí al cálculo de corrientes en una “red eléctrica”. Se dará tratamiento especial al recálcalo de las intensidades de las corrientes en cada “bucle” de la red cuando se modifican las fuerzas electromotrices de las fuentes, debido a fallas o cambios en las mismas.
Ilustraremos esto a  partir de un ejemplo:
El siguiente diagrama presenta un modelo sencillo de una red eléctrica constituida por baterías, cables y resistencias.
A partir de las leyes de Kirchhoff que señalan que la suma de las fuerzas electromotrices de fuentes (baterías u otros generadores de energía) en cada “bucle” de la red es igual a la suma de los productos IR (intensidad x resistencia), se llega al sistema de ecuaciones lineales simultáneas:
76i1
-25i2
-50i3
=1 0
-25i1
+56i2
-i3
= 0
-50i1
-i2
+106i3
= 0

Tal matriz se obtiene por el método del análisis de corrientes por bucles, después de la simplificación del mismo.
Observemos que los números 76, 56, 106 de la diagonal son la suma de las resistencias en cada uno de los bucles.
Los números –25 y –50 y –1 corresponden a las resistencias que se hallan en ramales comunes a los bucles vecinos.
Esta es la razón por la cual la matriz, en este caso es obtenida por el método del análisis de corrientes por bucles, es diagonalmente dominante.
La positividad de los elementos de la diagonal, obtenidos por el análisis de corrientes por bucles, junto con la diagonal dominancia, llevan a lo que la matriz obtenida sea positivo definida y que sus auto valores sean positivos. Ello garantiza además que los pivotes que aparecen en el método de Gauss sean diferentes de 0 y la matriz sea invertible, por esto Hallamos la inversa de la misma forma que lo hicimos en el ejercicio de criptografía utilizando el método de la matriz ampliada.
                

         
                            A
31
-25
-20
!
1
0
0
-25
26
-1
¡
0
1
0
-20
-1
33
!
0
0
1
                         
Realizando las operaciones ya conocidas obtenemos la inversa de A.

A-1
1
0
0
!
3/946
1/587
13/811
0
1
0
¡
1/881
17/919
1/133
0
0
1
!
-2/127
-1/150
13/631




Luego multiplicamos la matriz inversa por la matriz de coeficientes.
                            A-1
23/939
4/359
9/772
4/359
18/785
4/731
9/772
4/731
4/267

10
0
0

   i1
   i2
   i3

  133/543
   39/7350
97/832

0,24493554
0,11142857
0,11658654




Las corrientes de cada malla son:
Ø  I1 0,24493554
Ø  I2=   0,11142857
Ø  I3 =  0,11658654