Vectores y Arrays
Vectores y Arrays
Vectores y Arrays
1: Arreglos
Ha obtenido 0 punto(s) sobre 0 hasta ahora.
Arreglos
Un arreglo es un conjunto de datos o una estructura de datos homogéneos que se
encuentran ubicados en forma consecutiva en la memoria RAM (sirve para almacenar
datos en forma temporal).
Arreglos
Donde
NTC = (30 – 1 + 1) = 30
Cada componente del arreglo V será un número entero, y podrá
accederse por medio de un índice que será un valor comprendido entre 1 y 30.
De esta manera, por ejemplo:
V(1) hace referencia al elemento de la posición 1 cuyo valor es 52
V(2) hace referencia al elemento de la posición 2 cuyo valor es 12
En cuanto a las dimensiones los arreglos pueden ser:
● Unidimensional o vector: un solo índice
● Bidimensional o matriz: dos índices
● Multidimensional: mas de dos índices
Diferencia con registros
Las dos diferencias sustanciales entre arreglos y registro son:
1) Un arreglo puede almacenar N elementos del mismo tipo, mientras que un registro
puede almacenar N elementos de distintos tipos que se llaman campos.
2) Los componentes de un arreglo se acceden por medio de índices, mientras que en un
registro los campos se acceden por medio de su nombre, el cual es único.
Arreglos Unidimensionales: Vectores
Operaciones : Podemos clasificar a las operaciones en las que intervienen arreglos de la
siguiente manera:
● Lectura / escritura
● Recorrido
● Asignación
● Actualización (Añadir, eliminar, insertar)
● Ordenación
● Búsqueda
Como los arreglos son datos estructurados, muchas de estas operaciones no pueden
llevarse a cabo de manera global, sino que se debe trabajar sobre cada componente.
Seguidamente se analizará cada una de estas operaciones, excepto las dos últimas
(ordenación y búsqueda) que serán estudiadas en capítulos posteriores.
Operaciones: Lectura / escritura
El proceso de lectura /escritura de un arreglo se realiza de la siguiente manera:
Leer V(n) Lee todo el arreglo
Escribir V(n) Escribe todo el arreglo
Leer V(3) Lee el elemento 3 del arreglo
Operaciones: Recorrido
Recorrer un vector significa acceder a todos y a cada uno de sus elementos desde el
principio hasta el final o viceversa (Recorrido Secuencial).
Se puede acceder a los elementos de un vector para introducir datos (leer) en él o bien
para ver su contenido (escribir). A la operación de acceder a todos los elementos para
efectuar una acción determinada se denomina recorrido del vector. Esta operación se
realiza usando estructuras repetitivas, cuya variable de control I, se utiliza como subíndice
del vector (por ejemplo V(n). El incremento del contador del bucle producirá el tratamiento
sucesivo de los elementos del vector.
Esta operación es muy utilizada en este tipo de estructuras de datos, dado que cuando se
está en presencia de un vector, el acceso a toda la información se realiza recorriendolo.
En algunos casos (Recorrido Randomico) se puede acceder a un determinado elemento
o a varios de ellos con ciertas características sin necesidad de recorrer todo el arreglo, por
ejemplo acceder solo al último elemento que sabemos a priori posee la suma de los
elementos anteriores.
Operaciones: Actualización
Muchas veces resulta interesante que dado un arreglo, puedan añadirse nuevos
elementos o eliminar o insertar componentes. Estas resultan las tres operaciones
elementales que se pueden realizar en un arreglo: añadir,
eliminar e insertar elementos.
Cuando se realiza una operación de añadir un nuevo elemento a continuación del último
valor no nulo, la única condición necesaria para esta operación es comprobar que haya
espacio para el nuevo elemento.
La operación de eliminar un elemento al final del arreglo no presenta ningún problema; en
cambio, si el borrado se realiza en el interior del mismo esto provoca el efecto contrario al
de insertar, el movimiento deberá ser hacia
arriba (I-1) de los elementos inferiores a él para reorganizar el vector.
Ordenaciones en Arreglos
La importancia de mantener nuestros arreglos ordenados radica en que es mucho más
rápido tener acceso a un dato en un arreglo ordenado que en uno desordenado. Existen
muchos algoritmos para la ordenación de elementos en arreglos, algunos de ellos son:
Este método consiste en seleccionar el elemento más pequeño de nuestra lista para
colocarlo al inicio y así excluirlo de la lista. Para ahorrar espacio, siempre que vayamos a
colocar un elemento en su posición correcta lo intercambiaremos por aquel que la esté
ocupando en ese momento.
Notación
La representación de un elemento en un vector se suele hacer mediante
el identificador del vector seguido del índice entre corchetes, paréntesis o llaves:
Notación Ejemplos
vector[índice_1,índice_2...,índice_N] (Java, Lexico, Perl, etc.)
vector[índice_0][índice_1]...[índice_N] (C, C++, PHP, etc.)
vector(índice_1,índice_2...,índice_N) (Basic)
Aunque muchas veces en pseudocódigo y en libros de matemática se representan como
letras acompañadas de un subíndice numérico que indica la posición a la que se quiere
acceder. Por ejemplo, para un vector "A":
(vector unidimensional)
Forma de acceso
La forma de acceder a los elementos de la matriz es directa; esto significa (Acceso
Randomico) que el elemento deseado es obtenido a partir de su índice y no hay que ir
buscándolo elemento por elemento (en contraposición, en el caso de una lista, para llegar,
por ejemplo, al tercer elemento hay que acceder a los dos anteriores o almacenar un
apuntador o puntero que permita acceder de manera rápida a ese elemento).
Para trabajar con vectores muchas veces es preciso recorrerlos. Esto se realiza por medio
de bucles. El siguiente pseudocódigo muestra un algoritmo típico para recorrer un vector y
aplicar una función ' ' a cada una de las componentes del vector:
i = 0
f(v[i])
i=i+1
fin_mientras
Vectores dinámicos y estáticos
Lo habitual es que un vector tenga una cantidad fija de memoria asignada, aunque
dependiendo del tipo de vector y del lenguaje de programación un vector podría tener una
cantidad variable de datos. En este caso, se les denomina vectores dinámicos, en
oposición, a los vectores con una cantidad fija de memoria asignada se los
denomina vectores estáticos.
El uso de vectores dinámicos requiere realizar una apropiada gestión de memoria
dinámica. Un uso incorrecto de los vectores dinámicos, o mejor dicho, una mala gestión de
la memoria dinámica, puede conducir a una fuga de memoria. Al utilizar vectores
dinámicos siempre habrá que liberar la memoria utilizada cuando ésta ya no se vaya a
seguir utilizando.
Lenguajes más modernos y de más alto nivel, cuentan con un mecanismo denominado
recolector de basura (como es el caso de Java) que permiten que el programa decida si
debe liberar el espacio basándose en si se va a utilizar en el futuro o no un determinado
objeto.
Algoritmo de ordenamiento
Algoritmo de ordenamiento
En computación y matemáticas un algoritmo de ordenamiento es un algoritmo que pone
elementos de una lista o un vector en una secuencia dada por una relación de orden, es
decir, el resultado de salida ha de ser una permutación —o reordenamiento— de la
entrada que satisfaga la relación de orden dada. Las relaciones de orden más usadas son
el orden numérico y el orden lexicográfico. Ordenamientos eficientes son importantes para
optimizar el uso de otros algoritmos (como los de búsqueda y fusión) que requieren listas
ordenadas para una ejecución rápida. También es útil para poner datos en forma canónica
y para generar resultados legibles por humanos.
Desde los comienzos de la computación, el problema del ordenamiento ha atraído gran
cantidad de investigación, tal vez debido a la complejidad de resolverlo eficientemente a
pesar de su planteamiento simple y familiar. Por ejemplo, BubbleSort fue analizado desde
1956. Aunque muchos puedan considerarlo un problema resuelto, nuevos y útiles
algoritmos de ordenamiento se siguen inventado hasta el día de hoy (por ejemplo,
el ordenamiento de biblioteca se publicó por primera vez en el 2004). Los algoritmos de
ordenamiento son comunes en las clases introductorias a la computación, donde la
abundancia de algoritmos para el problema proporciona una gentil introducción a la
variedad de conceptos núcleo de los algoritmos, como notación de O
mayúscula, algoritmos divide y vencerás, estructuras de datos, análisis de los casos peor,
mejor, y promedio, y límites inferiores.
Clasificación
Los algoritmos de ordenamiento se pueden clasificar en las siguientes maneras:
Estabilidad
Los algoritmos de ordenamiento estable mantienen un relativo preorden total. Esto
significa que un algoritmo es estable solo cuando hay dos registros R y S con la misma
clave y con R apareciendo antes que S en la lista original.
Cuando elementos iguales (indistinguibles entre sí), como números enteros, o más
generalmente, cualquier tipo de dato en donde el elemento entero es la clave, la
estabilidad no es un problema. De todas formas, se asume que los siguientes pares de
números están por ser ordenados por su primer componente:
(4, 1) (3, 1) (4, 6) (3, 7) (después de ser ordenado por el segundo valor)
(3, 1) (3, 7) (4, 1) (4, 6) (después de ser ordenado por el primer valor)
Por otro lado:
(3, 7) (3, 1) (4, 1) (4, 6) (después de ser ordenado por el primer valor)
(3, 1) (4, 1) (4, 6) (3, 7) (después de ser ordenando por el segundo valor
,
Estables
Ordenamiento de burbuja
Cocktail sort O(n²) O(1) Intercambio
bidireccional
Ordenamiento por
Selection Sort O(n²) O(1) Intercambio
selección
Ordenamiento por
Insertion sort O(n²) O(1) Inserción
inserción
Ordenamiento por No
Bucket sort O(n) O(n)
casilleros comparativo
No
Ordenamiento por cuentas Counting sort O(n+k) O(n+k)
comparativo
No
Ordenamiento Radix Radix sort O(nk) O(n)
comparativo
Inestables
Ordenamiento por
Selection sort O(n²) O(1) Selección
selección
Ordenamiento por
Heapsort O(n log n) O(1) Selección
montículos
Cuestionables, imprácticos
O(n), excepto en
Pancake sorting máquinas de Von
Neumann
De esta manera se puede escribir el siguiente pseudocódigo para ordenar una lista
de n elementos indexados desde el 1:
Y en general:
De esta manera se puede escribir el siguiente pseudocódigo para ordenar una lista
de n elementos indexados desde el 1:
Para cada valor de j, obtenido en ese orden, se compara el valor del índice j con el
siguiente:
Si el término j es mayor
que el término j+1, los
valores se permutan, en
caso contrario se
continúa con la iteración.
Para el caso del
ejemplo, tenemos que:
Para la primera
iteración del primer
bucle:
Ordenamiento Shell
El ordenamiento Shell (Shell sort en inglés) es un algoritmo de
ordenamiento. El método se denomina Shell en honor de su inventor Donald
Shell. Su implementación original, requiere O(n2) comparaciones e
intercambios en el peor caso. Un cambio menor presentado en el libro de V.
Pratt produce una implementación con un rendimiento de O(n log2 n) en el
peor caso. Esto es mejor que las O(n2) comparaciones requeridas por
algoritmos simples pero peor que el óptimo O(n log n). Aunque es fácil
desarrollar un sentido intuitivo de cómo funciona este algoritmo, es muy difícil
analizar su tiempo de ejecución.
El Shell sort es una generalización del ordenamiento por inserción, teniendo
en cuenta dos observaciones:
Algoritmo de búsqueda
Un algoritmo de búsqueda es aquel que está diseñado para localizar un elemento con
ciertas propiedades dentro de una estructura de datos; por ejemplo, ubicar el registro
correspondiente a cierta persona en una base de datos, o el mejor movimiento en una
partida de ajedrez.
La variante más simple del problema es la búsqueda de un número en un vector.
Búsqueda dicotómica
Elementos necesarios en una búsqueda :
log2(n) donde n = elementos de la búsqueda
Ejemplo: log2(1.000.000) ≈ 20
Búsqueda secuencial
Se utiliza cuando el vector no está ordenado o no puede ser ordenado previamente.
Consiste en buscar el elemento comparándolo secuencialmente (de ahí su nombre) con
cada elemento del vector hasta encontrarlo, o hasta que se llegue al final. La existencia se
puede asegurar cuando el elemento es localizado, pero no podemos asegurar la no
existencia hasta no haber analizado todos los elementos del vector. A continuación se
muestra el pseudocódigo del algoritmo:
Datos de entrada:
tam: tamaño del vector. Los subíndices válidos van desde 0 hasta tam-1 incl
usive. Puede representarse así: vec[0...tam) o vec[0...tam-1].
Variables
pos = 0
if vec[pos] == dato:
else:
pos = pos + 1
Fin (while)
Retorne falso,
Búsqueda dicotómica (binaria)
Se utiliza cuando el vector en el que queremos determinar la existencia de un elemento
está previamente ordenado. Este algoritmo reduce el tiempo de búsqueda
considerablemente, ya que disminuye exponencialmente el número de iteraciones
necesarias.
Está altamente recomendado para buscar en arrays de gran tamaño. Por ejemplo, en uno
conteniendo 50.000.000 elementos, realiza como máximo 26 comparaciones (en el peor
de los casos).
Para implementar este algoritmo se compara el elemento a buscar con un elemento
cualquiera del array (normalmente el elemento central): si el valor de éste es mayor que el
del elemento buscado se repite el procedimiento en la parte del array que va desde el
inicio de éste hasta el elemento tomado, en caso contrario se toma la parte del array que
va desde el elemento tomado hasta el final. De esta manera obtenemos intervalos cada
vez más pequeños, hasta que se obtenga un intervalo indivisible. Si el elemento no se
encuentra dentro de este último entonces se deduce que el elemento buscado no se
encuentra en todo el array.
A continuación se presenta el pseudocódigo del algoritmo, tomando como elemento inicial
el elemento central del array.
Datos de entrada:
tam: tamaño del vector. Los subíndices válidos van desde 0 hasta tam-1 incl
usive.
Variables
inf = 0
sup = tam-1
sup = centro - 1
En caso contrario:
inf = centro + 1
Fin (Mientras)
Devolver Falso