Concepto “Estructura de datos”

Anuncio
PROGRAMA
ASIGNATURA
TEMA
ESTRUCTURAS DE DATOS
LISTAS ENLAZADAS
Concepto “Estructura de datos”
Una estructura de datos es una clase contenedora que proporciona almacenamiento para
items de datos y capacidades para almacenar y recuperar esos datos.
Concepto “Abstracción”
La abstracción es un proceso mental mediante el cual se entiende que al conocer un
objeto, entonces se conocen todas sus características.
Por ejemplo, al nombrar el objeto “Computador”, entonces se sabe que con él se pueden
hacer programas, navegar en Internet, guardar información, y además tiene tamaño,
velocidad, memoria RAM, etc.
Al conocer el objeto, entonces se ABSTRAEN todas sus propiedades, funciones y
características.
En éste ejemplo, “Computador” es el Tipo Abstracto de Dato.
Entonces, “Abstracción de datos” es el proceso mediante el cual se define, implementa y
se usa un TIPO DE DATO ABSTRACTO.
Se podría decir que un TIPO DE DATO ABSTRACTO (TDA) corresponde a un conjunto de
propiedades de una entidad y las operaciones o funciones que los afectan.
TDA básicos son LISTAS ENLAZADAS, PILAS, COLAS, ARBOL, TABLAS HASH.
1
Listas enlazadas
Es necesario entender primero que los arrays tienen algunas desventajas como:
 En un array desordenado la búsqueda es lenta.
 En un array ordenado la inserción es lenta.
 En ambos casos, la eliminación es lenta.
 El tamaño de un array no se puede cambiar después de creado.
