You are on page 1of 33

Estructuras de Datos y

Algoritmos

Listas, Pilas y Colas

Contenido
n Listas
n Tipos abstractos de datos (ADTs
(ADTs))
n El ADT lista
n Implementació
Implementación usando arreglos
n Listas encadenadas
n Aplicaciones
n Implementació
Implementación mediante cursores
n El ADT pila (Stack
(Stack))
n Implementació
Implementación de pilas
n Aplicaciones
n El ADT cola
n Implementació
Implementación de colas
n Aplicaciones

1
Contenido

n Los puntos resaltantes de este capí


capítulo
son:
n El concepto de Tipo de Dato Abstracto (ADT)
n Como realizar operaciones eficientes en listas
n El ADT Pila y sus aplicaciones
n Al ADT Cola y sus aplicaciones

Tipos de Datos Abstractos (ADTs)

n Un ADT es un conjunto de objetos


acompañ
acompañado de un conjunto de
operaciones definidas sobre ellos.
n Los ADTs son abstracciones matemá
matemáticas
independientes de la implementació
implementación
n Enteros, reales y booleanos son ATDs así
así
como lo son listas, pilas y colas

2
El ADT Lista

n Las listas generalizadas tienen la forma A1,


A2, A3, ... AN donde N es el tamañ
tamaño de la
lista. Si N es cero la lista esta vací
vacía.
n Para toda lista excepto la lista vací
vacía, Ai+1
sigue a Ai. El primer elemento es A1 y el
último AN
n posición del elemento Ai es i
La posició

Operaciones típicas en listas


n printList():: imprimir la lista.
printList()
n makeEmpty():: crear una lista vací
makeEmpty() vacía.
n pos find(elem x): buscar la primera
ocurrencia del elemento x en la lista.
n elem findKth(pos k): buscar el elemento en
la posició
posición k.
n Insert (elem x, pos k): insertar el elemento
x en la posició
posición k.
n Remove(elem x): eliminar la primera ocurrencia
del elemento x.

3
Lista usando arreglos
n Se de estimar el tamañ
tamaño del arreglo, lo que
puede resultar en un desperdicio de espacio.
n Las operaciones printList,
printList, find,
find, insert y
remove son O(N),
O(N), mientras que findKth es
O(1). (Si la lista esta ordenada por una clave
comparable el tiempo de find es O(log N)).
n Crear una lista mediante sucesivas inserciones
es O(N2).

Ejemplo: una lista ordenada de


números
class OrdArray
{
private double[] a; // ref to array a
private int nElems; // number of data items
//---------------------------------------------------------
public OrdArray(int max) // constructor
{
a = new double[max]; // create array
nElems = 0;
}
//---------------------------------------------------------
public int size()
{ return nElems; }
//---------------------------------------------------------

4
Ejemplo: una lista ordenada de
números
public int find(double searchKey) {
int lowerBound = 0;
int upperBound = nElems-1;
int curIn;
while(true){
curIn = (lowerBound + upperBound ) / 2;
if(a[curIn]==searchKey)
return curIn; // found it
else if(lowerBound > upperBound)
return nElems; // can't find it
else { // divide range
if(a[curIn] < searchKey)
lowerBound = curIn + 1; // it's in upper half
else
upperBound = curIn - 1; // it's in lower half
} // end else divide range
} // end while
} // end find()

Ejemplo: una lista ordenada de


números

public void insert(double value) // put element into array


{
int j;
for(j=0; j<nElems; j++) // find where it goes
if(a[j] > value) // (linear search)
break;
for(int k=nElems; k>j; k--) // move bigger ones up
a[k] = a[k-1];
a[j] = value; // insert it
nElems++; // increment size
} // end insert()

5
Ejemplo: una lista ordenada de
números

public boolean delete(double value)


{
int j = find(value);
if(j==nElems) // can't find it
return false;
else // found it
{
for(int k=j; k<nElems; k++) // move bigger ones down
a[k] = a[k+1];
nElems--; // decrement size
return true;
}
} // end delete()

Ejemplo: una lista ordenada de


números

public void display() // displays array contents


{
for(int j=0; j<nElems; j++) // for each element,
System.out.print(a[j] + " "); // display it
System.out.println("");
}
//---------------------------------------------------------
} // end class OrdArray

