//Pregunta 1

class ListaVacia  extends Exception{}

class ListaLlena extends Exception{}

class ListaNoParticionable extends Exception{}

class Nodo

{

	Nodo siguiente;

	Object palabra;

	Object significado;

	public Nodo(Object p, Object s, Nodo sig)

	{

		palabra=p;

		significado=s;

		siguiente=sig;

	}

}

static public int particionar(Lista x) throws Exception

{

	int numElem=0;

	Integer pivote;

	int numMenores=0;

	if(x.vacia())

	{

		return Integer.MAX_VALUE;

	}

	//cuento el numero de elementos de la lista, y chequeo

	//que la lista tenga elementos del mismo tipo

	for(numElem=0 ; x.buscar(numElem)!=null ; numElem++)

	{

	if(!((x.buscar(numElem)) instanceof Integer))

      	{

		throw new ListaNoParticionable();

	}

	}

	pivote=(Integer)x.buscar(0);



	//voy a guardar los menores en un arreglo, luego los

	//elimino de la lista y los reinserto al inicio

	Integer[] menores=new Integer[numElem];

	for(int j=0 ; j<numElem ; j++)

	{

		if( ((Integer)(x.buscar(j))).intValue()<(pivote.intValue()))

		{

			menores[numMenores]=(Integer)x.buscar(j);

			numMenores++;

		}

	}

	for(int j=0 ; j<numMenores ; j++)

	{

		x.eliminar(menores[j]);

	}

	for(int j=0 ; j<numMenores ; j++)

	{

		x.insertar(menores[j],0);

	}

	return pivote.intValue();

}



public void quicksort(Lista x) throws Exception

{

	//caso base de la recursion:lista vacia o con 1 elemento

	if(x.buscar(1)==null)

	{

		return;

	}

	Lista menores=new Lista();

	Lista mayores=new Lista();

	int pivote=particionar(x);

	int indicePivote=x.buscar(new Integer(pivote));

	int k;

	for(k=0 ; k<indicePivote ; k++)

	{

		menores.insertar(x.buscar(k),0);

	}

	for(k=0 ; k<indicePivote ; k++)

	{

		x.eliminar(x.buscar(0));//es cero porque al eliminar la numeracion se desplaza.

	}

	//por si el pivote esta repetido, busco la ultima vez que se repite

	for(k=0 ; ((Integer)(x.buscar(k))).intValue()==pivote ; k++)

	{

	}

	int indicePivote2 =k;		

	//capturo los mayores que el pivote, los inserto en otra lista, y luego los elimino

	for(k=indicePivote2 ; x.buscar(k)!=null; k++)

	{

		mayores.insertar(x.buscar(k),0);

	}

	for( ;x.buscar(indicePivote2)!=null ; )

	{

		x.eliminar( x.buscar(indicePivote2) );

	}

	//recursion

	quicksort(menores);

	quicksort(mayores);

	//concateno la solucion

	int i=0;

	while(menores.buscar(i)!=null)

	{

		x.insertar(menores.buscar(i),i);

		i++;

	}

	int indicePivote3 = i + indicePivote2 - 1;

	i=0;

	while(mayores.buscar(0)!=null)

	{

		x.insertar(mayores.buscar(0),indicePivote3 + i);

		mayores.eliminar(mayores.buscar(0));

		i++;

	}

}





//Pregunta 2

interface Comparable  //se puede usar una clase abstracta, pero es mejor esto

{

  public int compareTo(Comparable b);

}

class Diccionario

{

	//NOTA: Para poder realizar un orden de objetos, se requiere un operador de comparacion:

	// En java hay dos opciones al menos: hacer el codigo especifico para un tipo de objetos particular

	//o hacer el codigo para objetos que implementen una interfaz de comparacion (o una clase abstracta)

	//Lo ultimo es lo que haremos aqui. Para que esto funcione, el objeto debe implementar una interfaz

	//Comparable que obligue a la clase a implementar compareTo. Para que el codigo funcione,