Estos problemas se solucionan con las estructuras de datos llamadas “Lista Enlazada”.
La “Lista Enlazada” es una estructura en la cual los elementos se almacenan de forma no
adyacente, en vez de un vector de posiciones de memoria consecutivas.
Una de las ventajas más importantes de la Lista Enlazada es la optimización del uso de
memoria pues no se desperdicia el espacio de nodos vacíos, como sucede como los
arrays, pues los arrays reservan el espacio de memoria aun cuando no la use.
Cada elemento de la lista enlazada se almacena en un NODO que contiene el objeto y una
referencia.
La mayor desventaja de la Lista Enlazada es que para localizar un dato específico debe ser
recorrida desde el inicio, lo que quiere decir que no se puede ir al i-ésimo elemento como
se hace en un array.
Existen tres (3) tipos de listas:
1. Lista enlazada simple
2. Lista doblemente enlazada
3. Lista circular
Lista enlazada simple
2
Lista doblemente enlazada
Tiene enlace al nodo siguiente pero también al nodo anterior.
Lista circular
En una lista enlazada circular, el primer y el último nodo están unidos. El último nodo
apunta al primero.
3
Lista enlazada simple
Una Lista Enlazada está compuesta por una serie de Nodos, donde cada Nodo contiene el
dato almacenado y una referencia al siguiente Nodo de Lista; de este modo la Lista sólo
necesita una referencia al primer Nodo para poder tener acceso a todos sus elementos.
La lista enlazada está compuesta por:
1. Una clase auto-referenciada, con al menos un campo cuyo tipo de referencia es el
nombre de la clase.
2. Nodo: un objeto creado desde una clase auto-referenciada.
3. Campo de enlace: un campo cuyo tipo de referencia es el nombre de la clase.
4. Enlace: la referencia a un campo de enlace.
5. Y la clase que genera la lista enlazada.
class Empleado {
private int numeroemp;
private String nombre;
private double salario;
public Empleado next;
}
Esta clase es auto-referenciada porque el campo “next” tiene el tipo Empleado.
En el código anterior, “next” es un campo de enlace.
Por el contrario, numeroemp, nombre, y salario son campos no de enlace.
En el código anterior, la referencia next a un nodo “Empleado” es un enlace.
4
EJERCICIO DE CLASE
Implemente el siguiente código de lista enlazada en un programa que capture las notas
del primer corte de los estudiantes del curso.
Recuerde que el programa debe:
1. Capturar la nota de cada estudiante
2. Indicar la nota máxima
3. Indicar la nota mínima
4. Indicar el promedio de las notas
Pero es muy importante que analice el funcionamiento de los métodos sobre la lista
enlazada.
//Esta es la clase Nodo;
public class Nodo {
//Atributos de la clase nodo
Object Dato;
Nodo Sig;
//Constructor del nodo para crear un objeto
public Nodo(Object Valor){
Dato=Valor;
Sig=null;
}
//Constructor del nodo para crear un objeto del siguiente nodo
public Nodo(Object Valor,Nodo Sign){
Dato=Valor;
Sig=Sign;
}
}
//Ahora la clase Lista
import javax.swing.JOptionPane;
public class Lista {
//Atributos de la lista
Nodo Pri;
Nodo Ult;
String Nom;
//Constructor de la lista
public Lista(String n){
Pri=Ult=null;
Nom=n;
}
5
//Constructor
public boolean ListaVacia(){//EN CASO DE QUE LA LISTA ESTE VACIA
if(Pri==null){
return true;
}
else{
return false;
}
}
//Nombre de la lista
public Lista(){
this("Lista");
}
//Metodo para insertar por el frente de la lista
public void Ifrente(Object Elem){
if(ListaVacia()){
Pri=Ult=new Nodo(Elem);
}
else{
Pri=new Nodo(Elem,Pri);
}
}
//Metodo para insertar por la parte posterior de la lista
public void Iposterio(Object Elem){
if(ListaVacia()){
Pri=Ult=new Nodo(Elem);
}
else{
Ult=Ult.Sig=new Nodo(Elem);
}
}
//Metodo para mostrar los datos de la lista
public void Mostrar(){
Nodo Actual=Pri;
if(ListaVacia()){
System.out.println("La "+Nom+" esta vacia");
}
while(Actual!=null){
System.out.println(Actual.Dato);
Actual=Actual.Sig;
}
}
//Metodo para eliminar el frente de la lista
public void Efrente(){
if(ListaVacia()){
Pri=Pri.Sig;
6
}
else if(Pri.equals(Ult)){
Pri=Ult=null;
}
else{
Pri=Pri.Sig;
}
}
//Metodo para eliminar el posterior de la lista
public void Eposterior(){
if(ListaVacia()){
Pri=Pri.Sig;
}
else if(Pri.equals(null)){
Ult=null;
}
else{
Pri=Pri.Sig;
}
}
}
PSEUDOCODIGOS
Empieza la lista de enlace simple
7
Insertar un Nodo antes del primer nodo
Insertar un Nodo después del último Nodo
8
Insertar un Nodo entre dos nodos
Imágenes tomadas de: www.programacion.com
Análisis del algoritmo de ingresar un nodo entre otros dos
public void Agregaentredos(Object m){
if(ListaVacia()){
System.out.println("La "+Nom+" esta vacia");
} else {
temp = new Nodo(m);
Nodo Actual=Pri;
while(Actual.Dato.equals(2)== false){ //inserta después del nodo 2
Actual=Actual.Sig;
}
temp.Sig = Actual.Sig ;
Actual.Sig = temp;
}
9
Pseudocódigo de agregar un nodo entre otros dos
Si ListaVacia entonces
Muestre “Lista está vacia”
De lo contrario
Crear Nodo temporal
Ir al primer nodo
Recorrer lista hasta encontrar nodo
//Saltar al siguiente nodo
Actual = Actual.siguiente
Fin recorrido
//Al encontrar el nodo donde se desea insertar…
Referencia temporal siguiente = Actual siguiente
Referencia actual siguiente = Temporal
Fin si
Borrar cualquier nodo que no sea el primero
Localiza el nodo que precede al nodo a borrar y le asigna el enlace que hay en el campo
next del nodo a borrar al campo next del nodo que le precede.
En el siguiente ejemplo vamos a borrar el nodo D.
Pseudocódigo de borrar cualquier elemento que no sea el primero
Ir al nodo inicial
Buscar el nodo que se desea borrar
Al nodo anterior hacerlo apuntar al nodo subsiguiente
10
El siguiente ejemplo borrar el nodo que queda después del nodo 9.
Lista enlazada (4,1,9,2,3)
public void borracualquiera(){
Nodo Actual=Pri; //Se ubica en el primer nodo
while(Actual.Dato.equals(9)== false){
Actual=Actual.Sig;
}
Actual.Sig = Actual.Sig.Sig;
}
Investiga: ¿Cómo borrar preguntando antes que nodo se desea borrar?
Lista doblemente enlazada
Las listas de enlace simple restringen el movimiento por lo nodos a una sola dirección.
Problemas de la lista enlazada simple
No se puede recorrer una lista de enlace simple en dirección opuesta a menos que se use
un algoritmo de inversión (esto lleva más tiempo).
Se tendría que repetir el algoritmo de inversión para volverlo al estado original.
No se puede borrar un nodo sin acceder al nodo predecesor.
Estos problemas se solucionan con la LISTA DOBLEMENTE ENLAZADA.
En la LISTA DOBLEMENTE ENLAZADA cada nodo tiene un par de campos de enlace.
Un campo de enlace permite atravesar la lista hacia adelante, mientras que el otro
permite atravesar la lista haca atrás.
Cada nodo se enlaza con el siguiente mediante el campo de enlace next, excepto el último
nodo, cuyo campo de enlace next contiene null para indicar el final de la lista (en dirección
hacia adelante).
Para la dirección hacia atras, una variable de referencia contiene una referencia al último
nodo de la dirección normal (hacia adelante), lo que se interpreta como el primer nodo.
Cada nodo se enlaza con el anterior mediante el campo de enlace previous, y el primer
nodo de la direccion hacia adelante, contiene null en su campo previous para indicar el fin
de la lista.
11


El puntero anterior del primer elemento debe apuntar hacia NULL (el inicio de la
lista).
El puntero siguiente del último elemento debe apuntar hacia NULL (el fin de la
lista).
Para acceder a un elemento, la lista puede ser recorrida en ambos sentidos:
 Comenzando por el inicio, el puntero siguiente permite el desplazamiento hacia el
próximo elemento.
 Comenzando por el final, el puntero anterior permite el desplazamiento hacia el
elemento anterior.
Piense: ¿Qué pasa cuando se inicia la creación de la lista doblemente enlazada?
El primer nodo que se crea será el nodo inicial y el nodo final.
Métodos de la lista doblemente enlazada
Agregar al final
public void agregaralfinal(String dato){
Nodo2 nuevo = new Nodo2(dato);
if(estaVacia()){
topehaciaadelante = nuevo;
topehaciaatras = nuevo;
} else {
topehaciaatras.next = nuevo;
nuevo.next = null;
nuevo.prev = topehaciaatras;
topehaciaatras = nuevo;
}
}
12
Agregar al inicio
public void agregaralinicio(String dato){
Nodo2 nuevo = new Nodo2(dato);
if(estaVacia()){
topehaciaadelante = nuevo;
topehaciaatras = nuevo;
} else {
topehaciaadelante.prev = nuevo;
nuevo.next = topehaciaadelante;
topehaciaadelante = nuevo;
}
}
Borrar al final
public void borraralfinal(){
if(estaVacia()){
System.out.println("Esta vacía");
} else {
Nodo2 ultimo = topehaciaatras.prev;
ultimo.next = null;
topehaciaatras = ultimo;
}
}
Borrar al inicio
public void borraralinicio(){
if(estaVacia()){
System.out.println("Esta vacía");
} else {
Nodo2 primero = topehaciaadelante.next;
primero.prev = null;
topehaciaadelante = primero;
}
}
Buscar un nodo
public String buscar(String dato){
Nodo2 buscado = null;
Nodo2 iterador = topehaciaadelante;
while(iterador != null && buscado == null){
if(iterador.name == dato){
buscado = iterador;
} else {
iterador = iterador.next;
}
}
return dato;
}
13
Lista enlazada circular
El campo de enlace del último nodo de una lista de enlace simple contiene un enlace nulo,
ocurre lo mismo en los campos de enlace del primer y último elemento en ambas
direcciones en las listas doblemente enlazadas.
En la lista enlazada circular, el último nodo contiene la referencia al primer nodo.
Las operaciones que se realizan sobre una lista circular son similares a las operaciones
sobre listas lineales, teniendo en cuenta que no hay primero ni último nodo, aunque sí un
nodo de acceso a la lista.
La construcción de una lista circular se puede hacer con enlace simple o enlace doble.
Analicemos el siguiente código:
//Clase Nodo para la lista circular doblemente enlazada
public class Nodolc {
int info;
Nodolc ant,sig;
public void Nodolc(){
ant = null;
sig = null;
}
}
//lista circular doblemente enlazada
public class ListaCircular {
private Nodolc raiz;
public ListaCircular () {
raiz=null;
}
public void insertarPrimero(int x) {
Nodolc nuevo = new Nodolc();
nuevo.info=x;
if (raiz==null) {
nuevo.sig=nuevo;
nuevo.ant=nuevo;
raiz=nuevo;
} else {
Nodolc ultimo=raiz.ant;
nuevo.sig=raiz;
14
nuevo.ant=ultimo;
raiz.ant=nuevo;
ultimo.sig=nuevo;
raiz=nuevo;
}
}
public void imprimir ()
{
if (!vacia()) {
Nodolc reco=raiz;
do {
System.out.print (reco.info + "-");
reco = reco.sig;
} while (reco!=raiz);
System.out.println();
}
}
public void insertarUltimo(int x) {
Nodolc nuevo=new Nodolc();
nuevo.info=x;
if (raiz==null) {
nuevo.sig=nuevo;
nuevo.ant=nuevo;
raiz=nuevo;
} else {
Nodolc ultimo=raiz.ant;
nuevo.sig=raiz;
nuevo.ant=ultimo;
raiz.ant=nuevo;
ultimo.sig=nuevo;
}
}
public boolean vacia ()
{
if (raiz == null)
return true;
else
return false;
}
public int cantidad ()
{
int cant = 0;
if (!vacia()) {
Nodolc reco=raiz;
do {
cant++;
reco = reco.sig;
} while (reco!=raiz);
}
return cant;
}
public void borrar (int pos)
{
if (pos <= cantidad ())
if (pos == 1) {
{
15
if (cantidad()==1) {
raiz=null;
} else {
Nodolc ultimo=raiz.ant;
raiz = raiz.sig;
ultimo.sig=raiz;
raiz.ant=ultimo;
}
} else {
Nodolc reco = raiz;
for (int f = 1 ; f <= pos - 1 ; f++)
reco = reco.sig;
Nodolc anterior = reco.ant;
reco=reco.sig;
anterior.sig=reco;
reco.ant=anterior;
}
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
ListaCircular lc=new ListaCircular();
lc.insertarPrimero(100);
lc.insertarPrimero(45);
lc.insertarPrimero(12);
lc.insertarPrimero(4);
System.out.println("Luego de insertar 4 nodos al principio");
lc.imprimir();
lc.insertarUltimo(250);
lc.insertarUltimo(7);
System.out.println("Luego de insertar 2 nodos al final");
lc.imprimir();
System.out.println("Cantidad de nodos:"+lc.cantidad());
System.out.println("Luego de borrar el de la primer posición:");
lc.borrar(1);
lc.imprimir();
System.out.println("Luego de borrar el de la cuarta posición:");
lc.borrar(4);
lc.imprimir();
}
}
16
Descargar