/*******************************************************************
 * Gruppe: Timo Singer, Michael Scholz, Ulf Gebhardt
 * 
 *******************************************************************
 *
 * Questions / Fragen
 *******************************************************************
 * a) How does the measured performance of contains_fast and 
 * contains_lecture relate to each other? Explain the result!
 *
 * Wie verhält sich die gemessene Laufzeit von den Methoden 
 * contains_fast und contains_lecture zu einander?  
 * Erklären Sie das Ergebnis!
 * ----------------------------------------------------------------
 * 
 * contains_fast ist circa doppelt (2x) so schnell, benötigt also in etwa
 * die Hälfte der Zeit, die contains_lecture benötigt.
 * 
 * Dieses Verhalten lässt sich dadurch erklären, dass das gesuchte Element
 * im Mittel in der Mitte der Liste liegt, d.h. die for-schleife in
 * contains_fast (im Mittel = für sehr viele Aufrufe) schon nach der Hälfte
 * abbricht, da das Element gefunden wurde und die funktion mit return
 * verlassen wird.
 * 
 * Vergleich der Funktionen:
 * 
 * Eingabemenge		Funktion			Schleifendurchläufe
 * n				contains_lecture	n	(jedes mal)
 * n				contains_fast		n/2 (im Durchschnitt!) 
 * ----------------------------------------------------------------
 * b) The method contains_java calls the predefined Java contains 
 * function for Lists. How does contains_java perform compared to 
 * the other methods? Do you have an idea, why?
 * 
 * Die Methode contains_java ruft die in der Java-API vordefinierte 
 * contains-Funktion für Listen auf. Wie verhält sich die Laufzeit 
 * von contains_java zu den anderen? Was könnte der Grund sein?
 * ----------------------------------------------------------------
 * 
 * contains_java ist nochmal schneller als contains_fast.
 * 
 * D.h, wenn man alle 3 Funktionen vergleicht, dann gilt für die Laufzeit
 * im Durchschnitt:
 * 
 * Laufzeit (im Durchschnitt):
 * 
 * contains_lecture > contains_fast > contains_java
 * 
 * contains_java ist schneller als contains_fast, da die für Listen
 * in der Java-API definierte Funktion einen noch effizienteren
 * Suchalgorithmus benutzt, als contains_fast.
 * 
 * Wir vermuten, dass als Suchalgorithmus die Binäre-Suche eingesetzt wird.
 * Diese hat eine Komplexität von O(log(n)), im Gegensatz zu O(n) für
 * contains_lecture & contains_fast.
 * 
 * Eine andere Erklärungsmöglichkeit, warum contains_java schneller ist, ist
 * dass die List-Klasse intern Hashing vornimmt. Dies führt im Durchschnitt
 * zu einem O(1), im schlechtesten Fall allerdings zu O(n).
 * 
 *******************************************************************/
import java.util.List;
import java.util.Random;


/**
 * This class offers three different implementations of the "contains" method.
 * Each method takes a list of strings and a string and checks whether the
 * string is contained in the list. 
 */
public class Contains {

	/**
	 * Calls the "contains"-function predefined by the Java List class. 
	 * 
	 * @param list A list of strings
	 * @param element A single string
	 * @return True if element is contained in list, false otherwise.
	 */
	public boolean contains_java(List<String> list, String element) {
		return list.contains(element);
	}


	/**
	 * The contains function as defined in the lecture 
	 * (Slide set 3, page 11).
	 * 
	 * @param list A list of strings
	 * @param element A single string
	 * @return True if element is contained in list, false otherwise.
	 */
	public boolean contains_lecture(List<String> list, String element) {
		boolean found = false;
		for (String s : list) {
			if (s.equals(element))
				found = true;
		}
		return found;	
	}

	/**
	 * Implemented a small optimization for the contains function
	 * defined in the lecture: As soon as the element is found,
	 * true is returned and iteration stops
	 * 
	 * @param list A list of strings
	 * @param element A single string
	 * @return True if element is contained in list, false otherwise.
	 */
	public boolean contains_fast(List<String> list, String element) {
		for (String s : list) {
			if (s.equals(element))
				return true;
		}
		return false;
	}

	/**
	 * Reads a list and performs a lot of random lookups using the three
	 * contains methods defined above. The elements looked for are
	 * randomly chosen from the list beforehand.
	 * 
	 * @param argv not used
	 */
	public static void main(String[] argv) {
		Contains c = new Contains();
		// Reads a long list of strings
		ListFileReader fr = new ListFileReader("countries.txt");
		// Random number generator
		Random rand = new Random();
		List<String> list = fr.getList();
		int length = list.size();

		for (int i=0; i<5000; i++) {
			// Read a random string from the list
			String string = list.get(rand.nextInt(length));
			// Check whether the string is contained (should always return true)
			c.contains_lecture(list, string);
			c.contains_fast(list, string);
			c.contains_java(list, string);
		}
	}
}