6
Listas encadenadas
n A diferencia de los arreglos los elementos
no está
están almacenados en forma contigua.
n Cada elemento, ademá
además de la data,
contiene una referencia a la ubicació
ubicación del
pró
próximo elemento.
n Los tiempos para insert y remove son
O(1), mientras que find y findKth
requieren O(N).
O(N).

Operaciones en listas encadenadas

A1 A2 A3 A4 A5

Una lista encadenada

A1 A2 A3 A4 A5

Borrando un elemento en una lista encadenada

A1 A2 A3 A4 A5

Agregando un elemento
en una lista encadenada X

7
Cabeza de lista
A1 A2 A3 A4

header

Una lista encadenada

header
Una lista vacía

Nodos de la lista
package DataStructures;
class ListNode
{
// Constructors
ListNode( Object theElement )
{
this( theElement, null );
}
ListNode( Object theElement, ListNode n )
{
element = theElement;
next = n;
}
// Friendly data; accessible by other package routines
Object element;
ListNode next;
}

8
Iteradores
public class LinkedListItr {
LinkedListItr( ListNode theNode ) {
current = theNode;
}
public boolean isPastEnd( ) {
return current == null;
}
public Object retrieve( ) {
return isPastEnd( ) ? null : current.element;
}
public void advance( ) {
if( !isPastEnd( ) )
current = current.next;
}
private ListNode current; // Current position
}