	//todos los objetos deben ser convertidos a Comparable, siempre que se usa compareTo

	Nodo primero;

	public Diccionario()

	{

		primero=null;

	}

	public Object buscar1(Object x)   //secuencial, no explota orden, O(n) comparaciones peor caso

	{

		if(primero==null)

		{

			return null;

		}

		for(Nodo aux=primero; aux!=null ; aux=aux.siguiente)

		{

			if((aux.palabra).equals(x))

			{

				return aux.significado;

			}

		}

		return null;

  }

	public Object buscar(Object x) //binario, explota orden, O(log n) comparaciones peor caso.

	{

		Nodo inicio=primero;

		Nodo fin;

		Nodo aux;

		int i=0;

		for(aux=primero; aux.siguiente!=null; aux=aux.siguiente)

		{

			i++;

		}

		fin=aux;

		return busqBinaria(inicio, fin, i, x);

	}

 	 //ojo que BB con listas realiza O(n) recorridos de punteros peor caso con qu metodo se queda?



	public Object busqBinaria(Nodo inicio, Nodo fin, int largo, Object x)

	{

		Nodo centro;

		if(largo<2)

		{

			if((inicio.palabra).equals(x))

			{

				return inicio.significado;

			}

			if((fin.palabra).equals(x))

			{

				return fin.significado;

			}

			return null;

		}

		else

		{

			int j = largo/2;

			centro=inicio;

			for(int k=0; k<=j ;k++)

			{

				centro=centro.siguiente;

			}

			if(((Comparable)(centro.palabra)).compareTo((Comparable)x)<0)

			{

				return busqBinaria(inicio, centro, j, x);

				//al escribir codigo para alguna tarea o programa, hay que tener cuidado de los casos de borde. 

				//es usual este error al programar una BB.

			}

			else

			{

				return busqBinaria(centro, fin , j, x);

			}

		}

	}

  	//todos los mtodos que siguen deberan ser hechos con BB, pero ya vimos

  	//como se hace esto en el mtodo buscar. Queda propuesto la adaptacin.

	//como el proceso de busqueda se repite en los 4 metodos, se recomienda crear un solo

	//metodo que busque el nodo previo a una palabra cualquiera, exista o no exista en la lista. As se evita escribir la BB 4 veces.



	public boolean cambiar(Object x,Object y)

	{

		if(primero==null)

		{

			return false;

		}

		for(Nodo aux=primero; aux!=null ; aux=aux.siguiente)

		{

			if((aux.palabra).equals(x))

			{

				aux.significado=y;

				return true;

			}

		}

		return false;

	}	

	public boolean borrar(Object x)

	{

		if(buscar(x)==null)

		{

			return false;

		}

		if((primero.palabra).equals(x))

		{

			primero=primero.siguiente;

			return true;

		}

		for(Nodo aux=primero; aux!=null ; aux=aux.siguiente)

		{

			if((aux.siguiente.palabra).equals(x))

			{

				aux.siguiente=aux.siguiente.siguiente;

			}

		}

		return true;

	}

	public boolean agregar(Object x, Object y) //secuencial

	{

		Nodo aux;

		if(buscar(x)!=null)

		{

			return false;

		}

		if(primero==null)

		{

			primero=new Nodo(x,y,null);

			return true;

		}

		if(((Comparable)(primero.palabra)).compareTo((Comparable)x)>0)

		{

			primero=new Nodo(x,y,primero);

			return true;

		}

		for(aux=primero; aux.siguiente!=null ; aux=aux.siguiente)

		{

      			if(((Comparable)(aux.siguiente.palabra)).compareTo((Comparable)x)>0)

			{

				break;

			}

		}

		if(aux.siguiente==null)

		{

			aux.siguiente=new Nodo(x,y,null);

			return true;

		}

		else

		{

			Nodo n=new Nodo(x,y,aux.siguiente);

			aux.siguiente=n;

			return true;

		}

	}

}