La clase LinkedList
public class LinkedList {
private ListNode header;
public LinkedList( )
{
header = new ListNode( null );
}
public boolean isEmpty( )
{
return header.next == null;
}
public void makeEmpty( )
{
header.next = null;
}
public LinkedListItr zeroth( )
{
return new LinkedListItr( header );
}

9
La clase LinkedList
public LinkedListItr first( )
{
return new LinkedListItr( header.next );
}
public void insert( Object x, LinkedListItr p )
{
if( p != null && p.current != null )
p.current.next = new ListNode( x,
p.current.next );
}
public LinkedListItr find( Object x )
{
ListNode itr = header.next;
while( itr != null && !itr.element.equals( x ) )
itr = itr.next;
return new LinkedListItr( itr );
}

La clase LinkedList

public LinkedListItr findPrevious( Object x )


{
ListNode itr = header;
while(itr.next != null && !itr.next.element.equals(x))
itr = itr.next;
return new LinkedListItr( itr );
}
public void remove( Object x )
{
LinkedListItr p = findPrevious( x );
if( p.current.next != null )
p.current.next = p.current.next.next;
}

10
La clase LinkedList

public static void printList( LinkedList theList )


{
if( theList.isEmpty( ) )
System.out.print( "Empty list" );
else
{
LinkedListItr itr = theList.first( );
for( ; !itr.isPastEnd( ); itr.advance( ) )
System.out.print( itr.retrieve( ) + " " );
}

System.out.println( );
}

Listas doblemente encadenadas

A1 A2 A3 A4 A5

Una lista doblemente encadenada

A1 A2 A3 A4 A5

Una lista circular doblemente encadenada

11
El ADT polinomio
n Se definirá
definirá un tipo de datos abstracto para
representar polinomios de una variable de la
forma: N
f ( x ) = ∑ ai x i
i=0

n Se definen las operaciones para crear,


imprimir, sumar y multiplicar polinomios.
n Se podrí
podrían considerar otras operaciones como
diferenciació
diferenciación y divisió
división

Polinomios usando arreglos


public class Polynomial
{
public static final int MAX_DEGREE = 100;
public static int max( int a, int b )
{
return a > b ? a : b;
}
public Polynomial( )
{
zeroPolynomial( );
}
public void zeroPolynomial( )
{
for( int i = 0; i <= MAX_DEGREE; i++ )
coeffArray[ i ] = 0;
highPower = 0;
}

12
Polinomios usando arreglos
public Polynomial add( Polynomial rhs )
{
Polynomial sum = new Polynomial( );
sum.highPower = max( highPower, rhs.highPower );
for( int i = sum.highPower; i >= 0; i-- )
sum.coeffArray[i] = coeffArray[i] + rhs.coeffArray[i];
return sum;
}
public Polynomial multiply( Polynomial rhs ) throws Overflow
{
Polynomial product = new Polynomial( );
product.highPower = highPower + rhs.highPower;
if( product.highPower > MAX_DEGREE )
throw new Overflow( );
for( int i = 0; i <= highPower; i++ )
for( int j = 0; j <= rhs.highPower; j++ )
product.coeffArray[i+j]+=coeffArray[i]*rhs.coeffArray[j];
return product;
}

Polinomios usando arreglos


public void print( )
{
for( int i = highPower; i > 0; i-- )
System.out.print( coeffArray[ i ] + "x^" + i + " + " );
System.out.println( coeffArray[ 0 ] );
}

private int coeffArray[ ] = new int [ MAX_DEGREE + 1 ];


private int highPower = 0;
}

13
Polinomios usando listas
10 1000 5 14 1 0

P1
El polinomio 10 x1000 + 5x14 + 1

3 1990 -2 1492 11 1 5 0

P2
El polinomio 3x1990 − 2 x1492 + 11x + 5

Multilistas
S1 S2 S3 S4

C1

C2

C3

C4

C5

14
Listas encadenadas usando
cursores
n Se usa un arreglo para almacenar los nodos.
n Deben simularse las caracterí
características de las listas
encadenadas:
n Cada nodo contiene un enlace al siguiente. En el caso
de cursores los enlaces son índices del arreglo
n Se pueden obtener nuevos nodos cuando se
necesitan y los nodos son automá
automáticamente re-re-usados
al disponer de ellos.
n Esta implementació
implementación puede hacerse en
lenguajes que no manejan memoria diná
dinámica.

Nodo para CursorList


package DataStructures;
class CursorNode
{
// Constructors
CursorNode( Object theElement )
{
this( theElement, 0 );
}
CursorNode( Object theElement, int n )
{
element = theElement;
next = n;
}
// Friendly data; accessible by other package routines
Object element;
int next;
}

15
Iterador para CursorList
public class CursorListItr {
CursorListItr( int theNode ) {
current = theNode;
}
public boolean isPastEnd( ) {
return current == 0;
}
public Object retrieve( ) {
return isPastEnd( ) ? null :
CursorList.cursorSpace[ current ].element;
}
public void advance( ) {
if( !isPastEnd( ) )
current = CursorList.cursorSpace[ current ].next;
}
int current; // Current position
}

CusorList
public class CursorList
{
private static int alloc( )
{
int p = cursorSpace[ 0 ].next;
cursorSpace[ 0 ].next = cursorSpace[ p ].next;
if( p == 0 )
throw new OutOfMemoryError( );
return p;
}

private static void free( int p )


{
cursorSpace[ p ].element = null;
cursorSpace[ p ].next = cursorSpace[ 0 ].next;
cursorSpace[ 0 ].next = p;
}

16
CusorList
public CursorList( )
{
header = alloc( );
cursorSpace[ header ].next = 0;
}
public boolean isEmpty( )
{
return cursorSpace[ header ].next == 0;
}
public void makeEmpty( )
{
while( !isEmpty( ) )
remove( first( ).retrieve( ) );
}
public CursorListItr zeroth( )
{
return new CursorListItr( header );
}

CusorList
public CursorListItr first( )
{
return new CursorListItr( cursorSpace[ header ].next );
}
public void insert( Object x, CursorListItr p )
{
if( p != null && p.current != 0 )
{
int pos = p.current;
int tmp = alloc( );
cursorSpace[ tmp ].element = x;
cursorSpace[ tmp ].next = cursorSpace[ pos ].next;
cursorSpace[ pos ].next = tmp;
}
}

17
CusorList
public CursorListItr find( Object x )
{
int itr = cursorSpace[ header ].next;
while( itr != 0 && !cursorSpace[ itr].element.equals(x))
itr = cursorSpace[ itr ].next;
return new CursorListItr( itr );
}
public CursorListItr findPrevious( Object x )
{
int itr = header;
while( cursorSpace[ itr ].next != &&
!cursorSpace[cursorSpace[itr].next].element.equals(x))
itr = cursorSpace[ itr ].next;
return new CursorListItr( itr );
}

CusorList
public void remove( Object x ) {
CursorListItr p = findPrevious( x );
int pos = p.current;
if( cursorSpace[ pos ].next != 0 ) {
int tmp = cursorSpace[ pos ].next;
cursorSpace[ pos ].next = cursorSpace[ tmp ].next;
free( tmp ); }
}
static public void printList( CursorList theList ) {
if( theList.isEmpty( ) )
System.out.print( "Empty list" );
else {
CursorListItr itr = theList.first( );
for( ; !itr.isPastEnd( ); itr.advance( ) )
System.out.print( itr.retrieve( ) + " " ); }
System.out.println( );
}

18
CusorList
private int header;
static CursorNode[ ] cursorSpace;
private static final int SPACE_SIZE = 100;
static
{
cursorSpace = new CursorNode[ SPACE_SIZE ];
for( int i = 0; i < SPACE_SIZE; i++ )
cursorSpace[ i ] = new CursorNode( null, i + 1 );
cursorSpace[ SPACE_SIZE - 1 ].next = 0;
}
public static void main( String [ ] args )
{
CursorList theList = new CursorList( );
CursorListItr theItr;
int i;
theItr = theList.zeroth( );
printList( theList );

CusorList
for( i = 0; i < 10; i++ )
{
theList.insert( new MyInteger( i ), theItr );
printList( theList );
theItr.advance( );
}

for( i = 0; i < 10; i += 2 )


theList.remove( new MyInteger( i ) );
for( i = 0; i < 10; i++ )
if(( i % 2 == 0 ) != (theList.find(
new MyInteger( i )).isPastEnd( )))
System.out.println( "Find fails!" );
System.out.println( "Finished deletions" );
printList( theList );
}
}

19
El ADT Pila (Stack)

n Una pila (stack


(stack)) es una lista en la que
todas las operaciones se efectú
efectúan en la
posició
posición final de la misma
n Las operaciones fundamentales son:
n push(elem x): coloca el elemento x al final de
la lista.
n pop(): remueve el elemento al final de la lista.
n elem top():
top(): retorna el elemento final de la pila

El ADT Pila (Stack)


n Las pilas tambié
también se conocen como colas LIFO
(Last In First Out)
Out)
n Debido a la simplicidad de las operaciones
permitidas estas son muy rárápidas.
n A pesar de su simplicidad, las pilas son
estructuras muy útiles.
n Todos los programas tienen al menos una pila
para almacenar argumentos, variables locales y
direcció
dirección de retorno de llamadas a funciones.

20
Pilas usando listas encadenadas
public class StackLi
{
public StackLi( )
{
topOfStack = null;
}
public boolean isFull( )
{
return false;
}
public boolean isEmpty( )
{
return topOfStack == null;
}
public void makeEmpty( )
{
topOfStack = null;
}

Pilas usando listas encadenadas


public Object top( )
{
if( isEmpty( ) )
return null;
return topOfStack.element;
}
public void pop( ) throws Underflow {
if( isEmpty( ) )
throw new Underflow( );
topOfStack = topOfStack.next;
}
public Object topAndPop( ) {
if( isEmpty( ) )
return null;
Object topItem = topOfStack.element;
topOfStack = topOfStack.next;
return topItem;
}

21
Pilas usando listas encadenadas
public void push( Object x )
{
topOfStack = new ListNode( x, topOfStack );
}

private ListNode topOfStack;


public static void main( String [ ] args )
{
StackLi s = new StackLi( );

for( int i = 0; i < 10; i++ )


s.push( new MyInteger( i ) );
while( !s.isEmpty( ) )
System.out.println( s.topAndPop( ) );
}
}

Pilas usando arreglos


public class StackAr
{
public StackAr( )
{
this( DEFAULT_CAPACITY );
}
public StackAr( int capacity )
{
theArray = new Object[ capacity ];
topOfStack = -1;
}
public boolean isEmpty( )
{
return topOfStack == -1;
}
public boolean isFull( )
{
return topOfStack == theArray.length - 1;
}

22
Pilas usando arreglos
public void makeEmpty( )
{
topOfStack = -1;
}
public Object top( )
{
if( isEmpty( ) )
return null;
return theArray[ topOfStack ];
}
public void pop( ) throws Underflow
{
if( isEmpty( ) )
throw new Underflow( );
theArray[ topOfStack-- ] = null;
}

Pilas usando arreglos


public void push( Object x ) throws Overflow
{
if( isFull( ) )
throw new Overflow( );
theArray[ ++topOfStack ] = x;
}
public Object topAndPop( )
{
if( isEmpty( ) )
return null;
Object topItem = top( );
theArray[ topOfStack-- ] = null;
return topItem;
}

23
Pilas usando arreglos
private Object [ ] theArray;
private int topOfStack;
static final int DEFAULT_CAPACITY = 10;
public static void main( String [ ] args )
{
StackAr s = new StackAr( 12 );
try
{
for( int i = 0; i < 10; i++ )
s.push( new MyInteger( i ) );
}
catch( Overflow e ) { System.out.println(
"Unexpected overflow" ); }
while( !s.isEmpty( ) )
System.out.println( s.topAndPop( ) );
}
}

Aplicaciones de pilas

n Balance de simbolos.
simbolos.
n Conversió
Conversión de expresiones de infix a
postfix.
postfix.
n Evaluació
Evaluación de expresiones.
n Eliminació
Eliminación de recursió
recursión

24
Balance de Parentesis
class BracketChecker
{
private String input; // input string
public BracketChecker(String in) // constructor
{ input = in; }
public void check()
{
int stackSize = input.length(); // get max stack size
StackX theStack = new StackX(stackSize); // make stack
for(int j=0; j<input.length(); j++)// get chars in turn
{
char ch = input.charAt(j); // get char
switch(ch)
{
case '{': // opening symbols
case '[':
case '(':
theStack.push(ch); // push them
break;

case '}': // closing symbols


case ']':
case ')':
if( !theStack.isEmpty()) // if stack not empty,
{
char chx = theStack.pop(); // pop and check
if( (ch=='}' && chx!='{') ||
(ch==']' && chx!='[') ||
(ch==')' && chx!='(') )
System.out.println("Error: "+ch+" at "+j);
}
else // prematurely empty
System.out.println("Error: "+ch+" at "+j);
break;
default: // no action on other characters
break;
} // end switch
} // end for
if( !theStack.isEmpty() )
System.out.println("Error: missing right delimiter");
} // end check()
} // end class BracketChecker

25
Infix to Postfix
class InToPost // infix to postfix conversion
{
private StackX theStack;
private String input;
private String output = "";
public InToPost(String in) // constructor
{
input = in;
int stackSize = input.length();
theStack = new StackX(stackSize);
}

Infix to Postfix
public String doTrans() // do translation to postfix
{
for(int j=0; j<input.length(); j++) // for each char
{
char ch = input.charAt(j); // get it
switch(ch)
{
case '+': // it's + or -
case '-':
gotOper(ch, 1); // go pop operators
break; // (precedence 1)
case '*': // it's * or /
case '/':
gotOper(ch, 2); // go pop operators
break; // (precedence 2)
case '(': // it's a left paren
theStack.push(ch); // push it
break;

26
Infix to Postfix
case ')': // it's a right paren
gotParen(); // go pop operators
break;
default: // must be an operand
output = output + ch; // write it to output
break;
} // end switch
} // end for
while( !theStack.isEmpty() ) // pop remaining opers
{
output = output + theStack.pop(); // write to output
}
return output; // return postfix
} // end doTrans()

Infix to Postfix
private void gotOper(char opThis, int prec1)
{ // got operator from input
while( !theStack.isEmpty() )
{
char opTop = theStack.pop();
if( opTop == '(' ) // if it's a '('
{
theStack.push(opTop); // restore '('
break;
}
else // it's an operator
{
int prec2; // precedence of new op
if(opTop=='+' || opTop=='-') // find new op prec
prec2 = 1;
else
prec2 = 2;

27
Infix to Postfix
if(prec2 < prec1) // if prec of new op less
{ // than prec of old
theStack.push(opTop); // save newly-popped op
break;
}
else // prec of new not less
output = output + opTop; // than prec of old
} // end else (it's an operator)
} // end while
theStack.push(opThis); // push new operator
} // end gotOper()

Infix to Postfix

private void gotParen()


{ // got right paren from input
while( !theStack.isEmpty() )
{
char chx = theStack.pop();
if( chx == '(' ) // if popped '('
break; // we're done
else // if popped operator
output = output + chx; // output it
} // end while
} // end gotParen()
} // end class InToPost

28
Evaluación de una expresión Postfix
class ParsePost
{
private StackX theStack;
private String input;
public ParsePost(String s)
{ input = s; }
public int doParse()
{
theStack = new StackX(20); // make new stack
char ch;
int j;
int num1, num2, interAns;
for(j=0; j<input.length(); j++) // for each char,
{
ch = input.charAt(j); // read from input
if(ch >= '0' && ch <= '9') // if it's a number
theStack.push( (int)(ch-'0') ); // push it

Evaluación de una expresión Postfix


else // it's an operator
{
num2 = theStack.pop(); // pop operands
num1 = theStack.pop();
switch(ch) // do arithmetic
{
case '+':
interAns = num1 + num2;
break;
case '-':
interAns = num1 - num2;
break;
case '*':
interAns = num1 * num2;
break;
case '/':
interAns = num1 / num2;
break;

29
Evaluación de una expresión Postfix
default:
interAns = 0;
} // end switch
theStack.push(interAns); // push result
} // end else
} // end for
interAns = theStack.pop(); // get answer
return interAns;
} // end doParse()
} // end class ParsePost

El ADT Cola
n A semejanza de una pila, una cola es una
lista en la que se restringen las
operaciones permitidas:
n Solo se puede insertar en un extremo de la
lista.
n Solo se permite extraer elementos en el otro
extremo de la lista.
n Cualquier implementació
implementación de lista es
adecuada para colas.

30
Colas Usando Arreglos
n Es posible implementar colas usando arreglos de
modo que las operaciones requieren un tiempo
O(1)
n Ademá
Además del arreglo se tienen dos variables que
contienen los índices al inicio y fin de la cola.
n Tambié
También se usa una tercera variable que
contiene la longitud de la cola para diferenciar
una cola vací
vacía de una que llena todo el arreglo.

Colas Usando Arreglos


public class QueueAr
{
public QueueAr( )
{
this( DEFAULT_CAPACITY );
}
public QueueAr( int capacity )
{
theArray = new Object[ capacity ];
makeEmpty( );
}
public boolean isEmpty( )
{
return currentSize == 0;
}

31
Colas Usando Arreglos
public boolean isFull( )
{
return currentSize == theArray.length;
}
public void makeEmpty( )
{
currentSize = 0;
front = 0;
back = -1;
}
public Object getFront( )
{
if( isEmpty( ) )
return null;
return theArray[ front ];
}

Colas Usando Arreglos


public Object dequeue( )
{
if( isEmpty( ) )
return null;
currentSize--;
Object frontItem = theArray[ front ];
theArray[ front ] = null;
front = increment( front );
return frontItem;
}
public void enqueue( Object x ) throws Overflow
{
if( isFull( ) )
throw new Overflow( );
back = increment( back );
theArray[ back ] = x;
currentSize++;
}

32
Colas Usando Arreglos
private int increment( int x )
{
if( ++x == theArray.length )
x = 0;
return x;
}

private Object [ ] theArray;


private int currentSize;
private int front;
private int back;

static final int DEFAULT_CAPACITY = 10;


}

Aplicaciones de Colas

n Colas de impresió
impresión.
n Simulació
Simulación de lílíneas de espera.
n Colas de acceso a archivos en servidores

33

You might also like