<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
		<id>https://alda.iwr.uni-heidelberg.de/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Thorben</id>
		<title>Alda - User contributions [en]</title>
		<link rel="self" type="application/atom+xml" href="https://alda.iwr.uni-heidelberg.de/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Thorben"/>
		<link rel="alternate" type="text/html" href="https://alda.iwr.uni-heidelberg.de/index.php/Special:Contributions/Thorben"/>
		<updated>2026-05-08T08:23:01Z</updated>
		<subtitle>User contributions</subtitle>
		<generator>MediaWiki 1.30.0</generator>

	<entry>
		<id>https://alda.iwr.uni-heidelberg.de/index.php?title=Talk:Hashing_und_assoziative_Arrays&amp;diff=2222</id>
		<title>Talk:Hashing und assoziative Arrays</title>
		<link rel="alternate" type="text/html" href="https://alda.iwr.uni-heidelberg.de/index.php?title=Talk:Hashing_und_assoziative_Arrays&amp;diff=2222"/>
				<updated>2008-07-09T20:14:24Z</updated>
		
		<summary type="html">&lt;p&gt;Thorben: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''Wie sieht es denn jetzt mit einer Wiki Version aus?'''&lt;br /&gt;
&lt;br /&gt;
Warum als PDF? Das ist doch völlig am Sinn des Wikis vorbei...&lt;br /&gt;
&lt;br /&gt;
Finde ich auch, wenn du es schon als tex gemacht hast ist es doch super einfach&lt;br /&gt;
es in die Wiki zu übertragen, die unterstützt ja über &amp;lt; math &amp;gt; und &amp;lt; /math &amp;gt; auch&lt;br /&gt;
viele Latexbefehle...&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Hmmkay, war mir über die Funktionalität eines Wikis nicht ganz im klaren. Daher auch einfach &amp;quot;Faulheit&amp;quot; dahingehend, dass ich was genommen habe, was ich kannte. Wie gesagt, ich hätte sehr gern die Sourcen gescheit veröffentlicht, sodass eine gewissen Interaktualität gesichert wäre, aber .tex's darf man ja nicht hochladen. Ich kümmer mich frühestens Freitag, spätestens am Wochenende darum, dass ganze ins Wiki Format zu bringen. Sorry für die Verzögerung, Übungsblätter rufen...&lt;/div&gt;</summary>
		<author><name>Thorben</name></author>	</entry>

	<entry>
		<id>https://alda.iwr.uni-heidelberg.de/index.php?title=Talk:Graphen_und_Graphenalgorithmen&amp;diff=1784</id>
		<title>Talk:Graphen und Graphenalgorithmen</title>
		<link rel="alternate" type="text/html" href="https://alda.iwr.uni-heidelberg.de/index.php?title=Talk:Graphen_und_Graphenalgorithmen&amp;diff=1784"/>
				<updated>2008-06-18T15:14:54Z</updated>
		
		<summary type="html">&lt;p&gt;Thorben: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Habe die Graphen k1 bis k5 mit Graphviz gezeichnet und die Bilder gegen die ASCII Art ausgetauscht.&lt;br /&gt;
&lt;br /&gt;
Hier meine Quelltext:&lt;br /&gt;
k1.dot:&lt;br /&gt;
  graph {&lt;br /&gt;
        1&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
k2.dot:&lt;br /&gt;
  graph {&lt;br /&gt;
        1 -- 2&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
k3.dot:&lt;br /&gt;
  graph {&lt;br /&gt;
        1 -- 2&lt;br /&gt;
        2 -- 3&lt;br /&gt;
        3 -- 1&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
k4.dot:&lt;br /&gt;
  graph {&lt;br /&gt;
        1 -- 2 [weight = 10]&lt;br /&gt;
        1 -- 3&lt;br /&gt;
        2 -- 3 [weight = 10]&lt;br /&gt;
        3 -- 4 [weight = 10]&lt;br /&gt;
        4 -- 1 [weight = 10]&lt;br /&gt;
        4 -- 2&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
k5.dot&lt;br /&gt;
  graph {&lt;br /&gt;
        1 -- 2&lt;br /&gt;
        2 -- 3&lt;br /&gt;
        3 -- 4&lt;br /&gt;
        4 -- 5&lt;br /&gt;
        5 -- 1&lt;br /&gt;
&lt;br /&gt;
        1 -- 3&lt;br /&gt;
        1 -- 4&lt;br /&gt;
        2 -- 4&lt;br /&gt;
        2 -- 5&lt;br /&gt;
        5 -- 3&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
Generierung der Graphiken mit:&lt;br /&gt;
  #!/bin/bash&lt;br /&gt;
  for i in *.dot; do&lt;br /&gt;
        fdp -Tpng $i -Gcharset=latin1 -o `basename $i .dot`.png&lt;br /&gt;
  done;&lt;br /&gt;
&lt;br /&gt;
Gerichteter Graph:&lt;br /&gt;
  digraph {&lt;br /&gt;
        1 -&amp;gt; 2&lt;br /&gt;
        1 -&amp;gt; 4&lt;br /&gt;
        3 -&amp;gt; 2&lt;br /&gt;
        3 -&amp;gt; 4&lt;br /&gt;
  }&lt;br /&gt;
und übersetzt mit &amp;lt;tt&amp;gt;circo&amp;lt;/tt&amp;gt;&lt;br /&gt;
[[User:Thorben|Thorben]]&lt;/div&gt;</summary>
		<author><name>Thorben</name></author>	</entry>

	<entry>
		<id>https://alda.iwr.uni-heidelberg.de/index.php?title=Graphen_und_Graphenalgorithmen&amp;diff=1783</id>
		<title>Graphen und Graphenalgorithmen</title>
		<link rel="alternate" type="text/html" href="https://alda.iwr.uni-heidelberg.de/index.php?title=Graphen_und_Graphenalgorithmen&amp;diff=1783"/>
				<updated>2008-06-18T15:13:54Z</updated>
		
		<summary type="html">&lt;p&gt;Thorben: Gerichteter Graph als Graphik gemacht&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Einführung zu Graphen ==&lt;br /&gt;
&lt;br /&gt;
=== Motivation ===&lt;br /&gt;
&lt;br /&gt;
==== Königsberger - Brückenproblem ====&lt;br /&gt;
(1736 Euler)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:Koenigsberg.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Königsberger Brücken:&lt;br /&gt;
&lt;br /&gt;
Spaziergang durch Königsberg, so dass alle Brücken nur einmal überquert werden.&lt;br /&gt;
&lt;br /&gt;
Geometrie:&lt;br /&gt;
Topologie&lt;br /&gt;
&lt;br /&gt;
     O&lt;br /&gt;
    || \&lt;br /&gt;
    ||  \&lt;br /&gt;
     O   O&lt;br /&gt;
    ||  /&lt;br /&gt;
    || /&lt;br /&gt;
     O&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* '''Definition: ungerichteter Graph'''&lt;br /&gt;
&lt;br /&gt;
Ein ungerichteter Graph G = ( V, E )&lt;br /&gt;
&lt;br /&gt;
** V ist endliche Menge von Knoten (vertices)&lt;br /&gt;
** E c V × V (edges)&lt;br /&gt;
&lt;br /&gt;
Ein Graph heißt ungerichtet, wenn zusätzlich gilt:&lt;br /&gt;
&lt;br /&gt;
(x,y) ∈ E =&amp;gt; (y,x) ∈ E (symmetrie)&lt;br /&gt;
&lt;br /&gt;
Bsp:&lt;br /&gt;
&lt;br /&gt;
gerichteter Graph&lt;br /&gt;
[[Image:digraph.png|gerichteter Graph]]&lt;br /&gt;
&lt;br /&gt;
 ungerichtet&lt;br /&gt;
 &lt;br /&gt;
  O&lt;br /&gt;
 || \&lt;br /&gt;
 ||  \&lt;br /&gt;
  O   O&lt;br /&gt;
 ||  /&lt;br /&gt;
 || /&lt;br /&gt;
  O&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
   &lt;br /&gt;
&lt;br /&gt;
Bsp:&lt;br /&gt;
&lt;br /&gt;
* Landkarten:&lt;br /&gt;
** Knoten: Länder&lt;br /&gt;
** Kanten: gem. Grenzen&lt;br /&gt;
&lt;br /&gt;
* Schaltkreis:&lt;br /&gt;
** Knoten: Gatter&lt;br /&gt;
** Kanten: Verbindungen&lt;br /&gt;
&lt;br /&gt;
* Chemie (Summenformeln):&lt;br /&gt;
** Knoten: Elemente&lt;br /&gt;
** Kanten: Bindungen &lt;br /&gt;
&lt;br /&gt;
* Soziologie (StudieVZ)&lt;br /&gt;
** Soziogramm&lt;br /&gt;
*** Knoten: Personen&lt;br /&gt;
*** Kanten: Freund von ...&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* '''Definition: Vollständige Graphen'''&lt;br /&gt;
&lt;br /&gt;
Bei vollständigen Graphen ist jeder Knoten mit allen anderen Knoten verbunden.&lt;br /&gt;
&lt;br /&gt;
E =  U V (v,w) u (w,v)   |  v ∈ V, w ∈ V, u != w&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;0&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;0&amp;quot; style=&amp;quot;margin: 1em auto 1em auto&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| [[Image:k1.png|frame|k1]]&lt;br /&gt;
| [[Image:k2.png|frame|k2]]&lt;br /&gt;
| [[Image:k3.png|frame|k3]]&lt;br /&gt;
|-&lt;br /&gt;
| [[Image:k4.png|frame|k4]]&lt;br /&gt;
| [[Image:k5.png|frame|k5]]&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
''Rätsel''&lt;br /&gt;
Auf einer Party sind Leute. Alle stoßen miteinander an. Es hat 78 mal &amp;quot;Pling&amp;quot; gemacht.&lt;br /&gt;
Wieviele Leute waren da?&lt;br /&gt;
&lt;br /&gt;
== Repräsentation von Graphen ==&lt;br /&gt;
&lt;br /&gt;
Sei G = ( V, E ) geg und liege V in einer lineraren Sortierung vor.&lt;br /&gt;
V = { v1, ...., vn }&lt;br /&gt;
&lt;br /&gt;
== Adjazenzmatrix ==&lt;br /&gt;
&lt;br /&gt;
AG = aij = {1 falls (vi, vj) ∈ E ; sonst 0}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Bsp:&lt;br /&gt;
&lt;br /&gt;
 v = { a,b,c,d }     b      d&lt;br /&gt;
                     | \  / |&lt;br /&gt;
                     |  \/  |&lt;br /&gt;
                     |  /\  |&lt;br /&gt;
                     | /  \ |&lt;br /&gt;
                     a      c&lt;br /&gt;
 &lt;br /&gt;
       a b c d&lt;br /&gt;
      -----------&lt;br /&gt;
      (0 1 0 1) |a &lt;br /&gt;
 AG = (1 0 1 0) |b&lt;br /&gt;
      (0 1 0 1) |c&lt;br /&gt;
      (1 0 1 0) |d&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Adjezenzlisten ==&lt;br /&gt;
&lt;br /&gt;
al(v) = {v' ∈ V | (u,u') ∈ E}&lt;br /&gt;
Lg = ((v1, al(v1)), ...., (vn, al(vn))&lt;br /&gt;
&lt;br /&gt;
Python:&lt;br /&gt;
&lt;br /&gt;
 Array von Arrays [[...],[...],...,[...]]&lt;br /&gt;
                     0     1         n&lt;br /&gt;
&lt;br /&gt;
* '''Definition: Teilgraphen'''&lt;br /&gt;
&lt;br /&gt;
Ein Graph G' = (v',E') ist ein Teilgraph, wenn gilt:&lt;br /&gt;
&lt;br /&gt;
** v' c V &lt;br /&gt;
** E' c E &lt;br /&gt;
&lt;br /&gt;
Er heißt erzegender Graph, wenn zusätzlich gilt:&lt;br /&gt;
&lt;br /&gt;
** v' = V&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* '''Definition: Knotengrade'''&lt;br /&gt;
Für G = (v,E)und v ∈ V&lt;br /&gt;
grad(v) = |{v' ∈ V | v,v'∈ E}|&lt;br /&gt;
out_grad(v) = |   -&amp;quot;&amp;quot;-       |&lt;br /&gt;
in_grad(v)  = |{v'∈ V| (v',v) ∈ E}|&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Bsp: &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 ungerichtet&lt;br /&gt;
 &lt;br /&gt;
  c&lt;br /&gt;
 || \&lt;br /&gt;
 ||  \&lt;br /&gt;
  b   d          grad(a) = | {b,b,d} | = 3&lt;br /&gt;
 ||  /&lt;br /&gt;
 || /&lt;br /&gt;
  a&lt;br /&gt;
 &lt;br /&gt;
  &lt;br /&gt;
 gerichtet&lt;br /&gt;
 &lt;br /&gt;
  c←&lt;br /&gt;
  | \&lt;br /&gt;
  ↓  \&lt;br /&gt;
  b←--d         out_grad(d) = 2 = | {c,b} |&lt;br /&gt;
  |  /→          in_grad(d) = 1 = | {a} |&lt;br /&gt;
  ↓ /&lt;br /&gt;
  a&lt;br /&gt;
&lt;br /&gt;
* '''Definition: Wege'''&lt;br /&gt;
&lt;br /&gt;
Sei G = (v,E)&lt;br /&gt;
&lt;br /&gt;
** Für v0 ∈ V ist (v0) ein Weg in G&lt;br /&gt;
** Für Knoten v1,...vn,vn+1 und eine Kante (vn,vn+1) ∈ E ist mit einem Weg (v0,....vn) in G auch (v0,...,vn,vn+1) ein Weg in G.&lt;br /&gt;
&lt;br /&gt;
Also: Nichtleere Folgen von Knoten die durch eine Kante verbunden sind.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Eulerweg ==&lt;br /&gt;
&lt;br /&gt;
    O&lt;br /&gt;
   /  \&lt;br /&gt;
  O----O&lt;br /&gt;
  | \/ |&lt;br /&gt;
  | /\ |   &amp;quot;Das Haus vom Nikolaus&amp;quot; Alle ''Kanten'' werden nur ''einmal'' passiert&lt;br /&gt;
  O----O&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Hamiltonweg == &lt;br /&gt;
&lt;br /&gt;
    O&lt;br /&gt;
   /   &lt;br /&gt;
  O----O&lt;br /&gt;
     /  &lt;br /&gt;
    /      Alle ''Knoten'' werden nur ''einmal'' passiert&lt;br /&gt;
  O----O&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Kreis == &lt;br /&gt;
&lt;br /&gt;
    O&lt;br /&gt;
   /  \&lt;br /&gt;
  O    O&lt;br /&gt;
  |    |   v0 = vn&lt;br /&gt;
  |    |   vi != vj   Für Alle i,j   i !=j; i,j &amp;gt;0; i,j &amp;lt; n&lt;br /&gt;
  O----O     &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Zyklen ==&lt;br /&gt;
&lt;br /&gt;
    O&lt;br /&gt;
   /  \&lt;br /&gt;
  O    O&lt;br /&gt;
    \  |&lt;br /&gt;
     \ |   Wie Kreis nur ohne (vi != vj)&lt;br /&gt;
  O====O&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* '''Definition: planare Graphen'''&lt;br /&gt;
&lt;br /&gt;
Ist ein Graph, der auf einer Ebene gezeichnet werden ''kann'', sodass sich die Kanten nicht schneiden!&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Bsp:&lt;br /&gt;
&lt;br /&gt;
 1)  &lt;br /&gt;
 &lt;br /&gt;
      O&lt;br /&gt;
     /|\&lt;br /&gt;
    / O \&lt;br /&gt;
   / / \ \&lt;br /&gt;
   O     O&lt;br /&gt;
&lt;br /&gt;
 2)&lt;br /&gt;
 &lt;br /&gt;
    O&lt;br /&gt;
   /  \&lt;br /&gt;
  O----O&lt;br /&gt;
  | \/ |&lt;br /&gt;
  | /\ |   &lt;br /&gt;
  O----O&lt;br /&gt;
&lt;br /&gt;
 3)&lt;br /&gt;
 &lt;br /&gt;
 |----O   @&lt;br /&gt;
 |   /@ \&lt;br /&gt;
 |  O----O&lt;br /&gt;
 |  |@ / |&lt;br /&gt;
 |  | / @|   &lt;br /&gt;
 |  O----O               @ entspricht ''Regionen'' auch ausserhalb der Figur ist eine Region&lt;br /&gt;
 |@      |&lt;br /&gt;
 |-------|&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
1),2) und 3) sind planare Graphen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Der K5 Graph ist kein planarer Graph da sich zwangsweise Kanten schneiden.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* '''Definition: dualer Graph'''&lt;br /&gt;
&lt;br /&gt;
Der duale Graph eines geg. planaren Graphs G' ist ein Graph mit&lt;br /&gt;
&lt;br /&gt;
** Knoten für jede Region&lt;br /&gt;
** Für jede Kante aus E gilt es gibt eine Kante, die die angrenzende Region mit Knoten verbindet.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 dualer Graph&lt;br /&gt;
&lt;br /&gt;
      O------O&lt;br /&gt;
      |     /| \&lt;br /&gt;
    |-|-@  / | @\---|&lt;br /&gt;
    | | |\/  |/| O  |&lt;br /&gt;
    | | |/\ /| |/   |&lt;br /&gt;
    | | /  @ | /    |&lt;br /&gt;
    | O-+--+-O |    |&lt;br /&gt;
    |   |  |   |    |&lt;br /&gt;
    |---|--@---|----|&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* '''Definition: erreichbar'''&lt;br /&gt;
&lt;br /&gt;
 W ∈ V ist erreichbar von v ∈ G gdw.:&lt;br /&gt;
 es Existiert Weg(v,...w)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* '''Definition: Zusammenhang'''&lt;br /&gt;
&lt;br /&gt;
 G heißt zusammenhängend, wenn für Alle v,w ∈V gilt:&lt;br /&gt;
 w ist erreichbar von V&lt;br /&gt;
&lt;br /&gt;
== Bäume ==&lt;br /&gt;
&lt;br /&gt;
* '''Definition: Baum'''&lt;br /&gt;
&lt;br /&gt;
 Ein Baum ist ein zusammenhängender, kreisfreier Graph.&lt;br /&gt;
&lt;br /&gt;
Bsp.: Binary Search Tree&lt;br /&gt;
&lt;br /&gt;
* '''Definition: erzeugender Baum'''&lt;br /&gt;
&lt;br /&gt;
 für G = (v,E) ist ein erzeigender Teilgraph mit Baumeigenschaft&lt;br /&gt;
&lt;br /&gt;
Bsp.: &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    O    O&lt;br /&gt;
   /    /   &lt;br /&gt;
  O    O    O&lt;br /&gt;
  |  /    /   &lt;br /&gt;
  | /    /    &lt;br /&gt;
  O----O----O&lt;br /&gt;
&lt;br /&gt;
== Durchlaufen von Graphen ==&lt;br /&gt;
&lt;br /&gt;
=== Tiefensuche in Graphen ===&lt;br /&gt;
&lt;br /&gt;
Sei der Graph geg als Liste von Listen = g&lt;br /&gt;
&lt;br /&gt;
 def dfs (g,node,v=0):&lt;br /&gt;
   if v == 0:&lt;br /&gt;
     v = [0]*len(g) #visited-Liste&lt;br /&gt;
   v[node] = 1 #besuche node&lt;br /&gt;
   for t in g[node]: #gehe zu allen Nachbarn&lt;br /&gt;
     if v[t] == 0: #falls diese noch nicht besucht&lt;br /&gt;
       dfs(g,t,v) #Rekursion&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:Tiefens.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Aufruf dfs(g,1)&lt;br /&gt;
&lt;br /&gt;
=&amp;gt;Folge 1,2,4,3,6,7,5&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Breitensuche ===&lt;br /&gt;
&lt;br /&gt;
 from Queue import *&lt;br /&gt;
 def bfs(g,startnode)&lt;br /&gt;
   v = [0]*len(g)&lt;br /&gt;
   q = Queue()&lt;br /&gt;
   v = [startnode] = 1 #besuche&lt;br /&gt;
   q.put(startnode) #in Schlange&lt;br /&gt;
   while not q.get()&lt;br /&gt;
     node = q.get()&lt;br /&gt;
     for t in q[node]&lt;br /&gt;
       if v[t] == 0:&lt;br /&gt;
         v[t] = 1&lt;br /&gt;
         q.put(t)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:Breitens.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=&amp;gt;Folge 1,2,3,4,5,6,7&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Damenproblem ==&lt;br /&gt;
&lt;br /&gt;
  ---------------&lt;br /&gt;
 |   | X |   |   |&lt;br /&gt;
 |---|---|---|---| &lt;br /&gt;
 |   |   |   | X |&lt;br /&gt;
 |---|---|---|---|&lt;br /&gt;
 | X |   |   |   |&lt;br /&gt;
 |---|---|---|---|&lt;br /&gt;
 |   |   |   | X |&lt;br /&gt;
  ---------------&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
4 Damen auf einem vereinfachten Schachbrett so Positionieren, dass sich keine bedroht.&lt;br /&gt;
&lt;br /&gt;
erster Durchlauf:&lt;br /&gt;
&lt;br /&gt;
[[Image:Suche1.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
zweiter Durchlauf:&lt;br /&gt;
&lt;br /&gt;
[[Image:Suche2.jpg]]&lt;/div&gt;</summary>
		<author><name>Thorben</name></author>	</entry>

	<entry>
		<id>https://alda.iwr.uni-heidelberg.de/index.php?title=File:Digraph.png&amp;diff=1782</id>
		<title>File:Digraph.png</title>
		<link rel="alternate" type="text/html" href="https://alda.iwr.uni-heidelberg.de/index.php?title=File:Digraph.png&amp;diff=1782"/>
				<updated>2008-06-18T15:12:23Z</updated>
		
		<summary type="html">&lt;p&gt;Thorben: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Thorben</name></author>	</entry>

	<entry>
		<id>https://alda.iwr.uni-heidelberg.de/index.php?title=Talk:Graphen_und_Graphenalgorithmen&amp;diff=1781</id>
		<title>Talk:Graphen und Graphenalgorithmen</title>
		<link rel="alternate" type="text/html" href="https://alda.iwr.uni-heidelberg.de/index.php?title=Talk:Graphen_und_Graphenalgorithmen&amp;diff=1781"/>
				<updated>2008-06-18T15:08:19Z</updated>
		
		<summary type="html">&lt;p&gt;Thorben: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Habe die Graphen k1 bis k5 mit Graphviz gezeichnet und die Bilder gegen die ASCII Art ausgetauscht.&lt;br /&gt;
&lt;br /&gt;
Hier meine Quelltext:&lt;br /&gt;
k1.dot:&lt;br /&gt;
  graph {&lt;br /&gt;
        1&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
k2.dot:&lt;br /&gt;
  graph {&lt;br /&gt;
        1 -- 2&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
k3.dot:&lt;br /&gt;
  graph {&lt;br /&gt;
        1 -- 2&lt;br /&gt;
        2 -- 3&lt;br /&gt;
        3 -- 1&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
k4.dot:&lt;br /&gt;
  graph {&lt;br /&gt;
        1 -- 2 [weight = 10]&lt;br /&gt;
        1 -- 3&lt;br /&gt;
        2 -- 3 [weight = 10]&lt;br /&gt;
        3 -- 4 [weight = 10]&lt;br /&gt;
        4 -- 1 [weight = 10]&lt;br /&gt;
        4 -- 2&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
k5.dot&lt;br /&gt;
  graph {&lt;br /&gt;
        1 -- 2&lt;br /&gt;
        2 -- 3&lt;br /&gt;
        3 -- 4&lt;br /&gt;
        4 -- 5&lt;br /&gt;
        5 -- 1&lt;br /&gt;
&lt;br /&gt;
        1 -- 3&lt;br /&gt;
        1 -- 4&lt;br /&gt;
        2 -- 4&lt;br /&gt;
        2 -- 5&lt;br /&gt;
        5 -- 3&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
Generierung der Graphiken mit:&lt;br /&gt;
  #!/bin/bash&lt;br /&gt;
  for i in *.dot; do&lt;br /&gt;
        fdp -Tpng $i -Gcharset=latin1 -o `basename $i .dot`.png&lt;br /&gt;
  done;&lt;br /&gt;
[[User:Thorben|Thorben]]&lt;/div&gt;</summary>
		<author><name>Thorben</name></author>	</entry>

	<entry>
		<id>https://alda.iwr.uni-heidelberg.de/index.php?title=Talk:Graphen_und_Graphenalgorithmen&amp;diff=1780</id>
		<title>Talk:Graphen und Graphenalgorithmen</title>
		<link rel="alternate" type="text/html" href="https://alda.iwr.uni-heidelberg.de/index.php?title=Talk:Graphen_und_Graphenalgorithmen&amp;diff=1780"/>
				<updated>2008-06-18T15:07:25Z</updated>
		
		<summary type="html">&lt;p&gt;Thorben: New page: Habe die Graphen k1 bis k5 mit Graphviz gezeichnet und die Bilder gegen die ASCII Art ausgetauscht.  Hier meine Quelltext: k1.dot: graph {         1 }  k2.dot: graph {         1 -- 2 }  k3...&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Habe die Graphen k1 bis k5 mit Graphviz gezeichnet und die Bilder gegen die ASCII Art ausgetauscht.&lt;br /&gt;
&lt;br /&gt;
Hier meine Quelltext:&lt;br /&gt;
k1.dot:&lt;br /&gt;
graph {&lt;br /&gt;
        1&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
k2.dot:&lt;br /&gt;
graph {&lt;br /&gt;
        1 -- 2&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
k3.dot:&lt;br /&gt;
graph {&lt;br /&gt;
        1 -- 2&lt;br /&gt;
        2 -- 3&lt;br /&gt;
        3 -- 1&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
k4.dot:&lt;br /&gt;
graph {&lt;br /&gt;
        1 -- 2 [weight = 10]&lt;br /&gt;
        1 -- 3&lt;br /&gt;
        2 -- 3 [weight = 10]&lt;br /&gt;
        3 -- 4 [weight = 10]&lt;br /&gt;
        4 -- 1 [weight = 10]&lt;br /&gt;
        4 -- 2&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
k5.dot&lt;br /&gt;
graph {&lt;br /&gt;
        1 -- 2&lt;br /&gt;
        2 -- 3&lt;br /&gt;
        3 -- 4&lt;br /&gt;
        4 -- 5&lt;br /&gt;
        5 -- 1&lt;br /&gt;
&lt;br /&gt;
        1 -- 3&lt;br /&gt;
        1 -- 4&lt;br /&gt;
        2 -- 4&lt;br /&gt;
        2 -- 5&lt;br /&gt;
        5 -- 3&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Generierung der Graphiken mit:&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
for i in *.dot; do&lt;br /&gt;
        fdp -Tpng $i -Gcharset=latin1 -o `basename $i .dot`.png&lt;br /&gt;
done;&lt;/div&gt;</summary>
		<author><name>Thorben</name></author>	</entry>

	<entry>
		<id>https://alda.iwr.uni-heidelberg.de/index.php?title=Graphen_und_Graphenalgorithmen&amp;diff=1779</id>
		<title>Graphen und Graphenalgorithmen</title>
		<link rel="alternate" type="text/html" href="https://alda.iwr.uni-heidelberg.de/index.php?title=Graphen_und_Graphenalgorithmen&amp;diff=1779"/>
				<updated>2008-06-18T15:03:14Z</updated>
		
		<summary type="html">&lt;p&gt;Thorben: Graphen mit Graphviz gezeichnet --&amp;gt; siehe Talk&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Einführung zu Graphen ==&lt;br /&gt;
&lt;br /&gt;
=== Motivation ===&lt;br /&gt;
&lt;br /&gt;
==== Königsberger - Brückenproblem ====&lt;br /&gt;
(1736 Euler)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:Koenigsberg.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Königsberger Brücken:&lt;br /&gt;
&lt;br /&gt;
Spaziergang durch Königsberg, so dass alle Brücken nur einmal überquert werden.&lt;br /&gt;
&lt;br /&gt;
Geometrie:&lt;br /&gt;
Topologie&lt;br /&gt;
&lt;br /&gt;
     O&lt;br /&gt;
    || \&lt;br /&gt;
    ||  \&lt;br /&gt;
     O   O&lt;br /&gt;
    ||  /&lt;br /&gt;
    || /&lt;br /&gt;
     O&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* '''Definition: ungerichteter Graph'''&lt;br /&gt;
&lt;br /&gt;
Ein ungerichteter Graph G = ( V, E )&lt;br /&gt;
&lt;br /&gt;
** V ist endliche Menge von Knoten (vertices)&lt;br /&gt;
** E c V × V (edges)&lt;br /&gt;
&lt;br /&gt;
Ein Graph heißt ungerichtet, wenn zusätzlich gilt:&lt;br /&gt;
&lt;br /&gt;
(x,y) ∈ E =&amp;gt; (y,x) ∈ E (symmetrie)&lt;br /&gt;
&lt;br /&gt;
Bsp:&lt;br /&gt;
 &lt;br /&gt;
 gerichtet&lt;br /&gt;
 &lt;br /&gt;
 O----→O&lt;br /&gt;
 |     ↑&lt;br /&gt;
 ↓     |&lt;br /&gt;
 O←----O&lt;br /&gt;
&lt;br /&gt;
 ungerichtet&lt;br /&gt;
 &lt;br /&gt;
  O&lt;br /&gt;
 || \&lt;br /&gt;
 ||  \&lt;br /&gt;
  O   O&lt;br /&gt;
 ||  /&lt;br /&gt;
 || /&lt;br /&gt;
  O&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
   &lt;br /&gt;
&lt;br /&gt;
Bsp:&lt;br /&gt;
&lt;br /&gt;
* Landkarten:&lt;br /&gt;
** Knoten: Länder&lt;br /&gt;
** Kanten: gem. Grenzen&lt;br /&gt;
&lt;br /&gt;
* Schaltkreis:&lt;br /&gt;
** Knoten: Gatter&lt;br /&gt;
** Kanten: Verbindungen&lt;br /&gt;
&lt;br /&gt;
* Chemie (Summenformeln):&lt;br /&gt;
** Knoten: Elemente&lt;br /&gt;
** Kanten: Bindungen &lt;br /&gt;
&lt;br /&gt;
* Soziologie (StudieVZ)&lt;br /&gt;
** Soziogramm&lt;br /&gt;
*** Knoten: Personen&lt;br /&gt;
*** Kanten: Freund von ...&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* '''Definition: Vollständige Graphen'''&lt;br /&gt;
&lt;br /&gt;
Bei vollständigen Graphen ist jeder Knoten mit allen anderen Knoten verbunden.&lt;br /&gt;
&lt;br /&gt;
E =  U V (v,w) u (w,v)   |  v ∈ V, w ∈ V, u != w&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;0&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;0&amp;quot; style=&amp;quot;margin: 1em auto 1em auto&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| [[Image:k1.png|frame|k1]]&lt;br /&gt;
| [[Image:k2.png|frame|k2]]&lt;br /&gt;
| [[Image:k3.png|frame|k3]]&lt;br /&gt;
|-&lt;br /&gt;
| [[Image:k4.png|frame|k4]]&lt;br /&gt;
| [[Image:k5.png|frame|k5]]&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
''Rätsel''&lt;br /&gt;
Auf einer Party sind Leute. Alle stoßen miteinander an. Es hat 78 mal &amp;quot;Pling&amp;quot; gemacht.&lt;br /&gt;
Wieviele Leute waren da?&lt;br /&gt;
&lt;br /&gt;
== Repräsentation von Graphen ==&lt;br /&gt;
&lt;br /&gt;
Sei G = ( V, E ) geg und liege V in einer lineraren Sortierung vor.&lt;br /&gt;
V = { v1, ...., vn }&lt;br /&gt;
&lt;br /&gt;
== Adjazenzmatrix ==&lt;br /&gt;
&lt;br /&gt;
AG = aij = {1 falls (vi, vj) ∈ E ; sonst 0}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Bsp:&lt;br /&gt;
&lt;br /&gt;
 v = { a,b,c,d }     b      d&lt;br /&gt;
                     | \  / |&lt;br /&gt;
                     |  \/  |&lt;br /&gt;
                     |  /\  |&lt;br /&gt;
                     | /  \ |&lt;br /&gt;
                     a      c&lt;br /&gt;
 &lt;br /&gt;
       a b c d&lt;br /&gt;
      -----------&lt;br /&gt;
      (0 1 0 1) |a &lt;br /&gt;
 AG = (1 0 1 0) |b&lt;br /&gt;
      (0 1 0 1) |c&lt;br /&gt;
      (1 0 1 0) |d&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Adjezenzlisten ==&lt;br /&gt;
&lt;br /&gt;
al(v) = {v' ∈ V | (u,u') ∈ E}&lt;br /&gt;
Lg = ((v1, al(v1)), ...., (vn, al(vn))&lt;br /&gt;
&lt;br /&gt;
Python:&lt;br /&gt;
&lt;br /&gt;
 Array von Arrays [[...],[...],...,[...]]&lt;br /&gt;
                     0     1         n&lt;br /&gt;
&lt;br /&gt;
* '''Definition: Teilgraphen'''&lt;br /&gt;
&lt;br /&gt;
Ein Graph G' = (v',E') ist ein Teilgraph, wenn gilt:&lt;br /&gt;
&lt;br /&gt;
** v' c V &lt;br /&gt;
** E' c E &lt;br /&gt;
&lt;br /&gt;
Er heißt erzegender Graph, wenn zusätzlich gilt:&lt;br /&gt;
&lt;br /&gt;
** v' = V&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* '''Definition: Knotengrade'''&lt;br /&gt;
Für G = (v,E)und v ∈ V&lt;br /&gt;
grad(v) = |{v' ∈ V | v,v'∈ E}|&lt;br /&gt;
out_grad(v) = |   -&amp;quot;&amp;quot;-       |&lt;br /&gt;
in_grad(v)  = |{v'∈ V| (v',v) ∈ E}|&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Bsp: &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 ungerichtet&lt;br /&gt;
 &lt;br /&gt;
  c&lt;br /&gt;
 || \&lt;br /&gt;
 ||  \&lt;br /&gt;
  b   d          grad(a) = | {b,b,d} | = 3&lt;br /&gt;
 ||  /&lt;br /&gt;
 || /&lt;br /&gt;
  a&lt;br /&gt;
 &lt;br /&gt;
  &lt;br /&gt;
 gerichtet&lt;br /&gt;
 &lt;br /&gt;
  c←&lt;br /&gt;
  | \&lt;br /&gt;
  ↓  \&lt;br /&gt;
  b←--d         out_grad(d) = 2 = | {c,b} |&lt;br /&gt;
  |  /→          in_grad(d) = 1 = | {a} |&lt;br /&gt;
  ↓ /&lt;br /&gt;
  a&lt;br /&gt;
&lt;br /&gt;
* '''Definition: Wege'''&lt;br /&gt;
&lt;br /&gt;
Sei G = (v,E)&lt;br /&gt;
&lt;br /&gt;
** Für v0 ∈ V ist (v0) ein Weg in G&lt;br /&gt;
** Für Knoten v1,...vn,vn+1 und eine Kante (vn,vn+1) ∈ E ist mit einem Weg (v0,....vn) in G auch (v0,...,vn,vn+1) ein Weg in G.&lt;br /&gt;
&lt;br /&gt;
Also: Nichtleere Folgen von Knoten die durch eine Kante verbunden sind.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Eulerweg ==&lt;br /&gt;
&lt;br /&gt;
    O&lt;br /&gt;
   /  \&lt;br /&gt;
  O----O&lt;br /&gt;
  | \/ |&lt;br /&gt;
  | /\ |   &amp;quot;Das Haus vom Nikolaus&amp;quot; Alle ''Kanten'' werden nur ''einmal'' passiert&lt;br /&gt;
  O----O&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Hamiltonweg == &lt;br /&gt;
&lt;br /&gt;
    O&lt;br /&gt;
   /   &lt;br /&gt;
  O----O&lt;br /&gt;
     /  &lt;br /&gt;
    /      Alle ''Knoten'' werden nur ''einmal'' passiert&lt;br /&gt;
  O----O&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Kreis == &lt;br /&gt;
&lt;br /&gt;
    O&lt;br /&gt;
   /  \&lt;br /&gt;
  O    O&lt;br /&gt;
  |    |   v0 = vn&lt;br /&gt;
  |    |   vi != vj   Für Alle i,j   i !=j; i,j &amp;gt;0; i,j &amp;lt; n&lt;br /&gt;
  O----O     &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Zyklen ==&lt;br /&gt;
&lt;br /&gt;
    O&lt;br /&gt;
   /  \&lt;br /&gt;
  O    O&lt;br /&gt;
    \  |&lt;br /&gt;
     \ |   Wie Kreis nur ohne (vi != vj)&lt;br /&gt;
  O====O&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* '''Definition: planare Graphen'''&lt;br /&gt;
&lt;br /&gt;
Ist ein Graph, der auf einer Ebene gezeichnet werden ''kann'', sodass sich die Kanten nicht schneiden!&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Bsp:&lt;br /&gt;
&lt;br /&gt;
 1)  &lt;br /&gt;
 &lt;br /&gt;
      O&lt;br /&gt;
     /|\&lt;br /&gt;
    / O \&lt;br /&gt;
   / / \ \&lt;br /&gt;
   O     O&lt;br /&gt;
&lt;br /&gt;
 2)&lt;br /&gt;
 &lt;br /&gt;
    O&lt;br /&gt;
   /  \&lt;br /&gt;
  O----O&lt;br /&gt;
  | \/ |&lt;br /&gt;
  | /\ |   &lt;br /&gt;
  O----O&lt;br /&gt;
&lt;br /&gt;
 3)&lt;br /&gt;
 &lt;br /&gt;
 |----O   @&lt;br /&gt;
 |   /@ \&lt;br /&gt;
 |  O----O&lt;br /&gt;
 |  |@ / |&lt;br /&gt;
 |  | / @|   &lt;br /&gt;
 |  O----O               @ entspricht ''Regionen'' auch ausserhalb der Figur ist eine Region&lt;br /&gt;
 |@      |&lt;br /&gt;
 |-------|&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
1),2) und 3) sind planare Graphen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Der K5 Graph ist kein planarer Graph da sich zwangsweise Kanten schneiden.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* '''Definition: dualer Graph'''&lt;br /&gt;
&lt;br /&gt;
Der duale Graph eines geg. planaren Graphs G' ist ein Graph mit&lt;br /&gt;
&lt;br /&gt;
** Knoten für jede Region&lt;br /&gt;
** Für jede Kante aus E gilt es gibt eine Kante, die die angrenzende Region mit Knoten verbindet.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 dualer Graph&lt;br /&gt;
&lt;br /&gt;
      O------O&lt;br /&gt;
      |     /| \&lt;br /&gt;
    |-|-@  / | @\---|&lt;br /&gt;
    | | |\/  |/| O  |&lt;br /&gt;
    | | |/\ /| |/   |&lt;br /&gt;
    | | /  @ | /    |&lt;br /&gt;
    | O-+--+-O |    |&lt;br /&gt;
    |   |  |   |    |&lt;br /&gt;
    |---|--@---|----|&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* '''Definition: erreichbar'''&lt;br /&gt;
&lt;br /&gt;
 W ∈ V ist erreichbar von v ∈ G gdw.:&lt;br /&gt;
 es Existiert Weg(v,...w)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* '''Definition: Zusammenhang'''&lt;br /&gt;
&lt;br /&gt;
 G heißt zusammenhängend, wenn für Alle v,w ∈V gilt:&lt;br /&gt;
 w ist erreichbar von V&lt;br /&gt;
&lt;br /&gt;
== Bäume ==&lt;br /&gt;
&lt;br /&gt;
* '''Definition: Baum'''&lt;br /&gt;
&lt;br /&gt;
 Ein Baum ist ein zusammenhängender, kreisfreier Graph.&lt;br /&gt;
&lt;br /&gt;
Bsp.: Binary Search Tree&lt;br /&gt;
&lt;br /&gt;
* '''Definition: erzeugender Baum'''&lt;br /&gt;
&lt;br /&gt;
 für G = (v,E) ist ein erzeigender Teilgraph mit Baumeigenschaft&lt;br /&gt;
&lt;br /&gt;
Bsp.: &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    O    O&lt;br /&gt;
   /    /   &lt;br /&gt;
  O    O    O&lt;br /&gt;
  |  /    /   &lt;br /&gt;
  | /    /    &lt;br /&gt;
  O----O----O&lt;br /&gt;
&lt;br /&gt;
== Durchlaufen von Graphen ==&lt;br /&gt;
&lt;br /&gt;
=== Tiefensuche in Graphen ===&lt;br /&gt;
&lt;br /&gt;
Sei der Graph geg als Liste von Listen = g&lt;br /&gt;
&lt;br /&gt;
 def dfs (g,node,v=0):&lt;br /&gt;
   if v == 0:&lt;br /&gt;
     v = [0]*len(g) #visited-Liste&lt;br /&gt;
   v[node] = 1 #besuche node&lt;br /&gt;
   for t in g[node]: #gehe zu allen Nachbarn&lt;br /&gt;
     if v[t] == 0: #falls diese noch nicht besucht&lt;br /&gt;
       dfs(g,t,v) #Rekursion&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:Tiefens.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Aufruf dfs(g,1)&lt;br /&gt;
&lt;br /&gt;
=&amp;gt;Folge 1,2,4,3,6,7,5&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Breitensuche ===&lt;br /&gt;
&lt;br /&gt;
 from Queue import *&lt;br /&gt;
 def bfs(g,startnode)&lt;br /&gt;
   v = [0]*len(g)&lt;br /&gt;
   q = Queue()&lt;br /&gt;
   v = [startnode] = 1 #besuche&lt;br /&gt;
   q.put(startnode) #in Schlange&lt;br /&gt;
   while not q.get()&lt;br /&gt;
     node = q.get()&lt;br /&gt;
     for t in q[node]&lt;br /&gt;
       if v[t] == 0:&lt;br /&gt;
         v[t] = 1&lt;br /&gt;
         q.put(t)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:Breitens.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=&amp;gt;Folge 1,2,3,4,5,6,7&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Damenproblem ==&lt;br /&gt;
&lt;br /&gt;
  ---------------&lt;br /&gt;
 |   | X |   |   |&lt;br /&gt;
 |---|---|---|---| &lt;br /&gt;
 |   |   |   | X |&lt;br /&gt;
 |---|---|---|---|&lt;br /&gt;
 | X |   |   |   |&lt;br /&gt;
 |---|---|---|---|&lt;br /&gt;
 |   |   |   | X |&lt;br /&gt;
  ---------------&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
4 Damen auf einem vereinfachten Schachbrett so Positionieren, dass sich keine bedroht.&lt;br /&gt;
&lt;br /&gt;
erster Durchlauf:&lt;br /&gt;
&lt;br /&gt;
[[Image:Suche1.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
zweiter Durchlauf:&lt;br /&gt;
&lt;br /&gt;
[[Image:Suche2.jpg]]&lt;/div&gt;</summary>
		<author><name>Thorben</name></author>	</entry>

	<entry>
		<id>https://alda.iwr.uni-heidelberg.de/index.php?title=File:K5.png&amp;diff=1777</id>
		<title>File:K5.png</title>
		<link rel="alternate" type="text/html" href="https://alda.iwr.uni-heidelberg.de/index.php?title=File:K5.png&amp;diff=1777"/>
				<updated>2008-06-18T14:47:31Z</updated>
		
		<summary type="html">&lt;p&gt;Thorben: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Thorben</name></author>	</entry>

	<entry>
		<id>https://alda.iwr.uni-heidelberg.de/index.php?title=File:K4.png&amp;diff=1776</id>
		<title>File:K4.png</title>
		<link rel="alternate" type="text/html" href="https://alda.iwr.uni-heidelberg.de/index.php?title=File:K4.png&amp;diff=1776"/>
				<updated>2008-06-18T14:47:09Z</updated>
		
		<summary type="html">&lt;p&gt;Thorben: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Thorben</name></author>	</entry>

	<entry>
		<id>https://alda.iwr.uni-heidelberg.de/index.php?title=File:K3.png&amp;diff=1774</id>
		<title>File:K3.png</title>
		<link rel="alternate" type="text/html" href="https://alda.iwr.uni-heidelberg.de/index.php?title=File:K3.png&amp;diff=1774"/>
				<updated>2008-06-18T14:46:48Z</updated>
		
		<summary type="html">&lt;p&gt;Thorben: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Thorben</name></author>	</entry>

	<entry>
		<id>https://alda.iwr.uni-heidelberg.de/index.php?title=File:K2.png&amp;diff=1773</id>
		<title>File:K2.png</title>
		<link rel="alternate" type="text/html" href="https://alda.iwr.uni-heidelberg.de/index.php?title=File:K2.png&amp;diff=1773"/>
				<updated>2008-06-18T14:46:16Z</updated>
		
		<summary type="html">&lt;p&gt;Thorben: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Thorben</name></author>	</entry>

	<entry>
		<id>https://alda.iwr.uni-heidelberg.de/index.php?title=File:K1.png&amp;diff=1771</id>
		<title>File:K1.png</title>
		<link rel="alternate" type="text/html" href="https://alda.iwr.uni-heidelberg.de/index.php?title=File:K1.png&amp;diff=1771"/>
				<updated>2008-06-18T14:45:53Z</updated>
		
		<summary type="html">&lt;p&gt;Thorben: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Thorben</name></author>	</entry>

	<entry>
		<id>https://alda.iwr.uni-heidelberg.de/index.php?title=Talk:Main_Page&amp;diff=1742</id>
		<title>Talk:Main Page</title>
		<link rel="alternate" type="text/html" href="https://alda.iwr.uni-heidelberg.de/index.php?title=Talk:Main_Page&amp;diff=1742"/>
				<updated>2008-06-10T23:10:38Z</updated>
		
		<summary type="html">&lt;p&gt;Thorben: /* Spam */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Änderungsvorschläge ==&lt;br /&gt;
&lt;br /&gt;
=== zum Übungsbetrieb ===&lt;br /&gt;
&lt;br /&gt;
Bitte die Email-Adressen der Tutoren eintragen, so wie es schon für Thomas Gerlach der Fall ist.&lt;br /&gt;
:Ich hatte jetzt nur die von Daniel (Do Gruppe) parat, habe sie mal eingetragen [[Special:Contributions/83.189.36.163|83.189.36.163]] 13:41, 13 April 2008 (UTC)&lt;br /&gt;
&lt;br /&gt;
Die Übungen sind ja auch mal wieder extrem einfach und beanspruchen fast grkeine Zeit... Ich sitze jetzt schon so ziemlich den ganzen Tag der zweiten Aufgabe und keine Ende in sicht... als ob wir sonst keine Uni hätten.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Zu Übungsblatt 2:==&lt;br /&gt;
In-place sortieren bei selection- und quick-sort ist mir ja noch einsichtig - aber bei merge-sort? ist der algorithmus nicht so spezifiziert, dass man eine neue liste/ein neues array aufbaut? oder sollen wir einfach noch ne kapsel-funktion schreiben, und die neu-aufgebaute liste am ende auf die ausgangsliste verweisen lassen; das wäre zwar kein in-place sortieren im eigentlichen sinne, aber anders kann ich es mir gerade nicht vorstellen.&lt;br /&gt;
:Also ich denke eher, dass das ein Fehler in der Aufgabenstellung ist. Quick und Merge in-place ist doch schon ziemlich kontroproduktiv...&lt;br /&gt;
::U. Köthe: In-place war in der Aufgabe nicht so gemeint, dass die Algorithmen intern keinen zusätzlichen Speicher verwenden dürfen, sondern dass das sortierte Array am Ende das unsortierte überschreiben soll.&lt;br /&gt;
&lt;br /&gt;
Vllt. hilft das ja noch jemandem, der mit seinem quick-sort nicht zu Rande kommt: hab die Erfahrung gemacht, dass es keine korrekten Ergebnisse liefert, wenn man die repeat-untils aus der Spezifikation aus der Vorlesung einfach in whiles mit umgekehrter Bedingung macht (also aus repeat...until a[j]&amp;lt;=a[p] etwa while a[j]&amp;gt;a[p]) - python hat zwar keine repeat-untils, aber mit einem while True...und einem den Block abschließenden if a[j]&amp;lt;=a[p]:break kann man das simulieren, und dann kann man einfach die spezifikationen in python eintippen.&lt;br /&gt;
&lt;br /&gt;
== Spam ==&lt;br /&gt;
&lt;br /&gt;
Ich schlage vor einfach mal alle nicht deutsch(sprachig)en IPs zu verbieten, da die Bots wohl aus USA/AU kommen (http://www.who.is/whois-ip/ip-address/208.17.80.5/).&lt;br /&gt;
Ausserdem vorsicht beim reverten, vorhin sind da ein paar Einträge verlorengegangen.&lt;br /&gt;
&lt;br /&gt;
Eine weitere Möglichkeit besteht darin, die Website unter Passwortschutz zu stellen und das Passwort in der Vorlesung bekanntzugeben. Dieses Passwort muss ja kein großes Geheimnis sein, sondern soll nur Bots daran hindern, die Seite zu manipulieren.&lt;br /&gt;
&lt;br /&gt;
Finde ich alles nicht so sinnvoll. Reicht es nicht, dass man sich registrieren muss? Hat den weiteren Vorteil das man den Autoren mal Namen zuordnen kann... [[User:Thorben|Thorben]]&lt;/div&gt;</summary>
		<author><name>Thorben</name></author>	</entry>

	<entry>
		<id>https://alda.iwr.uni-heidelberg.de/index.php?title=File:HASHTB12.svg.png&amp;diff=1741</id>
		<title>File:HASHTB12.svg.png</title>
		<link rel="alternate" type="text/html" href="https://alda.iwr.uni-heidelberg.de/index.php?title=File:HASHTB12.svg.png&amp;diff=1741"/>
				<updated>2008-06-10T23:01:00Z</updated>
		
		<summary type="html">&lt;p&gt;Thorben: from Wikipedia: http://upload.wikimedia.org/wikipedia/commons/thumb/9/90/HASHTB12.svg/362px-HASHTB12.svg.png&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;from Wikipedia: http://upload.wikimedia.org/wikipedia/commons/thumb/9/90/HASHTB12.svg/362px-HASHTB12.svg.png&lt;/div&gt;</summary>
		<author><name>Thorben</name></author>	</entry>

	<entry>
		<id>https://alda.iwr.uni-heidelberg.de/index.php?title=Hashing_und_assoziative_Arrays&amp;diff=1740</id>
		<title>Hashing und assoziative Arrays</title>
		<link rel="alternate" type="text/html" href="https://alda.iwr.uni-heidelberg.de/index.php?title=Hashing_und_assoziative_Arrays&amp;diff=1740"/>
				<updated>2008-06-10T23:00:30Z</updated>
		
		<summary type="html">&lt;p&gt;Thorben: /* Hashtabelle mit offener Adressierung (offenes Hashing) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Mitschrift gibts [http://hci.iwr.uni-heidelberg.de/alda/images/AlDa.pdf hier] als PDF und [http://hci.iwr.uni-heidelberg.de/alda/images/Alda_source.pdf hier] gibts die TeX-Sourcen, leider als PDF weil man wohl keine .TeXs hochladen darf. Originale gibts auf Anfrage bei kirchner at cl dot uni minus heidelberg dot de. Wird das Package &amp;quot;listings&amp;quot; verwendet, das gibts bei [http://tug.ctan.org/tex-archive/macros/latex/contrib/listings/ http://tug.ctan.org/tex-archive/macros/latex/contrib/listings/] &lt;br /&gt;
&lt;br /&gt;
Tipp- und sonstige Fehler dürfen gerne verbessert und erneut hochgeladen werden, oder gebt mir per Email Bescheid, dann pflege ich die   Korrektur ein :)&lt;br /&gt;
&lt;br /&gt;
Ich Finde dein Aufschrieb sollte ins Wiki übetragen werden, das bietet auch alles, was   &lt;br /&gt;
du mit Latex machen kannst. Die Bäume kannst du z.B. mit Latex zeichnen, einen pro Seite und diese dann in eine png Datei umwandeln. Wie sowas geht kann man z.B. in den Quellen von doxygen oder mediawiki selbst nachlesen. Oder man zoomt rein und macht einen Screenshot :-)&lt;br /&gt;
&lt;br /&gt;
== Hashtabelle mit linearer Verkettung ==&lt;br /&gt;
[[Image:HASHTB32.svg.png|frame|Prinzip ([http://en.wikipedia.org/wiki/Hash_table Quelle])]]&lt;br /&gt;
&lt;br /&gt;
Pessimistischer Ansatz: Kollisionen treten häufig auf, deshalb wird unter jedem&lt;br /&gt;
Hashindex gleich eine Liste angelegt, in der Einträge aufgenommen werden können.&lt;br /&gt;
&lt;br /&gt;
===Implementation in Python===&lt;br /&gt;
''HashNode'' ist eine Hilfsdatenstruktur, die Schlüssel und Wert speichert&lt;br /&gt;
und mit Hilfe von ''next'' eine verkettete Liste realisiert&lt;br /&gt;
  class HashNode:&lt;br /&gt;
      def __init__(self,key,data,next):&lt;br /&gt;
          self.key = key&lt;br /&gt;
          self.data = data&lt;br /&gt;
          self.next = next # Verkettung!&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Die eigentliche Hashtabelle wird in der Klasse ''HashTable'' implementiert:&lt;br /&gt;
  class HashTable:&lt;br /&gt;
      def __init__(self):&lt;br /&gt;
         self.capacity = ... # Geeignete Werte siehe unten&lt;br /&gt;
         self.size = 0&lt;br /&gt;
         self.array = [None]*self.capacity&lt;br /&gt;
&lt;br /&gt;
In Python ([http://docs.python.org/ref/sequence-types.html Python Docs zum Thema]) wird der Zugriffsoperator ''[ ]'' für eine Datenstruktur wie folgt (innerhalb einer Klasse) implementiert:&lt;br /&gt;
  def __setitem__(self, key, value)&lt;br /&gt;
&lt;br /&gt;
so dass im Programmtext dann folgende Syntax möglich ist: &amp;lt;tt&amp;gt;a[key] = value&amp;lt;/tt&amp;gt; (schreibender Zugriff auf &amp;lt;tt&amp;gt;a[key]&amp;lt;/tt&amp;gt;).&lt;br /&gt;
Analog wird der lesende Zugriff &amp;lt;tt&amp;gt;value = a[key]&amp;lt;/tt&amp;gt; wie folgt umgesetzt:&lt;br /&gt;
  def __getitem__(self, key, value)&lt;br /&gt;
&lt;br /&gt;
Implementierung der &amp;lt;tt&amp;gt;__setitem__&amp;lt;/tt&amp;gt;-Funktion in der &amp;lt;tt&amp;gt;HashTable&amp;lt;/tt&amp;gt;-Klasse:&lt;br /&gt;
  def __setitem__(self, key, value):&lt;br /&gt;
      index = hash(key) % self.capacity&lt;br /&gt;
      node = self.array[index]&lt;br /&gt;
      while node is not None:&lt;br /&gt;
          if node.key == key:&lt;br /&gt;
              # Element key ist schon in der Tabelle&lt;br /&gt;
              #Überschreibe die Daten mit dem neuen Wert&lt;br /&gt;
              node.data = value&lt;br /&gt;
              return&lt;br /&gt;
          # Kollision des Hashwerts, probiere nächsten Key aus&lt;br /&gt;
          node = node.next&lt;br /&gt;
      # Kein Element hatte den richtigen Schlüssel.&lt;br /&gt;
      # ==&amp;gt;Es gibt diesen Schlüssel noch nicht&lt;br /&gt;
      # Füge also ein neues Element in die Hashtabelle ein&lt;br /&gt;
       &lt;br /&gt;
      self.array[index] = HashNode(key, value, self.array[index])&lt;br /&gt;
      # Der alte Anfang der Liste wurde der Nachfolger des neu eingefügten&lt;br /&gt;
      # ersten Elements&lt;br /&gt;
       &lt;br /&gt;
      self.size += 1&lt;br /&gt;
&lt;br /&gt;
Und die Implementierung der &amp;lt;tt&amp;gt;__getitem__&amp;lt;/tt&amp;gt; Funktionen:&lt;br /&gt;
  def __getitem__(self, key):&lt;br /&gt;
      index = hash(key) % self.capacity&lt;br /&gt;
      node = self.array[index]&lt;br /&gt;
      while node is not None:&lt;br /&gt;
           if node.key == key: # Gefunden!&lt;br /&gt;
               return node.data&lt;br /&gt;
           node = node.next&lt;br /&gt;
      raise KeyError(key)&lt;br /&gt;
&lt;br /&gt;
==== Wahl der Kapazität ====&lt;br /&gt;
In der C++ Standardbibliothek (Klasse &amp;lt;tt&amp;gt; [http://www.sgi.com/tech/stl/hash_map.htmlstd::hash_map std::hash_map]&amp;lt;/tt&amp;gt;) wird die Hashtabelle häufig mit Hilfe der linearen Verkettung&lt;br /&gt;
imlementiert. Dabei wird &amp;lt;tt&amp;gt;capacity&amp;lt;/tt&amp;gt; immer als ''Primzahl'' gewählt, wobei sich aufeinanderfolgende Kapazitäten immer ungefähr verdoppeln:&lt;br /&gt;
  53, 97, 193, 398, 769, ...&lt;br /&gt;
[http://gcc.gnu.org/viewcvs/*checkout*/trunk/libstdc++-v3/src/hashtable.cc GCC hashtable.cc (Primzahlen)] [http://gcc.gnu.org/viewcvs/*checkout*/trunk/libstdc++-v3/include/tr1_impl/hashtable_policy.h GCC Hash Implementation]&lt;br /&gt;
&lt;br /&gt;
Das hat zur Folge, dass &amp;lt;tt&amp;gt;hash(key) % self.capacity&amp;lt;/tt&amp;gt; ''alle'' Bits von h benutzt (Eigenschaft aus der Zahlentheorie). Die Kapizität wird vergrößert, wenn &amp;lt;tt&amp;gt;size == capacity&amp;lt;/tt&amp;gt; erreicht wird. Analog zum dynamischen Array werden die Daten dann aus dem alten Array (&amp;lt;tt&amp;gt;self.array&amp;lt;/tt&amp;gt;) in ein entsprechend vergrößertes neues Array kopiert.&lt;br /&gt;
&lt;br /&gt;
== Hashtabelle mit offener Adressierung (offenes Hashing) ==&lt;br /&gt;
[[Image:HASHTB12.svg.png|frame|Prinzip ([http://en.wikipedia.org/wiki/Hash_table Quelle])]]&lt;br /&gt;
&lt;br /&gt;
[http://de.wikipedia.org/wiki/Hashtabelle#Hashing_mit_offener_Adressierung Wikipedia (de)]&lt;br /&gt;
[http://en.wikipedia.org/wiki/Open_addressing Wikipedia (en)]&lt;br /&gt;
&lt;br /&gt;
Optimistischer Ansatz: Kollisionen werden nicht so häufig auftreten.&lt;br /&gt;
&lt;br /&gt;
=== Idee ===&lt;br /&gt;
Wenn &amp;lt;tt&amp;gt;array[index]&amp;lt;/tt&amp;gt; durch Kollision bereits vergeben ist, probiere einen&lt;br /&gt;
anderen Index aus.&lt;br /&gt;
&lt;br /&gt;
* Das Array enthält pro Element höchstens ein (key,value)-Paar&lt;br /&gt;
* Das Array muss stets mindestens ''einen'' freien Platz haben (sonst gäbe es beim Ausprobieren anderer Indizes eine Endlosschleife). Es gilt immer &amp;lt;tt&amp;gt;self.size &amp;lt; self.capacity&amp;lt;/tt&amp;gt;. Dies war bei der vorigen Hash-Implementation mit linearer Verkettung nicht notwendig (aber im Sinne schneller zugriffszeiten trotzdem wünschenswert).&lt;br /&gt;
&lt;br /&gt;
=== Vorgehen bei Kollisionen ===&lt;br /&gt;
&lt;br /&gt;
==== Sequentielles Sondieren====&lt;br /&gt;
Probiere den nächsten Index: &amp;lt;tt&amp;gt;index = (index+1) % capacity&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Vorteil: einfach&lt;br /&gt;
* Nachteil: Clusterbildung&lt;br /&gt;
&lt;br /&gt;
Clusterbildung heißt, dass sich größere zusammenhängende Bereiche bilden die belegt sind, unterbrochen von Bereichen die komplett frei sind. Beim Versuche des Einfügens eines Elements an einen Platz, der schon belegt ist, muss jetzt das ganze Cluster sequentiell durchlaufen werden, bis ein freier Platz gefunden wird. Damit entspricht die Komplexität der Suche der mittleren Länge der belegten Bereiche, was sich entsprechend in einer langsamen Suche widerspiegelt.&lt;br /&gt;
&lt;br /&gt;
==== Doppeltes Hashing ====&lt;br /&gt;
[http://de.wikipedia.org/wiki/Doppel-Hashing Wikipedia (de)] [http://en.wikipedia.org/wiki/Double_hashing Wikipedia (en)]&lt;br /&gt;
&lt;br /&gt;
Bestimme einen neuen Index (bei Kollisionen) durch eine ''2. Hashfunktion''.&lt;br /&gt;
&lt;br /&gt;
Das doppelte Hashing wird typischerweise in der Praxis angewendet und liegt auch der Python Implementierung des Datentyps [http://docs.python.org/tut/node7.html#SECTION007500000000000000000 Dictionary] (Syntax &amp;lt;tt&amp;gt;{'a':1, 'b':2, 'c':3}&amp;lt;/tt&amp;gt; zugrunde.&lt;br /&gt;
&lt;br /&gt;
Eine effiziente Implementierung dieses Datentyps ist für die Performance der Skriptsprache Python extrem wichtig, da z.B. beim Aufruf einer Funktion der auszuführunde Code in einem Dictionary unter dem Schlüssel ''Funktionsname'' nachgeschlagen wird oder die Werte lokaler Variablen innerhalb einer Funktion ebenfalls in einem Dictionary zu finden sind.&lt;br /&gt;
&lt;br /&gt;
Für die Implementierung in Python werden wieder die obigen Klassen &amp;lt;tt&amp;gt;HashNode&amp;lt;/tt&amp;gt; (das Attribut &amp;lt;tt&amp;gt;next&amp;lt;/tt&amp;gt; kann allerdings jetzt entfernt werden) und &amp;lt;tt&amp;gt;HashTable&amp;lt;/tt&amp;gt; benötigt, es folgen die angepassten Implementationen von &amp;lt;tt&amp;gt;__setitem__&amp;lt;/tt&amp;gt; und &amp;lt;tt&amp;gt;__getitem__&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
  def __setitem__(self, key, value):&lt;br /&gt;
      h = hash(key)&lt;br /&gt;
      index = h % self.capacity&lt;br /&gt;
      while True:&lt;br /&gt;
          if self.array[index] is None or self.array[index].key is None:&lt;br /&gt;
               # das Feld ist frei (1. Abfrage)&lt;br /&gt;
               # oder das Feld ist als frei markiert (2. Abfrage)&lt;br /&gt;
               self.array[index] = HashNode(key, value)&lt;br /&gt;
               self.size +=1&lt;br /&gt;
               return&lt;br /&gt;
          if self.array[index].key == key:&lt;br /&gt;
               # Es gibt diesen Schlüssel schon,&lt;br /&gt;
               # überschreibe die Daten&lt;br /&gt;
               self.array[index].data = value&lt;br /&gt;
               return&lt;br /&gt;
          # Letzter Fall: Kollision =&amp;gt; neuer Index durch 2. Hashfunktion&lt;br /&gt;
          index = (5*index+1+h) % self.capacity&lt;br /&gt;
          h = h &amp;gt;&amp;gt; 5&lt;br /&gt;
(für den &amp;lt;tt&amp;gt;&amp;gt;&amp;gt;&amp;lt;/tt&amp;gt;-Operator, siehe die [http://docs.python.org/ref/shifting.html Python Dokumentation])&lt;br /&gt;
&lt;br /&gt;
Die vorgestellte Implementierung orientiert sich an Pythons interner Dictionary Implementierung, der zugehörige Quelltext (mit ausführlichem Kommentar) findet sich unter [http://svn.python.org/view/*checkout*/python/trunk/Objects/dictobject.c dictobject.c Python Implementation (SVN)]&lt;br /&gt;
&lt;br /&gt;
===== Beispiel =====&lt;br /&gt;
Mit Zahlen &amp;lt;math&amp;gt;2^5&amp;lt;/math&amp;gt; statt &amp;lt;math&amp;gt;2^{32}&amp;lt;/math&amp;gt;.&lt;br /&gt;
  h=25, capacity=8&lt;br /&gt;
  i_0 = 25%8 = 1&lt;br /&gt;
  Es finde eine Kollision statt.&lt;br /&gt;
  i_1 = (5*1+h)%8 = 31%8 = 7&lt;br /&gt;
  h = h&amp;gt;&amp;gt;2 &amp;lt;==&amp;gt; h = (0b11001)&amp;gt;&amp;gt;2 = 0b00110 = 6&lt;br /&gt;
  Es finde eine Kollision statt.&lt;br /&gt;
  i_2 = (5*7+1+h)%8  =42%8 = 2&lt;br /&gt;
  h = h&amp;gt;&amp;gt;2 &amp;lt;==&amp;gt; h=1&lt;br /&gt;
  Es finde eine Kollision statt.&lt;br /&gt;
  i_3 = (5*2+1+h)%8 = 12%8 = 4&lt;br /&gt;
  h = h&amp;gt;&amp;gt;2 &amp;lt;==&amp;gt; h=0&lt;br /&gt;
  Es finde eine Kollision statt.&lt;br /&gt;
  i_4 = (5*4+1+0)%8 = 5&lt;br /&gt;
  i_5 = (5*5+1)%8 = 2&lt;br /&gt;
  i_6 = (5*2+1)%8 = 3&lt;br /&gt;
   ...&lt;br /&gt;
Allen Indizes werden erreicht bevor sich die Folge wiederholt.&lt;br /&gt;
&lt;br /&gt;
===== Komplexität des offenen Hashings =====&lt;br /&gt;
&lt;br /&gt;
* Annahme: uniformes Hashing, das heißt alle Indizes haben gleiche Wahrscheinlichkeit&lt;br /&gt;
* Füllstand &amp;lt;math&amp;gt;\alpha = \frac{\text{size}}{\text{capacity}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* '''Erfolglose Suche''' (d.h. es wird entweder ein neues Element eingefügt oder ein &amp;lt;tt&amp;gt;KeyError&amp;lt;/tt&amp;gt; geworfen): Untere Schranke für die Komplexität ist &amp;lt;math&amp;gt;\Omega\left(\frac{1}{1-\alpha}\right)&amp;lt;/math&amp;gt; Schritte (= Anzahl der notwendigen index-Berechnungen).&lt;br /&gt;
* '''Erfolgreiche Suche''' &amp;lt;math&amp;gt;\Omega\left(\frac{1}{\alpha}\ln\left(\frac{1}{1-\alpha}\right)\right)&amp;lt;/math&amp;gt; Schritte.&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;5&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
! &amp;lt;math&amp;gt;\alpha&amp;lt;/math&amp;gt;&lt;br /&gt;
! 0.5&lt;br /&gt;
! 0.9&lt;br /&gt;
|- &lt;br /&gt;
| erfolglos&lt;br /&gt;
| 2.0&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| erfolgreich&lt;br /&gt;
| 1.4&lt;br /&gt;
| 2.6&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===== Wahl der Kapazität =====&lt;br /&gt;
In Python wird &amp;lt;tt&amp;gt;capacity&amp;lt;/tt&amp;gt; Aufgrund der obigen Beobachtung so gewählt, dass &amp;lt;math&amp;gt;\alpha \leq 2/3&amp;lt;/math&amp;gt;. Falls &amp;lt;math&amp;gt;\alpha&amp;lt;/math&amp;gt; größer werden sollte, verdopple die Kapazität und kopiere das alte array in das neue Array (analog zum dynamischen Array)&lt;br /&gt;
&lt;br /&gt;
In Python werden die Kapazitätsgrößen als Zweierpotenzen gewählt, also 4,8,16,32,...,&lt;br /&gt;
so dass &amp;lt;tt&amp;gt;h % self.capacity&amp;lt;/tt&amp;gt; nur die unteren Bits von &amp;lt;tt&amp;gt;h&amp;lt;/tt&amp;gt; benutzt.&lt;br /&gt;
&lt;br /&gt;
== Anwendung von Hashing ==&lt;br /&gt;
&lt;br /&gt;
* Hashtabelle, assoziatives Aray&lt;br /&gt;
* Sortieren in linearer Zeit (Übungsaufgabe 6.2)&lt;br /&gt;
* Suchen von Strings in Texten: Rabin-Karp-Algorithmus&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
=== Rabin Karp Algorithmus ===&lt;br /&gt;
[http://de.wikipedia.org/wiki/Rabin-Karp-Algorithmus Wikipedia (de)] [http://en.wikipedia.org/wiki/Rabin-Karp_string_search_algorithm Wikipedia (en)]&lt;br /&gt;
&lt;br /&gt;
In Textverarbeitungsanwendungen ist eine häufig benutzte Funktion die ''Search &amp;amp; Replace'' Funktionalität. Die Suche sollte in O(len(text)) möglich sein, aber ein naiver Algorithmus braucht O(len(text)*len(searchstring))&lt;br /&gt;
&lt;br /&gt;
==== Naive Implementierung der Suche ====&lt;br /&gt;
  def search(text, s):&lt;br /&gt;
      M, N = len(text), len(s)&lt;br /&gt;
      for k in range(M-N):&lt;br /&gt;
          if s==text[k:k+N]:   # O(N), da N Zeichen verglichen werden müssen&lt;br /&gt;
              return k&lt;br /&gt;
      return -1 #nicht gefunden&lt;br /&gt;
&lt;br /&gt;
==== Idee des Rabin Karp Algorithmus ====&lt;br /&gt;
Statt Vergleichen &amp;lt;tt&amp;gt;s==text[k:k+N]&amp;lt;/tt&amp;gt;, die O(N) benötigen da N Vergleiche der Buchstaben durchgeführt werden müssen, Vergleiche die Hashs von Suchstring und dem zu untersuchenden Textabschnitt: &amp;lt;tt&amp;gt;hash(s) == hash(text[k:k+N])&amp;lt;/tt&amp;gt;. Dabei muss natürlich &amp;lt;tt&amp;gt;hash(s)&amp;lt;/tt&amp;gt; nur einmal berechnet werden, wohingegen &amp;lt;tt&amp;gt;hash(text[k:k+N])&amp;lt;/tt&amp;gt; immer wieder neu berechnet werden muss. Damit der Vergleich O(1) sein kann, ist es deswegen erforderlich, eine solche Hashfunktion zu haben, die nicht alle Zeichen (das wäre O(N) ) einlesen muss, sondern die vorhergehende Hashfunktion mit einbezieht.&lt;br /&gt;
&lt;br /&gt;
Eine solche Hashfunktion heißt ''Running Hash'' und funktioniert analog zum ''Sliding Mean''.&lt;br /&gt;
&lt;br /&gt;
Die Running Hash Funktion berechnet in O(1) den hash von &amp;lt;tt&amp;gt;text[k+1:k+1+N]&amp;lt;/tt&amp;gt; ausgehend vom hash für &amp;lt;tt&amp;gt;text[k:k+N]&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Idee: Interpretiere den Text als Ziffern in einer base d Darstellung:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h_k = \text{text}[k]\cdot d^{N-1} + \text{text}[k]\cdot d^{N-2} + \cdots + \text{text}[k+N-1]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für die Basis 10 (Dezimalsystem) ergibt sich also&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h_k = \text{text}[k]\cdot {10}^{N-1} + \text{text}[k]\cdot {10}^{N-2} + \cdots + \text{text}[k+N-1]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Daraus folgt&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h_{k+1} = 10\cdot h_k - \text{text}[k]\cdot {10}^{N} + \text{text}[k+N]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Komplexität dieses Updates ist O(1), falls man &amp;lt;math&amp;gt;{10}^{N}&amp;lt;/math&amp;gt; vorberechnet hat.&lt;br /&gt;
&lt;br /&gt;
In der Realität wählt man dann d=32 und benutzt noch an einigen Stellen modulo Operationen, um die Zahlen nicht zu groß werden zu lassen.&lt;br /&gt;
&lt;br /&gt;
==== Implementation ====&lt;br /&gt;
  def searchRabinKarp(text, s):&lt;br /&gt;
      ht, hs, dN = 0, 0, 1&lt;br /&gt;
      M, N = len(text), len(s)&lt;br /&gt;
      d, q = 32, 33554393&lt;br /&gt;
      #q ist eine große Primzahl, aber so,&lt;br /&gt;
      #dass d*q &amp;lt; 2**32 (um Überlauf zu vermeiden)&lt;br /&gt;
      &lt;br /&gt;
      #Initialisierung      &lt;br /&gt;
      for k in range(N):&lt;br /&gt;
          ht = (ht*d + ord(text[k])) % q&lt;br /&gt;
          #ord() gibt die ASCIInummer des übergebenen Zeichens zurück&lt;br /&gt;
          ds = (hs*d + ord( s[k] )) % q&lt;br /&gt;
          dN = (dN*a) % q&lt;br /&gt;
      #Die Variablen sind jetzt wie folgt initialisiert:&lt;br /&gt;
      #ht = hash(text[0:N])&lt;br /&gt;
      #hs = hash(s)&lt;br /&gt;
      #dN = (d**N) % q&lt;br /&gt;
      &lt;br /&gt;
      #Hauptschleife&lt;br /&gt;
      k = 0 &lt;br /&gt;
      while k &amp;lt; M-N:&lt;br /&gt;
          if hs == ht and s==text[k:k+N]:&lt;br /&gt;
              return k # serch string an Position k gefunden&lt;br /&gt;
          if k+N &amp;lt; M:&lt;br /&gt;
              ht = (d*ht - dN * ord(text[k]) + dN*q + ord(text[k+N]) ) % q&lt;br /&gt;
          k +=1&lt;br /&gt;
      return -1  # search string nicht gefunden&lt;/div&gt;</summary>
		<author><name>Thorben</name></author>	</entry>

	<entry>
		<id>https://alda.iwr.uni-heidelberg.de/index.php?title=Hashing_und_assoziative_Arrays&amp;diff=1739</id>
		<title>Hashing und assoziative Arrays</title>
		<link rel="alternate" type="text/html" href="https://alda.iwr.uni-heidelberg.de/index.php?title=Hashing_und_assoziative_Arrays&amp;diff=1739"/>
				<updated>2008-06-10T22:57:50Z</updated>
		
		<summary type="html">&lt;p&gt;Thorben: /* Hashtabelle mit linearer Verkettung */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Mitschrift gibts [http://hci.iwr.uni-heidelberg.de/alda/images/AlDa.pdf hier] als PDF und [http://hci.iwr.uni-heidelberg.de/alda/images/Alda_source.pdf hier] gibts die TeX-Sourcen, leider als PDF weil man wohl keine .TeXs hochladen darf. Originale gibts auf Anfrage bei kirchner at cl dot uni minus heidelberg dot de. Wird das Package &amp;quot;listings&amp;quot; verwendet, das gibts bei [http://tug.ctan.org/tex-archive/macros/latex/contrib/listings/ http://tug.ctan.org/tex-archive/macros/latex/contrib/listings/] &lt;br /&gt;
&lt;br /&gt;
Tipp- und sonstige Fehler dürfen gerne verbessert und erneut hochgeladen werden, oder gebt mir per Email Bescheid, dann pflege ich die   Korrektur ein :)&lt;br /&gt;
&lt;br /&gt;
Ich Finde dein Aufschrieb sollte ins Wiki übetragen werden, das bietet auch alles, was   &lt;br /&gt;
du mit Latex machen kannst. Die Bäume kannst du z.B. mit Latex zeichnen, einen pro Seite und diese dann in eine png Datei umwandeln. Wie sowas geht kann man z.B. in den Quellen von doxygen oder mediawiki selbst nachlesen. Oder man zoomt rein und macht einen Screenshot :-)&lt;br /&gt;
&lt;br /&gt;
== Hashtabelle mit linearer Verkettung ==&lt;br /&gt;
[[Image:HASHTB32.svg.png|frame|Prinzip ([http://en.wikipedia.org/wiki/Hash_table Quelle])]]&lt;br /&gt;
&lt;br /&gt;
Pessimistischer Ansatz: Kollisionen treten häufig auf, deshalb wird unter jedem&lt;br /&gt;
Hashindex gleich eine Liste angelegt, in der Einträge aufgenommen werden können.&lt;br /&gt;
&lt;br /&gt;
===Implementation in Python===&lt;br /&gt;
''HashNode'' ist eine Hilfsdatenstruktur, die Schlüssel und Wert speichert&lt;br /&gt;
und mit Hilfe von ''next'' eine verkettete Liste realisiert&lt;br /&gt;
  class HashNode:&lt;br /&gt;
      def __init__(self,key,data,next):&lt;br /&gt;
          self.key = key&lt;br /&gt;
          self.data = data&lt;br /&gt;
          self.next = next # Verkettung!&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Die eigentliche Hashtabelle wird in der Klasse ''HashTable'' implementiert:&lt;br /&gt;
  class HashTable:&lt;br /&gt;
      def __init__(self):&lt;br /&gt;
         self.capacity = ... # Geeignete Werte siehe unten&lt;br /&gt;
         self.size = 0&lt;br /&gt;
         self.array = [None]*self.capacity&lt;br /&gt;
&lt;br /&gt;
In Python ([http://docs.python.org/ref/sequence-types.html Python Docs zum Thema]) wird der Zugriffsoperator ''[ ]'' für eine Datenstruktur wie folgt (innerhalb einer Klasse) implementiert:&lt;br /&gt;
  def __setitem__(self, key, value)&lt;br /&gt;
&lt;br /&gt;
so dass im Programmtext dann folgende Syntax möglich ist: &amp;lt;tt&amp;gt;a[key] = value&amp;lt;/tt&amp;gt; (schreibender Zugriff auf &amp;lt;tt&amp;gt;a[key]&amp;lt;/tt&amp;gt;).&lt;br /&gt;
Analog wird der lesende Zugriff &amp;lt;tt&amp;gt;value = a[key]&amp;lt;/tt&amp;gt; wie folgt umgesetzt:&lt;br /&gt;
  def __getitem__(self, key, value)&lt;br /&gt;
&lt;br /&gt;
Implementierung der &amp;lt;tt&amp;gt;__setitem__&amp;lt;/tt&amp;gt;-Funktion in der &amp;lt;tt&amp;gt;HashTable&amp;lt;/tt&amp;gt;-Klasse:&lt;br /&gt;
  def __setitem__(self, key, value):&lt;br /&gt;
      index = hash(key) % self.capacity&lt;br /&gt;
      node = self.array[index]&lt;br /&gt;
      while node is not None:&lt;br /&gt;
          if node.key == key:&lt;br /&gt;
              # Element key ist schon in der Tabelle&lt;br /&gt;
              #Überschreibe die Daten mit dem neuen Wert&lt;br /&gt;
              node.data = value&lt;br /&gt;
              return&lt;br /&gt;
          # Kollision des Hashwerts, probiere nächsten Key aus&lt;br /&gt;
          node = node.next&lt;br /&gt;
      # Kein Element hatte den richtigen Schlüssel.&lt;br /&gt;
      # ==&amp;gt;Es gibt diesen Schlüssel noch nicht&lt;br /&gt;
      # Füge also ein neues Element in die Hashtabelle ein&lt;br /&gt;
       &lt;br /&gt;
      self.array[index] = HashNode(key, value, self.array[index])&lt;br /&gt;
      # Der alte Anfang der Liste wurde der Nachfolger des neu eingefügten&lt;br /&gt;
      # ersten Elements&lt;br /&gt;
       &lt;br /&gt;
      self.size += 1&lt;br /&gt;
&lt;br /&gt;
Und die Implementierung der &amp;lt;tt&amp;gt;__getitem__&amp;lt;/tt&amp;gt; Funktionen:&lt;br /&gt;
  def __getitem__(self, key):&lt;br /&gt;
      index = hash(key) % self.capacity&lt;br /&gt;
      node = self.array[index]&lt;br /&gt;
      while node is not None:&lt;br /&gt;
           if node.key == key: # Gefunden!&lt;br /&gt;
               return node.data&lt;br /&gt;
           node = node.next&lt;br /&gt;
      raise KeyError(key)&lt;br /&gt;
&lt;br /&gt;
==== Wahl der Kapazität ====&lt;br /&gt;
In der C++ Standardbibliothek (Klasse &amp;lt;tt&amp;gt; [http://www.sgi.com/tech/stl/hash_map.htmlstd::hash_map std::hash_map]&amp;lt;/tt&amp;gt;) wird die Hashtabelle häufig mit Hilfe der linearen Verkettung&lt;br /&gt;
imlementiert. Dabei wird &amp;lt;tt&amp;gt;capacity&amp;lt;/tt&amp;gt; immer als ''Primzahl'' gewählt, wobei sich aufeinanderfolgende Kapazitäten immer ungefähr verdoppeln:&lt;br /&gt;
  53, 97, 193, 398, 769, ...&lt;br /&gt;
[http://gcc.gnu.org/viewcvs/*checkout*/trunk/libstdc++-v3/src/hashtable.cc GCC hashtable.cc (Primzahlen)] [http://gcc.gnu.org/viewcvs/*checkout*/trunk/libstdc++-v3/include/tr1_impl/hashtable_policy.h GCC Hash Implementation]&lt;br /&gt;
&lt;br /&gt;
Das hat zur Folge, dass &amp;lt;tt&amp;gt;hash(key) % self.capacity&amp;lt;/tt&amp;gt; ''alle'' Bits von h benutzt (Eigenschaft aus der Zahlentheorie). Die Kapizität wird vergrößert, wenn &amp;lt;tt&amp;gt;size == capacity&amp;lt;/tt&amp;gt; erreicht wird. Analog zum dynamischen Array werden die Daten dann aus dem alten Array (&amp;lt;tt&amp;gt;self.array&amp;lt;/tt&amp;gt;) in ein entsprechend vergrößertes neues Array kopiert.&lt;br /&gt;
&lt;br /&gt;
== Hashtabelle mit offener Adressierung (offenes Hashing) ==&lt;br /&gt;
[http://de.wikipedia.org/wiki/Hashtabelle#Hashing_mit_offener_Adressierung Wikipedia (de)]&lt;br /&gt;
[http://en.wikipedia.org/wiki/Open_addressing Wikipedia (en)]&lt;br /&gt;
&lt;br /&gt;
Optimistischer Ansatz: Kollisionen werden nicht so häufig auftreten.&lt;br /&gt;
&lt;br /&gt;
=== Idee ===&lt;br /&gt;
Wenn &amp;lt;tt&amp;gt;array[index]&amp;lt;/tt&amp;gt; durch Kollision bereits vergeben ist, probiere einen&lt;br /&gt;
anderen Index aus.&lt;br /&gt;
&lt;br /&gt;
* Das Array enthält pro Element höchstens ein (key,value)-Paar&lt;br /&gt;
* Das Array muss stets mindestens ''einen'' freien Platz haben (sonst gäbe es beim Ausprobieren anderer Indizes eine Endlosschleife). Es gilt immer &amp;lt;tt&amp;gt;self.size &amp;lt; self.capacity&amp;lt;/tt&amp;gt;. Dies war bei der vorigen Hash-Implementation mit linearer Verkettung nicht notwendig (aber im Sinne schneller zugriffszeiten trotzdem wünschenswert).&lt;br /&gt;
&lt;br /&gt;
=== Vorgehen bei Kollisionen ===&lt;br /&gt;
&lt;br /&gt;
==== Sequentielles Sondieren====&lt;br /&gt;
Probiere den nächsten Index: &amp;lt;tt&amp;gt;index = (index+1) % capacity&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Vorteil: einfach&lt;br /&gt;
* Nachteil: Clusterbildung&lt;br /&gt;
&lt;br /&gt;
Clusterbildung heißt, dass sich größere zusammenhängende Bereiche bilden die belegt sind, unterbrochen von Bereichen die komplett frei sind. Beim Versuche des Einfügens eines Elements an einen Platz, der schon belegt ist, muss jetzt das ganze Cluster sequentiell durchlaufen werden, bis ein freier Platz gefunden wird. Damit entspricht die Komplexität der Suche der mittleren Länge der belegten Bereiche, was sich entsprechend in einer langsamen Suche widerspiegelt.&lt;br /&gt;
&lt;br /&gt;
==== Doppeltes Hashing ====&lt;br /&gt;
[http://de.wikipedia.org/wiki/Doppel-Hashing Wikipedia (de)] [http://en.wikipedia.org/wiki/Double_hashing Wikipedia (en)]&lt;br /&gt;
&lt;br /&gt;
Bestimme einen neuen Index (bei Kollisionen) durch eine ''2. Hashfunktion''.&lt;br /&gt;
&lt;br /&gt;
Das doppelte Hashing wird typischerweise in der Praxis angewendet und liegt auch der Python Implementierung des Datentyps [http://docs.python.org/tut/node7.html#SECTION007500000000000000000 Dictionary] (Syntax &amp;lt;tt&amp;gt;{'a':1, 'b':2, 'c':3}&amp;lt;/tt&amp;gt; zugrunde.&lt;br /&gt;
&lt;br /&gt;
Eine effiziente Implementierung dieses Datentyps ist für die Performance der Skriptsprache Python extrem wichtig, da z.B. beim Aufruf einer Funktion der auszuführunde Code in einem Dictionary unter dem Schlüssel ''Funktionsname'' nachgeschlagen wird oder die Werte lokaler Variablen innerhalb einer Funktion ebenfalls in einem Dictionary zu finden sind.&lt;br /&gt;
&lt;br /&gt;
Für die Implementierung in Python werden wieder die obigen Klassen &amp;lt;tt&amp;gt;HashNode&amp;lt;/tt&amp;gt; (das Attribut &amp;lt;tt&amp;gt;next&amp;lt;/tt&amp;gt; kann allerdings jetzt entfernt werden) und &amp;lt;tt&amp;gt;HashTable&amp;lt;/tt&amp;gt; benötigt, es folgen die angepassten Implementationen von &amp;lt;tt&amp;gt;__setitem__&amp;lt;/tt&amp;gt; und &amp;lt;tt&amp;gt;__getitem__&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
  def __setitem__(self, key, value):&lt;br /&gt;
      h = hash(key)&lt;br /&gt;
      index = h % self.capacity&lt;br /&gt;
      while True:&lt;br /&gt;
          if self.array[index] is None or self.array[index].key is None:&lt;br /&gt;
               # das Feld ist frei (1. Abfrage)&lt;br /&gt;
               # oder das Feld ist als frei markiert (2. Abfrage)&lt;br /&gt;
               self.array[index] = HashNode(key, value)&lt;br /&gt;
               self.size +=1&lt;br /&gt;
               return&lt;br /&gt;
          if self.array[index].key == key:&lt;br /&gt;
               # Es gibt diesen Schlüssel schon,&lt;br /&gt;
               # überschreibe die Daten&lt;br /&gt;
               self.array[index].data = value&lt;br /&gt;
               return&lt;br /&gt;
          # Letzter Fall: Kollision =&amp;gt; neuer Index durch 2. Hashfunktion&lt;br /&gt;
          index = (5*index+1+h) % self.capacity&lt;br /&gt;
          h = h &amp;gt;&amp;gt; 5&lt;br /&gt;
(für den &amp;lt;tt&amp;gt;&amp;gt;&amp;gt;&amp;lt;/tt&amp;gt;-Operator, siehe die [http://docs.python.org/ref/shifting.html Python Dokumentation])&lt;br /&gt;
&lt;br /&gt;
Die vorgestellte Implementierung orientiert sich an Pythons interner Dictionary Implementierung, der zugehörige Quelltext (mit ausführlichem Kommentar) findet sich unter [http://svn.python.org/view/*checkout*/python/trunk/Objects/dictobject.c dictobject.c Python Implementation (SVN)]&lt;br /&gt;
&lt;br /&gt;
===== Beispiel =====&lt;br /&gt;
Mit Zahlen &amp;lt;math&amp;gt;2^5&amp;lt;/math&amp;gt; statt &amp;lt;math&amp;gt;2^{32}&amp;lt;/math&amp;gt;.&lt;br /&gt;
  h=25, capacity=8&lt;br /&gt;
  i_0 = 25%8 = 1&lt;br /&gt;
  Es finde eine Kollision statt.&lt;br /&gt;
  i_1 = (5*1+h)%8 = 31%8 = 7&lt;br /&gt;
  h = h&amp;gt;&amp;gt;2 &amp;lt;==&amp;gt; h = (0b11001)&amp;gt;&amp;gt;2 = 0b00110 = 6&lt;br /&gt;
  Es finde eine Kollision statt.&lt;br /&gt;
  i_2 = (5*7+1+h)%8  =42%8 = 2&lt;br /&gt;
  h = h&amp;gt;&amp;gt;2 &amp;lt;==&amp;gt; h=1&lt;br /&gt;
  Es finde eine Kollision statt.&lt;br /&gt;
  i_3 = (5*2+1+h)%8 = 12%8 = 4&lt;br /&gt;
  h = h&amp;gt;&amp;gt;2 &amp;lt;==&amp;gt; h=0&lt;br /&gt;
  Es finde eine Kollision statt.&lt;br /&gt;
  i_4 = (5*4+1+0)%8 = 5&lt;br /&gt;
  i_5 = (5*5+1)%8 = 2&lt;br /&gt;
  i_6 = (5*2+1)%8 = 3&lt;br /&gt;
   ...&lt;br /&gt;
Allen Indizes werden erreicht bevor sich die Folge wiederholt.&lt;br /&gt;
&lt;br /&gt;
===== Komplexität des offenen Hashings =====&lt;br /&gt;
&lt;br /&gt;
* Annahme: uniformes Hashing, das heißt alle Indizes haben gleiche Wahrscheinlichkeit&lt;br /&gt;
* Füllstand &amp;lt;math&amp;gt;\alpha = \frac{\text{size}}{\text{capacity}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* '''Erfolglose Suche''' (d.h. es wird entweder ein neues Element eingefügt oder ein &amp;lt;tt&amp;gt;KeyError&amp;lt;/tt&amp;gt; geworfen): Untere Schranke für die Komplexität ist &amp;lt;math&amp;gt;\Omega\left(\frac{1}{1-\alpha}\right)&amp;lt;/math&amp;gt; Schritte (= Anzahl der notwendigen index-Berechnungen).&lt;br /&gt;
* '''Erfolgreiche Suche''' &amp;lt;math&amp;gt;\Omega\left(\frac{1}{\alpha}\ln\left(\frac{1}{1-\alpha}\right)\right)&amp;lt;/math&amp;gt; Schritte.&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;5&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
! &amp;lt;math&amp;gt;\alpha&amp;lt;/math&amp;gt;&lt;br /&gt;
! 0.5&lt;br /&gt;
! 0.9&lt;br /&gt;
|- &lt;br /&gt;
| erfolglos&lt;br /&gt;
| 2.0&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| erfolgreich&lt;br /&gt;
| 1.4&lt;br /&gt;
| 2.6&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===== Wahl der Kapazität =====&lt;br /&gt;
In Python wird &amp;lt;tt&amp;gt;capacity&amp;lt;/tt&amp;gt; Aufgrund der obigen Beobachtung so gewählt, dass &amp;lt;math&amp;gt;\alpha \leq 2/3&amp;lt;/math&amp;gt;. Falls &amp;lt;math&amp;gt;\alpha&amp;lt;/math&amp;gt; größer werden sollte, verdopple die Kapazität und kopiere das alte array in das neue Array (analog zum dynamischen Array)&lt;br /&gt;
&lt;br /&gt;
In Python werden die Kapazitätsgrößen als Zweierpotenzen gewählt, also 4,8,16,32,...,&lt;br /&gt;
so dass &amp;lt;tt&amp;gt;h % self.capacity&amp;lt;/tt&amp;gt; nur die unteren Bits von &amp;lt;tt&amp;gt;h&amp;lt;/tt&amp;gt; benutzt.&lt;br /&gt;
&lt;br /&gt;
== Anwendung von Hashing ==&lt;br /&gt;
&lt;br /&gt;
* Hashtabelle, assoziatives Aray&lt;br /&gt;
* Sortieren in linearer Zeit (Übungsaufgabe 6.2)&lt;br /&gt;
* Suchen von Strings in Texten: Rabin-Karp-Algorithmus&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
=== Rabin Karp Algorithmus ===&lt;br /&gt;
[http://de.wikipedia.org/wiki/Rabin-Karp-Algorithmus Wikipedia (de)] [http://en.wikipedia.org/wiki/Rabin-Karp_string_search_algorithm Wikipedia (en)]&lt;br /&gt;
&lt;br /&gt;
In Textverarbeitungsanwendungen ist eine häufig benutzte Funktion die ''Search &amp;amp; Replace'' Funktionalität. Die Suche sollte in O(len(text)) möglich sein, aber ein naiver Algorithmus braucht O(len(text)*len(searchstring))&lt;br /&gt;
&lt;br /&gt;
==== Naive Implementierung der Suche ====&lt;br /&gt;
  def search(text, s):&lt;br /&gt;
      M, N = len(text), len(s)&lt;br /&gt;
      for k in range(M-N):&lt;br /&gt;
          if s==text[k:k+N]:   # O(N), da N Zeichen verglichen werden müssen&lt;br /&gt;
              return k&lt;br /&gt;
      return -1 #nicht gefunden&lt;br /&gt;
&lt;br /&gt;
==== Idee des Rabin Karp Algorithmus ====&lt;br /&gt;
Statt Vergleichen &amp;lt;tt&amp;gt;s==text[k:k+N]&amp;lt;/tt&amp;gt;, die O(N) benötigen da N Vergleiche der Buchstaben durchgeführt werden müssen, Vergleiche die Hashs von Suchstring und dem zu untersuchenden Textabschnitt: &amp;lt;tt&amp;gt;hash(s) == hash(text[k:k+N])&amp;lt;/tt&amp;gt;. Dabei muss natürlich &amp;lt;tt&amp;gt;hash(s)&amp;lt;/tt&amp;gt; nur einmal berechnet werden, wohingegen &amp;lt;tt&amp;gt;hash(text[k:k+N])&amp;lt;/tt&amp;gt; immer wieder neu berechnet werden muss. Damit der Vergleich O(1) sein kann, ist es deswegen erforderlich, eine solche Hashfunktion zu haben, die nicht alle Zeichen (das wäre O(N) ) einlesen muss, sondern die vorhergehende Hashfunktion mit einbezieht.&lt;br /&gt;
&lt;br /&gt;
Eine solche Hashfunktion heißt ''Running Hash'' und funktioniert analog zum ''Sliding Mean''.&lt;br /&gt;
&lt;br /&gt;
Die Running Hash Funktion berechnet in O(1) den hash von &amp;lt;tt&amp;gt;text[k+1:k+1+N]&amp;lt;/tt&amp;gt; ausgehend vom hash für &amp;lt;tt&amp;gt;text[k:k+N]&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Idee: Interpretiere den Text als Ziffern in einer base d Darstellung:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h_k = \text{text}[k]\cdot d^{N-1} + \text{text}[k]\cdot d^{N-2} + \cdots + \text{text}[k+N-1]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für die Basis 10 (Dezimalsystem) ergibt sich also&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h_k = \text{text}[k]\cdot {10}^{N-1} + \text{text}[k]\cdot {10}^{N-2} + \cdots + \text{text}[k+N-1]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Daraus folgt&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h_{k+1} = 10\cdot h_k - \text{text}[k]\cdot {10}^{N} + \text{text}[k+N]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Komplexität dieses Updates ist O(1), falls man &amp;lt;math&amp;gt;{10}^{N}&amp;lt;/math&amp;gt; vorberechnet hat.&lt;br /&gt;
&lt;br /&gt;
In der Realität wählt man dann d=32 und benutzt noch an einigen Stellen modulo Operationen, um die Zahlen nicht zu groß werden zu lassen.&lt;br /&gt;
&lt;br /&gt;
==== Implementation ====&lt;br /&gt;
  def searchRabinKarp(text, s):&lt;br /&gt;
      ht, hs, dN = 0, 0, 1&lt;br /&gt;
      M, N = len(text), len(s)&lt;br /&gt;
      d, q = 32, 33554393&lt;br /&gt;
      #q ist eine große Primzahl, aber so,&lt;br /&gt;
      #dass d*q &amp;lt; 2**32 (um Überlauf zu vermeiden)&lt;br /&gt;
      &lt;br /&gt;
      #Initialisierung      &lt;br /&gt;
      for k in range(N):&lt;br /&gt;
          ht = (ht*d + ord(text[k])) % q&lt;br /&gt;
          #ord() gibt die ASCIInummer des übergebenen Zeichens zurück&lt;br /&gt;
          ds = (hs*d + ord( s[k] )) % q&lt;br /&gt;
          dN = (dN*a) % q&lt;br /&gt;
      #Die Variablen sind jetzt wie folgt initialisiert:&lt;br /&gt;
      #ht = hash(text[0:N])&lt;br /&gt;
      #hs = hash(s)&lt;br /&gt;
      #dN = (d**N) % q&lt;br /&gt;
      &lt;br /&gt;
      #Hauptschleife&lt;br /&gt;
      k = 0 &lt;br /&gt;
      while k &amp;lt; M-N:&lt;br /&gt;
          if hs == ht and s==text[k:k+N]:&lt;br /&gt;
              return k # serch string an Position k gefunden&lt;br /&gt;
          if k+N &amp;lt; M:&lt;br /&gt;
              ht = (d*ht - dN * ord(text[k]) + dN*q + ord(text[k+N]) ) % q&lt;br /&gt;
          k +=1&lt;br /&gt;
      return -1  # search string nicht gefunden&lt;/div&gt;</summary>
		<author><name>Thorben</name></author>	</entry>

	<entry>
		<id>https://alda.iwr.uni-heidelberg.de/index.php?title=File:HASHTB32.svg.png&amp;diff=1738</id>
		<title>File:HASHTB32.svg.png</title>
		<link rel="alternate" type="text/html" href="https://alda.iwr.uni-heidelberg.de/index.php?title=File:HASHTB32.svg.png&amp;diff=1738"/>
				<updated>2008-06-10T22:56:03Z</updated>
		
		<summary type="html">&lt;p&gt;Thorben: from Wikipedia: http://en.wikipedia.org/wiki/Hash_table&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;from Wikipedia: http://en.wikipedia.org/wiki/Hash_table&lt;/div&gt;</summary>
		<author><name>Thorben</name></author>	</entry>

	<entry>
		<id>https://alda.iwr.uni-heidelberg.de/index.php?title=Hashing_und_assoziative_Arrays&amp;diff=1737</id>
		<title>Hashing und assoziative Arrays</title>
		<link rel="alternate" type="text/html" href="https://alda.iwr.uni-heidelberg.de/index.php?title=Hashing_und_assoziative_Arrays&amp;diff=1737"/>
				<updated>2008-06-10T22:47:27Z</updated>
		
		<summary type="html">&lt;p&gt;Thorben: /* Doppeltes Hashing */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Mitschrift gibts [http://hci.iwr.uni-heidelberg.de/alda/images/AlDa.pdf hier] als PDF und [http://hci.iwr.uni-heidelberg.de/alda/images/Alda_source.pdf hier] gibts die TeX-Sourcen, leider als PDF weil man wohl keine .TeXs hochladen darf. Originale gibts auf Anfrage bei kirchner at cl dot uni minus heidelberg dot de. Wird das Package &amp;quot;listings&amp;quot; verwendet, das gibts bei [http://tug.ctan.org/tex-archive/macros/latex/contrib/listings/ http://tug.ctan.org/tex-archive/macros/latex/contrib/listings/] &lt;br /&gt;
&lt;br /&gt;
Tipp- und sonstige Fehler dürfen gerne verbessert und erneut hochgeladen werden, oder gebt mir per Email Bescheid, dann pflege ich die   Korrektur ein :)&lt;br /&gt;
&lt;br /&gt;
Ich Finde dein Aufschrieb sollte ins Wiki übetragen werden, das bietet auch alles, was   &lt;br /&gt;
du mit Latex machen kannst. Die Bäume kannst du z.B. mit Latex zeichnen, einen pro Seite und diese dann in eine png Datei umwandeln. Wie sowas geht kann man z.B. in den Quellen von doxygen oder mediawiki selbst nachlesen. Oder man zoomt rein und macht einen Screenshot :-)&lt;br /&gt;
&lt;br /&gt;
== Hashtabelle mit linearer Verkettung ==&lt;br /&gt;
Pessimistischer Ansatz: Kollisionen treten häufig auf, deshalb wird unter jedem&lt;br /&gt;
Hashindex gleich eine Liste angelegt, in der Einträge aufgenommen werden können.&lt;br /&gt;
&lt;br /&gt;
===Implementation in Python===&lt;br /&gt;
''HashNode'' ist eine Hilfsdatenstruktur, die Schlüssel und Wert speichert&lt;br /&gt;
und mit Hilfe von ''next'' eine verkettete Liste realisiert&lt;br /&gt;
  class HashNode:&lt;br /&gt;
      def __init__(self,key,data,next):&lt;br /&gt;
          self.key = key&lt;br /&gt;
          self.data = data&lt;br /&gt;
          self.next = next # Verkettung!&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Die eigentliche Hashtabelle wird in der Klasse ''HashTable'' implementiert:&lt;br /&gt;
  class HashTable:&lt;br /&gt;
      def __init__(self):&lt;br /&gt;
         self.capacity = ... # Geeignete Werte siehe unten&lt;br /&gt;
         self.size = 0&lt;br /&gt;
         self.array = [None]*self.capacity&lt;br /&gt;
&lt;br /&gt;
In Python ([http://docs.python.org/ref/sequence-types.html Python Docs zum Thema]) wird der Zugriffsoperator ''[ ]'' für eine Datenstruktur wie folgt (innerhalb einer Klasse) implementiert:&lt;br /&gt;
  def __setitem__(self, key, value)&lt;br /&gt;
&lt;br /&gt;
so dass im Programmtext dann folgende Syntax möglich ist: &amp;lt;tt&amp;gt;a[key] = value&amp;lt;/tt&amp;gt; (schreibender Zugriff auf &amp;lt;tt&amp;gt;a[key]&amp;lt;/tt&amp;gt;).&lt;br /&gt;
Analog wird der lesende Zugriff &amp;lt;tt&amp;gt;value = a[key]&amp;lt;/tt&amp;gt; wie folgt umgesetzt:&lt;br /&gt;
  def __getitem__(self, key, value)&lt;br /&gt;
&lt;br /&gt;
Implementierung der &amp;lt;tt&amp;gt;__setitem__&amp;lt;/tt&amp;gt;-Funktion in der &amp;lt;tt&amp;gt;HashTable&amp;lt;/tt&amp;gt;-Klasse:&lt;br /&gt;
  def __setitem__(self, key, value):&lt;br /&gt;
      index = hash(key) % self.capacity&lt;br /&gt;
      node = self.array[index]&lt;br /&gt;
      while node is not None:&lt;br /&gt;
          if node.key == key:&lt;br /&gt;
              # Element key ist schon in der Tabelle&lt;br /&gt;
              #Überschreibe die Daten mit dem neuen Wert&lt;br /&gt;
              node.data = value&lt;br /&gt;
              return&lt;br /&gt;
          # Kollision des Hashwerts, probiere nächsten Key aus&lt;br /&gt;
          node = node.next&lt;br /&gt;
      # Kein Element hatte den richtigen Schlüssel.&lt;br /&gt;
      # ==&amp;gt;Es gibt diesen Schlüssel noch nicht&lt;br /&gt;
      # Füge also ein neues Element in die Hashtabelle ein&lt;br /&gt;
       &lt;br /&gt;
      self.array[index] = HashNode(key, value, self.array[index])&lt;br /&gt;
      # Der alte Anfang der Liste wurde der Nachfolger des neu eingefügten&lt;br /&gt;
      # ersten Elements&lt;br /&gt;
       &lt;br /&gt;
      self.size += 1&lt;br /&gt;
&lt;br /&gt;
Und die Implementierung der &amp;lt;tt&amp;gt;__getitem__&amp;lt;/tt&amp;gt; Funktionen:&lt;br /&gt;
  def __getitem__(self, key):&lt;br /&gt;
      index = hash(key) % self.capacity&lt;br /&gt;
      node = self.array[index]&lt;br /&gt;
      while node is not None:&lt;br /&gt;
           if node.key == key: # Gefunden!&lt;br /&gt;
               return node.data&lt;br /&gt;
           node = node.next&lt;br /&gt;
      raise KeyError(key)&lt;br /&gt;
&lt;br /&gt;
==== Wahl der Kapazität ====&lt;br /&gt;
In der C++ Standardbibliothek (Klasse &amp;lt;tt&amp;gt; [http://www.sgi.com/tech/stl/hash_map.htmlstd::hash_map std::hash_map]&amp;lt;/tt&amp;gt;) wird die Hashtabelle häufig mit Hilfe der linearen Verkettung&lt;br /&gt;
imlementiert. Dabei wird &amp;lt;tt&amp;gt;capacity&amp;lt;/tt&amp;gt; immer als ''Primzahl'' gewählt, wobei sich aufeinanderfolgende Kapazitäten immer ungefähr verdoppeln:&lt;br /&gt;
  53, 97, 193, 398, 769, ...&lt;br /&gt;
[http://gcc.gnu.org/viewcvs/*checkout*/trunk/libstdc++-v3/src/hashtable.cc GCC hashtable.cc (Primzahlen)] [http://gcc.gnu.org/viewcvs/*checkout*/trunk/libstdc++-v3/include/tr1_impl/hashtable_policy.h GCC Hash Implementation]&lt;br /&gt;
&lt;br /&gt;
Das hat zur Folge, dass &amp;lt;tt&amp;gt;hash(key) % self.capacity&amp;lt;/tt&amp;gt; ''alle'' Bits von h benutzt (Eigenschaft aus der Zahlentheorie). Die Kapizität wird vergrößert, wenn &amp;lt;tt&amp;gt;size == capacity&amp;lt;/tt&amp;gt; erreicht wird. Analog zum dynamischen Array werden die Daten dann aus dem alten Array (&amp;lt;tt&amp;gt;self.array&amp;lt;/tt&amp;gt;) in ein entsprechend vergrößertes neues Array kopiert.&lt;br /&gt;
&lt;br /&gt;
== Hashtabelle mit offener Adressierung (offenes Hashing) ==&lt;br /&gt;
[http://de.wikipedia.org/wiki/Hashtabelle#Hashing_mit_offener_Adressierung Wikipedia (de)]&lt;br /&gt;
[http://en.wikipedia.org/wiki/Open_addressing Wikipedia (en)]&lt;br /&gt;
&lt;br /&gt;
Optimistischer Ansatz: Kollisionen werden nicht so häufig auftreten.&lt;br /&gt;
&lt;br /&gt;
=== Idee ===&lt;br /&gt;
Wenn &amp;lt;tt&amp;gt;array[index]&amp;lt;/tt&amp;gt; durch Kollision bereits vergeben ist, probiere einen&lt;br /&gt;
anderen Index aus.&lt;br /&gt;
&lt;br /&gt;
* Das Array enthält pro Element höchstens ein (key,value)-Paar&lt;br /&gt;
* Das Array muss stets mindestens ''einen'' freien Platz haben (sonst gäbe es beim Ausprobieren anderer Indizes eine Endlosschleife). Es gilt immer &amp;lt;tt&amp;gt;self.size &amp;lt; self.capacity&amp;lt;/tt&amp;gt;. Dies war bei der vorigen Hash-Implementation mit linearer Verkettung nicht notwendig (aber im Sinne schneller zugriffszeiten trotzdem wünschenswert).&lt;br /&gt;
&lt;br /&gt;
=== Vorgehen bei Kollisionen ===&lt;br /&gt;
&lt;br /&gt;
==== Sequentielles Sondieren====&lt;br /&gt;
Probiere den nächsten Index: &amp;lt;tt&amp;gt;index = (index+1) % capacity&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Vorteil: einfach&lt;br /&gt;
* Nachteil: Clusterbildung&lt;br /&gt;
&lt;br /&gt;
Clusterbildung heißt, dass sich größere zusammenhängende Bereiche bilden die belegt sind, unterbrochen von Bereichen die komplett frei sind. Beim Versuche des Einfügens eines Elements an einen Platz, der schon belegt ist, muss jetzt das ganze Cluster sequentiell durchlaufen werden, bis ein freier Platz gefunden wird. Damit entspricht die Komplexität der Suche der mittleren Länge der belegten Bereiche, was sich entsprechend in einer langsamen Suche widerspiegelt.&lt;br /&gt;
&lt;br /&gt;
==== Doppeltes Hashing ====&lt;br /&gt;
[http://de.wikipedia.org/wiki/Doppel-Hashing Wikipedia (de)] [http://en.wikipedia.org/wiki/Double_hashing Wikipedia (en)]&lt;br /&gt;
&lt;br /&gt;
Bestimme einen neuen Index (bei Kollisionen) durch eine ''2. Hashfunktion''.&lt;br /&gt;
&lt;br /&gt;
Das doppelte Hashing wird typischerweise in der Praxis angewendet und liegt auch der Python Implementierung des Datentyps [http://docs.python.org/tut/node7.html#SECTION007500000000000000000 Dictionary] (Syntax &amp;lt;tt&amp;gt;{'a':1, 'b':2, 'c':3}&amp;lt;/tt&amp;gt; zugrunde.&lt;br /&gt;
&lt;br /&gt;
Eine effiziente Implementierung dieses Datentyps ist für die Performance der Skriptsprache Python extrem wichtig, da z.B. beim Aufruf einer Funktion der auszuführunde Code in einem Dictionary unter dem Schlüssel ''Funktionsname'' nachgeschlagen wird oder die Werte lokaler Variablen innerhalb einer Funktion ebenfalls in einem Dictionary zu finden sind.&lt;br /&gt;
&lt;br /&gt;
Für die Implementierung in Python werden wieder die obigen Klassen &amp;lt;tt&amp;gt;HashNode&amp;lt;/tt&amp;gt; (das Attribut &amp;lt;tt&amp;gt;next&amp;lt;/tt&amp;gt; kann allerdings jetzt entfernt werden) und &amp;lt;tt&amp;gt;HashTable&amp;lt;/tt&amp;gt; benötigt, es folgen die angepassten Implementationen von &amp;lt;tt&amp;gt;__setitem__&amp;lt;/tt&amp;gt; und &amp;lt;tt&amp;gt;__getitem__&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
  def __setitem__(self, key, value):&lt;br /&gt;
      h = hash(key)&lt;br /&gt;
      index = h % self.capacity&lt;br /&gt;
      while True:&lt;br /&gt;
          if self.array[index] is None or self.array[index].key is None:&lt;br /&gt;
               # das Feld ist frei (1. Abfrage)&lt;br /&gt;
               # oder das Feld ist als frei markiert (2. Abfrage)&lt;br /&gt;
               self.array[index] = HashNode(key, value)&lt;br /&gt;
               self.size +=1&lt;br /&gt;
               return&lt;br /&gt;
          if self.array[index].key == key:&lt;br /&gt;
               # Es gibt diesen Schlüssel schon,&lt;br /&gt;
               # überschreibe die Daten&lt;br /&gt;
               self.array[index].data = value&lt;br /&gt;
               return&lt;br /&gt;
          # Letzter Fall: Kollision =&amp;gt; neuer Index durch 2. Hashfunktion&lt;br /&gt;
          index = (5*index+1+h) % self.capacity&lt;br /&gt;
          h = h &amp;gt;&amp;gt; 5&lt;br /&gt;
(für den &amp;lt;tt&amp;gt;&amp;gt;&amp;gt;&amp;lt;/tt&amp;gt;-Operator, siehe die [http://docs.python.org/ref/shifting.html Python Dokumentation])&lt;br /&gt;
&lt;br /&gt;
Die vorgestellte Implementierung orientiert sich an Pythons interner Dictionary Implementierung, der zugehörige Quelltext (mit ausführlichem Kommentar) findet sich unter [http://svn.python.org/view/*checkout*/python/trunk/Objects/dictobject.c dictobject.c Python Implementation (SVN)]&lt;br /&gt;
&lt;br /&gt;
===== Beispiel =====&lt;br /&gt;
Mit Zahlen &amp;lt;math&amp;gt;2^5&amp;lt;/math&amp;gt; statt &amp;lt;math&amp;gt;2^{32}&amp;lt;/math&amp;gt;.&lt;br /&gt;
  h=25, capacity=8&lt;br /&gt;
  i_0 = 25%8 = 1&lt;br /&gt;
  Es finde eine Kollision statt.&lt;br /&gt;
  i_1 = (5*1+h)%8 = 31%8 = 7&lt;br /&gt;
  h = h&amp;gt;&amp;gt;2 &amp;lt;==&amp;gt; h = (0b11001)&amp;gt;&amp;gt;2 = 0b00110 = 6&lt;br /&gt;
  Es finde eine Kollision statt.&lt;br /&gt;
  i_2 = (5*7+1+h)%8  =42%8 = 2&lt;br /&gt;
  h = h&amp;gt;&amp;gt;2 &amp;lt;==&amp;gt; h=1&lt;br /&gt;
  Es finde eine Kollision statt.&lt;br /&gt;
  i_3 = (5*2+1+h)%8 = 12%8 = 4&lt;br /&gt;
  h = h&amp;gt;&amp;gt;2 &amp;lt;==&amp;gt; h=0&lt;br /&gt;
  Es finde eine Kollision statt.&lt;br /&gt;
  i_4 = (5*4+1+0)%8 = 5&lt;br /&gt;
  i_5 = (5*5+1)%8 = 2&lt;br /&gt;
  i_6 = (5*2+1)%8 = 3&lt;br /&gt;
   ...&lt;br /&gt;
Allen Indizes werden erreicht bevor sich die Folge wiederholt.&lt;br /&gt;
&lt;br /&gt;
===== Komplexität des offenen Hashings =====&lt;br /&gt;
&lt;br /&gt;
* Annahme: uniformes Hashing, das heißt alle Indizes haben gleiche Wahrscheinlichkeit&lt;br /&gt;
* Füllstand &amp;lt;math&amp;gt;\alpha = \frac{\text{size}}{\text{capacity}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* '''Erfolglose Suche''' (d.h. es wird entweder ein neues Element eingefügt oder ein &amp;lt;tt&amp;gt;KeyError&amp;lt;/tt&amp;gt; geworfen): Untere Schranke für die Komplexität ist &amp;lt;math&amp;gt;\Omega\left(\frac{1}{1-\alpha}\right)&amp;lt;/math&amp;gt; Schritte (= Anzahl der notwendigen index-Berechnungen).&lt;br /&gt;
* '''Erfolgreiche Suche''' &amp;lt;math&amp;gt;\Omega\left(\frac{1}{\alpha}\ln\left(\frac{1}{1-\alpha}\right)\right)&amp;lt;/math&amp;gt; Schritte.&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;5&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
! &amp;lt;math&amp;gt;\alpha&amp;lt;/math&amp;gt;&lt;br /&gt;
! 0.5&lt;br /&gt;
! 0.9&lt;br /&gt;
|- &lt;br /&gt;
| erfolglos&lt;br /&gt;
| 2.0&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| erfolgreich&lt;br /&gt;
| 1.4&lt;br /&gt;
| 2.6&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===== Wahl der Kapazität =====&lt;br /&gt;
In Python wird &amp;lt;tt&amp;gt;capacity&amp;lt;/tt&amp;gt; Aufgrund der obigen Beobachtung so gewählt, dass &amp;lt;math&amp;gt;\alpha \leq 2/3&amp;lt;/math&amp;gt;. Falls &amp;lt;math&amp;gt;\alpha&amp;lt;/math&amp;gt; größer werden sollte, verdopple die Kapazität und kopiere das alte array in das neue Array (analog zum dynamischen Array)&lt;br /&gt;
&lt;br /&gt;
In Python werden die Kapazitätsgrößen als Zweierpotenzen gewählt, also 4,8,16,32,...,&lt;br /&gt;
so dass &amp;lt;tt&amp;gt;h % self.capacity&amp;lt;/tt&amp;gt; nur die unteren Bits von &amp;lt;tt&amp;gt;h&amp;lt;/tt&amp;gt; benutzt.&lt;br /&gt;
&lt;br /&gt;
== Anwendung von Hashing ==&lt;br /&gt;
&lt;br /&gt;
* Hashtabelle, assoziatives Aray&lt;br /&gt;
* Sortieren in linearer Zeit (Übungsaufgabe 6.2)&lt;br /&gt;
* Suchen von Strings in Texten: Rabin-Karp-Algorithmus&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
=== Rabin Karp Algorithmus ===&lt;br /&gt;
[http://de.wikipedia.org/wiki/Rabin-Karp-Algorithmus Wikipedia (de)] [http://en.wikipedia.org/wiki/Rabin-Karp_string_search_algorithm Wikipedia (en)]&lt;br /&gt;
&lt;br /&gt;
In Textverarbeitungsanwendungen ist eine häufig benutzte Funktion die ''Search &amp;amp; Replace'' Funktionalität. Die Suche sollte in O(len(text)) möglich sein, aber ein naiver Algorithmus braucht O(len(text)*len(searchstring))&lt;br /&gt;
&lt;br /&gt;
==== Naive Implementierung der Suche ====&lt;br /&gt;
  def search(text, s):&lt;br /&gt;
      M, N = len(text), len(s)&lt;br /&gt;
      for k in range(M-N):&lt;br /&gt;
          if s==text[k:k+N]:   # O(N), da N Zeichen verglichen werden müssen&lt;br /&gt;
              return k&lt;br /&gt;
      return -1 #nicht gefunden&lt;br /&gt;
&lt;br /&gt;
==== Idee des Rabin Karp Algorithmus ====&lt;br /&gt;
Statt Vergleichen &amp;lt;tt&amp;gt;s==text[k:k+N]&amp;lt;/tt&amp;gt;, die O(N) benötigen da N Vergleiche der Buchstaben durchgeführt werden müssen, Vergleiche die Hashs von Suchstring und dem zu untersuchenden Textabschnitt: &amp;lt;tt&amp;gt;hash(s) == hash(text[k:k+N])&amp;lt;/tt&amp;gt;. Dabei muss natürlich &amp;lt;tt&amp;gt;hash(s)&amp;lt;/tt&amp;gt; nur einmal berechnet werden, wohingegen &amp;lt;tt&amp;gt;hash(text[k:k+N])&amp;lt;/tt&amp;gt; immer wieder neu berechnet werden muss. Damit der Vergleich O(1) sein kann, ist es deswegen erforderlich, eine solche Hashfunktion zu haben, die nicht alle Zeichen (das wäre O(N) ) einlesen muss, sondern die vorhergehende Hashfunktion mit einbezieht.&lt;br /&gt;
&lt;br /&gt;
Eine solche Hashfunktion heißt ''Running Hash'' und funktioniert analog zum ''Sliding Mean''.&lt;br /&gt;
&lt;br /&gt;
Die Running Hash Funktion berechnet in O(1) den hash von &amp;lt;tt&amp;gt;text[k+1:k+1+N]&amp;lt;/tt&amp;gt; ausgehend vom hash für &amp;lt;tt&amp;gt;text[k:k+N]&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Idee: Interpretiere den Text als Ziffern in einer base d Darstellung:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h_k = \text{text}[k]\cdot d^{N-1} + \text{text}[k]\cdot d^{N-2} + \cdots + \text{text}[k+N-1]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für die Basis 10 (Dezimalsystem) ergibt sich also&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h_k = \text{text}[k]\cdot {10}^{N-1} + \text{text}[k]\cdot {10}^{N-2} + \cdots + \text{text}[k+N-1]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Daraus folgt&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h_{k+1} = 10\cdot h_k - \text{text}[k]\cdot {10}^{N} + \text{text}[k+N]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Komplexität dieses Updates ist O(1), falls man &amp;lt;math&amp;gt;{10}^{N}&amp;lt;/math&amp;gt; vorberechnet hat.&lt;br /&gt;
&lt;br /&gt;
In der Realität wählt man dann d=32 und benutzt noch an einigen Stellen modulo Operationen, um die Zahlen nicht zu groß werden zu lassen.&lt;br /&gt;
&lt;br /&gt;
==== Implementation ====&lt;br /&gt;
  def searchRabinKarp(text, s):&lt;br /&gt;
      ht, hs, dN = 0, 0, 1&lt;br /&gt;
      M, N = len(text), len(s)&lt;br /&gt;
      d, q = 32, 33554393&lt;br /&gt;
      #q ist eine große Primzahl, aber so,&lt;br /&gt;
      #dass d*q &amp;lt; 2**32 (um Überlauf zu vermeiden)&lt;br /&gt;
      &lt;br /&gt;
      #Initialisierung      &lt;br /&gt;
      for k in range(N):&lt;br /&gt;
          ht = (ht*d + ord(text[k])) % q&lt;br /&gt;
          #ord() gibt die ASCIInummer des übergebenen Zeichens zurück&lt;br /&gt;
          ds = (hs*d + ord( s[k] )) % q&lt;br /&gt;
          dN = (dN*a) % q&lt;br /&gt;
      #Die Variablen sind jetzt wie folgt initialisiert:&lt;br /&gt;
      #ht = hash(text[0:N])&lt;br /&gt;
      #hs = hash(s)&lt;br /&gt;
      #dN = (d**N) % q&lt;br /&gt;
      &lt;br /&gt;
      #Hauptschleife&lt;br /&gt;
      k = 0 &lt;br /&gt;
      while k &amp;lt; M-N:&lt;br /&gt;
          if hs == ht and s==text[k:k+N]:&lt;br /&gt;
              return k # serch string an Position k gefunden&lt;br /&gt;
          if k+N &amp;lt; M:&lt;br /&gt;
              ht = (d*ht - dN * ord(text[k]) + dN*q + ord(text[k+N]) ) % q&lt;br /&gt;
          k +=1&lt;br /&gt;
      return -1  # search string nicht gefunden&lt;/div&gt;</summary>
		<author><name>Thorben</name></author>	</entry>

	<entry>
		<id>https://alda.iwr.uni-heidelberg.de/index.php?title=Hashing_und_assoziative_Arrays&amp;diff=1736</id>
		<title>Hashing und assoziative Arrays</title>
		<link rel="alternate" type="text/html" href="https://alda.iwr.uni-heidelberg.de/index.php?title=Hashing_und_assoziative_Arrays&amp;diff=1736"/>
				<updated>2008-06-10T22:44:51Z</updated>
		
		<summary type="html">&lt;p&gt;Thorben: /* Doppeltes Hashing */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Mitschrift gibts [http://hci.iwr.uni-heidelberg.de/alda/images/AlDa.pdf hier] als PDF und [http://hci.iwr.uni-heidelberg.de/alda/images/Alda_source.pdf hier] gibts die TeX-Sourcen, leider als PDF weil man wohl keine .TeXs hochladen darf. Originale gibts auf Anfrage bei kirchner at cl dot uni minus heidelberg dot de. Wird das Package &amp;quot;listings&amp;quot; verwendet, das gibts bei [http://tug.ctan.org/tex-archive/macros/latex/contrib/listings/ http://tug.ctan.org/tex-archive/macros/latex/contrib/listings/] &lt;br /&gt;
&lt;br /&gt;
Tipp- und sonstige Fehler dürfen gerne verbessert und erneut hochgeladen werden, oder gebt mir per Email Bescheid, dann pflege ich die   Korrektur ein :)&lt;br /&gt;
&lt;br /&gt;
Ich Finde dein Aufschrieb sollte ins Wiki übetragen werden, das bietet auch alles, was   &lt;br /&gt;
du mit Latex machen kannst. Die Bäume kannst du z.B. mit Latex zeichnen, einen pro Seite und diese dann in eine png Datei umwandeln. Wie sowas geht kann man z.B. in den Quellen von doxygen oder mediawiki selbst nachlesen. Oder man zoomt rein und macht einen Screenshot :-)&lt;br /&gt;
&lt;br /&gt;
== Hashtabelle mit linearer Verkettung ==&lt;br /&gt;
Pessimistischer Ansatz: Kollisionen treten häufig auf, deshalb wird unter jedem&lt;br /&gt;
Hashindex gleich eine Liste angelegt, in der Einträge aufgenommen werden können.&lt;br /&gt;
&lt;br /&gt;
===Implementation in Python===&lt;br /&gt;
''HashNode'' ist eine Hilfsdatenstruktur, die Schlüssel und Wert speichert&lt;br /&gt;
und mit Hilfe von ''next'' eine verkettete Liste realisiert&lt;br /&gt;
  class HashNode:&lt;br /&gt;
      def __init__(self,key,data,next):&lt;br /&gt;
          self.key = key&lt;br /&gt;
          self.data = data&lt;br /&gt;
          self.next = next # Verkettung!&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Die eigentliche Hashtabelle wird in der Klasse ''HashTable'' implementiert:&lt;br /&gt;
  class HashTable:&lt;br /&gt;
      def __init__(self):&lt;br /&gt;
         self.capacity = ... # Geeignete Werte siehe unten&lt;br /&gt;
         self.size = 0&lt;br /&gt;
         self.array = [None]*self.capacity&lt;br /&gt;
&lt;br /&gt;
In Python ([http://docs.python.org/ref/sequence-types.html Python Docs zum Thema]) wird der Zugriffsoperator ''[ ]'' für eine Datenstruktur wie folgt (innerhalb einer Klasse) implementiert:&lt;br /&gt;
  def __setitem__(self, key, value)&lt;br /&gt;
&lt;br /&gt;
so dass im Programmtext dann folgende Syntax möglich ist: &amp;lt;tt&amp;gt;a[key] = value&amp;lt;/tt&amp;gt; (schreibender Zugriff auf &amp;lt;tt&amp;gt;a[key]&amp;lt;/tt&amp;gt;).&lt;br /&gt;
Analog wird der lesende Zugriff &amp;lt;tt&amp;gt;value = a[key]&amp;lt;/tt&amp;gt; wie folgt umgesetzt:&lt;br /&gt;
  def __getitem__(self, key, value)&lt;br /&gt;
&lt;br /&gt;
Implementierung der &amp;lt;tt&amp;gt;__setitem__&amp;lt;/tt&amp;gt;-Funktion in der &amp;lt;tt&amp;gt;HashTable&amp;lt;/tt&amp;gt;-Klasse:&lt;br /&gt;
  def __setitem__(self, key, value):&lt;br /&gt;
      index = hash(key) % self.capacity&lt;br /&gt;
      node = self.array[index]&lt;br /&gt;
      while node is not None:&lt;br /&gt;
          if node.key == key:&lt;br /&gt;
              # Element key ist schon in der Tabelle&lt;br /&gt;
              #Überschreibe die Daten mit dem neuen Wert&lt;br /&gt;
              node.data = value&lt;br /&gt;
              return&lt;br /&gt;
          # Kollision des Hashwerts, probiere nächsten Key aus&lt;br /&gt;
          node = node.next&lt;br /&gt;
      # Kein Element hatte den richtigen Schlüssel.&lt;br /&gt;
      # ==&amp;gt;Es gibt diesen Schlüssel noch nicht&lt;br /&gt;
      # Füge also ein neues Element in die Hashtabelle ein&lt;br /&gt;
       &lt;br /&gt;
      self.array[index] = HashNode(key, value, self.array[index])&lt;br /&gt;
      # Der alte Anfang der Liste wurde der Nachfolger des neu eingefügten&lt;br /&gt;
      # ersten Elements&lt;br /&gt;
       &lt;br /&gt;
      self.size += 1&lt;br /&gt;
&lt;br /&gt;
Und die Implementierung der &amp;lt;tt&amp;gt;__getitem__&amp;lt;/tt&amp;gt; Funktionen:&lt;br /&gt;
  def __getitem__(self, key):&lt;br /&gt;
      index = hash(key) % self.capacity&lt;br /&gt;
      node = self.array[index]&lt;br /&gt;
      while node is not None:&lt;br /&gt;
           if node.key == key: # Gefunden!&lt;br /&gt;
               return node.data&lt;br /&gt;
           node = node.next&lt;br /&gt;
      raise KeyError(key)&lt;br /&gt;
&lt;br /&gt;
==== Wahl der Kapazität ====&lt;br /&gt;
In der C++ Standardbibliothek (Klasse &amp;lt;tt&amp;gt; [http://www.sgi.com/tech/stl/hash_map.htmlstd::hash_map std::hash_map]&amp;lt;/tt&amp;gt;) wird die Hashtabelle häufig mit Hilfe der linearen Verkettung&lt;br /&gt;
imlementiert. Dabei wird &amp;lt;tt&amp;gt;capacity&amp;lt;/tt&amp;gt; immer als ''Primzahl'' gewählt, wobei sich aufeinanderfolgende Kapazitäten immer ungefähr verdoppeln:&lt;br /&gt;
  53, 97, 193, 398, 769, ...&lt;br /&gt;
[http://gcc.gnu.org/viewcvs/*checkout*/trunk/libstdc++-v3/src/hashtable.cc GCC hashtable.cc (Primzahlen)] [http://gcc.gnu.org/viewcvs/*checkout*/trunk/libstdc++-v3/include/tr1_impl/hashtable_policy.h GCC Hash Implementation]&lt;br /&gt;
&lt;br /&gt;
Das hat zur Folge, dass &amp;lt;tt&amp;gt;hash(key) % self.capacity&amp;lt;/tt&amp;gt; ''alle'' Bits von h benutzt (Eigenschaft aus der Zahlentheorie). Die Kapizität wird vergrößert, wenn &amp;lt;tt&amp;gt;size == capacity&amp;lt;/tt&amp;gt; erreicht wird. Analog zum dynamischen Array werden die Daten dann aus dem alten Array (&amp;lt;tt&amp;gt;self.array&amp;lt;/tt&amp;gt;) in ein entsprechend vergrößertes neues Array kopiert.&lt;br /&gt;
&lt;br /&gt;
== Hashtabelle mit offener Adressierung (offenes Hashing) ==&lt;br /&gt;
[http://de.wikipedia.org/wiki/Hashtabelle#Hashing_mit_offener_Adressierung Wikipedia (de)]&lt;br /&gt;
[http://en.wikipedia.org/wiki/Open_addressing Wikipedia (en)]&lt;br /&gt;
&lt;br /&gt;
Optimistischer Ansatz: Kollisionen werden nicht so häufig auftreten.&lt;br /&gt;
&lt;br /&gt;
=== Idee ===&lt;br /&gt;
Wenn &amp;lt;tt&amp;gt;array[index]&amp;lt;/tt&amp;gt; durch Kollision bereits vergeben ist, probiere einen&lt;br /&gt;
anderen Index aus.&lt;br /&gt;
&lt;br /&gt;
* Das Array enthält pro Element höchstens ein (key,value)-Paar&lt;br /&gt;
* Das Array muss stets mindestens ''einen'' freien Platz haben (sonst gäbe es beim Ausprobieren anderer Indizes eine Endlosschleife). Es gilt immer &amp;lt;tt&amp;gt;self.size &amp;lt; self.capacity&amp;lt;/tt&amp;gt;. Dies war bei der vorigen Hash-Implementation mit linearer Verkettung nicht notwendig (aber im Sinne schneller zugriffszeiten trotzdem wünschenswert).&lt;br /&gt;
&lt;br /&gt;
=== Vorgehen bei Kollisionen ===&lt;br /&gt;
&lt;br /&gt;
==== Sequentielles Sondieren====&lt;br /&gt;
Probiere den nächsten Index: &amp;lt;tt&amp;gt;index = (index+1) % capacity&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Vorteil: einfach&lt;br /&gt;
* Nachteil: Clusterbildung&lt;br /&gt;
&lt;br /&gt;
Clusterbildung heißt, dass sich größere zusammenhängende Bereiche bilden die belegt sind, unterbrochen von Bereichen die komplett frei sind. Beim Versuche des Einfügens eines Elements an einen Platz, der schon belegt ist, muss jetzt das ganze Cluster sequentiell durchlaufen werden, bis ein freier Platz gefunden wird. Damit entspricht die Komplexität der Suche der mittleren Länge der belegten Bereiche, was sich entsprechend in einer langsamen Suche widerspiegelt.&lt;br /&gt;
&lt;br /&gt;
==== Doppeltes Hashing ====&lt;br /&gt;
[http://de.wikipedia.org/wiki/Doppel-Hashing Wikipedia (de)] [http://en.wikipedia.org/wiki/Double_hashing Wikipedia (en)]&lt;br /&gt;
&lt;br /&gt;
Bestimme einen neuen Index (bei Kollisionen) durch eine ''2. Hashfunktion''.&lt;br /&gt;
&lt;br /&gt;
Das doppelte Hashing wird typischerweise in der Praxis angewendet und liegt auch der Python Implementierung des Datentyps [http://docs.python.org/tut/node7.html#SECTION007500000000000000000 Dictionary] (Syntax &amp;lt;tt&amp;gt;{'a':1, 'b':2, 'c':3}&amp;lt;/tt&amp;gt; zugrunde.&lt;br /&gt;
&lt;br /&gt;
Eine effiziente Implementierung dieses Datentyps ist für die Performance der Skriptsprache Python extrem wichtig, da z.B. beim Aufruf einer Funktion der auszuführunde Code in einem Dictionary unter dem Schlüssel ''Funktionsname'' nachgeschlagen wird oder die Werte lokaler Variablen innerhalb einer Funktion ebenfalls in einem Dictionary zu finden sind.&lt;br /&gt;
&lt;br /&gt;
Für die Implementierung in Python werden wieder die obigen Klassen &amp;lt;tt&amp;gt;HashNode&amp;lt;/tt&amp;gt; (das Attribut &amp;lt;tt&amp;gt;next&amp;lt;/tt&amp;gt; kann allerdings jetzt entfernt werden) und &amp;lt;tt&amp;gt;HashTable&amp;lt;/tt&amp;gt; benötigt, es folgen die angepassten Implementationen von &amp;lt;tt&amp;gt;__setitem__&amp;lt;/tt&amp;gt; und &amp;lt;tt&amp;gt;__getitem__&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
  def __setitem__(self, key, value):&lt;br /&gt;
      h = hash(key)&lt;br /&gt;
      index = h % self.capacity&lt;br /&gt;
      while True:&lt;br /&gt;
          if self.array[index] is None or self.array[index].key is None:&lt;br /&gt;
               # das Feld ist frei (1. Abfrage)&lt;br /&gt;
               # oder das Feld ist als frei markiert (2. Abfrage)&lt;br /&gt;
               self.array[index] = HashNode(key, value)&lt;br /&gt;
               self.size +=1&lt;br /&gt;
               return&lt;br /&gt;
          if self.array[index].key == key:&lt;br /&gt;
               # Es gibt diesen Schlüssel schon,&lt;br /&gt;
               # überschreibe die Daten&lt;br /&gt;
               self.array[index].data = value&lt;br /&gt;
               return&lt;br /&gt;
          # Letzter Fall: Kollision =&amp;gt; neuer Index durch 2. Hashfunktion&lt;br /&gt;
          index = (5*index+1+h) % self.capacity&lt;br /&gt;
          h = h &amp;gt;&amp;gt; 5&lt;br /&gt;
&lt;br /&gt;
Die vorgestellte Implementierung orientiert sich an Pythons interner Dictionary Implementierung, der zugehörige Quelltext (mit ausführlichem Kommentar) findet sich unter [http://svn.python.org/view/*checkout*/python/trunk/Objects/dictobject.c dictobject.c Python Implementation (SVN)]&lt;br /&gt;
&lt;br /&gt;
===== Beispiel =====&lt;br /&gt;
Mit Zahlen &amp;lt;math&amp;gt;2^5&amp;lt;/math&amp;gt; statt &amp;lt;math&amp;gt;2^{32}&amp;lt;/math&amp;gt;.&lt;br /&gt;
  h=25, capacity=8&lt;br /&gt;
  i_0 = 25%8 = 1&lt;br /&gt;
  Es finde eine Kollision statt.&lt;br /&gt;
  i_1 = (5*1+h)%8 = 31%8 = 7&lt;br /&gt;
  h = h&amp;gt;&amp;gt;2 &amp;lt;==&amp;gt; h = (0b11001)&amp;gt;&amp;gt;2 = 0b00110 = 6&lt;br /&gt;
  Es finde eine Kollision statt.&lt;br /&gt;
  i_2 = (5*7+1+h)%8  =42%8 = 2&lt;br /&gt;
  h = h&amp;gt;&amp;gt;2 &amp;lt;==&amp;gt; h=1&lt;br /&gt;
  Es finde eine Kollision statt.&lt;br /&gt;
  i_3 = (5*2+1+h)%8 = 12%8 = 4&lt;br /&gt;
  h = h&amp;gt;&amp;gt;2 &amp;lt;==&amp;gt; h=0&lt;br /&gt;
  Es finde eine Kollision statt.&lt;br /&gt;
  i_4 = (5*4+1+0)%8 = 5&lt;br /&gt;
  i_5 = (5*5+1)%8 = 2&lt;br /&gt;
  i_6 = (5*2+1)%8 = 3&lt;br /&gt;
   ...&lt;br /&gt;
Allen Indizes werden erreicht bevor sich die Folge wiederholt.&lt;br /&gt;
&lt;br /&gt;
===== Komplexität des offenen Hashings =====&lt;br /&gt;
&lt;br /&gt;
* Annahme: uniformes Hashing, das heißt alle Indizes haben gleiche Wahrscheinlichkeit&lt;br /&gt;
* Füllstand &amp;lt;math&amp;gt;\alpha = \frac{\text{size}}{\text{capacity}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* '''Erfolglose Suche''' (d.h. es wird entweder ein neues Element eingefügt oder ein &amp;lt;tt&amp;gt;KeyError&amp;lt;/tt&amp;gt; geworfen): Untere Schranke für die Komplexität ist &amp;lt;math&amp;gt;\Omega\left(\frac{1}{1-\alpha}\right)&amp;lt;/math&amp;gt; Schritte (= Anzahl der notwendigen index-Berechnungen).&lt;br /&gt;
* '''Erfolgreiche Suche''' &amp;lt;math&amp;gt;\Omega\left(\frac{1}{\alpha}\ln\left(\frac{1}{1-\alpha}\right)\right)&amp;lt;/math&amp;gt; Schritte.&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;5&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
! &amp;lt;math&amp;gt;\alpha&amp;lt;/math&amp;gt;&lt;br /&gt;
! 0.5&lt;br /&gt;
! 0.9&lt;br /&gt;
|- &lt;br /&gt;
| erfolglos&lt;br /&gt;
| 2.0&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| erfolgreich&lt;br /&gt;
| 1.4&lt;br /&gt;
| 2.6&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===== Wahl der Kapazität =====&lt;br /&gt;
In Python wird &amp;lt;tt&amp;gt;capacity&amp;lt;/tt&amp;gt; Aufgrund der obigen Beobachtung so gewählt, dass &amp;lt;math&amp;gt;\alpha \leq 2/3&amp;lt;/math&amp;gt;. Falls &amp;lt;math&amp;gt;\alpha&amp;lt;/math&amp;gt; größer werden sollte, verdopple die Kapazität und kopiere das alte array in das neue Array (analog zum dynamischen Array)&lt;br /&gt;
&lt;br /&gt;
In Python werden die Kapazitätsgrößen als Zweierpotenzen gewählt, also 4,8,16,32,...,&lt;br /&gt;
so dass &amp;lt;tt&amp;gt;h % self.capacity&amp;lt;/tt&amp;gt; nur die unteren Bits von &amp;lt;tt&amp;gt;h&amp;lt;/tt&amp;gt; benutzt.&lt;br /&gt;
&lt;br /&gt;
== Anwendung von Hashing ==&lt;br /&gt;
&lt;br /&gt;
* Hashtabelle, assoziatives Aray&lt;br /&gt;
* Sortieren in linearer Zeit (Übungsaufgabe 6.2)&lt;br /&gt;
* Suchen von Strings in Texten: Rabin-Karp-Algorithmus&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
=== Rabin Karp Algorithmus ===&lt;br /&gt;
[http://de.wikipedia.org/wiki/Rabin-Karp-Algorithmus Wikipedia (de)] [http://en.wikipedia.org/wiki/Rabin-Karp_string_search_algorithm Wikipedia (en)]&lt;br /&gt;
&lt;br /&gt;
In Textverarbeitungsanwendungen ist eine häufig benutzte Funktion die ''Search &amp;amp; Replace'' Funktionalität. Die Suche sollte in O(len(text)) möglich sein, aber ein naiver Algorithmus braucht O(len(text)*len(searchstring))&lt;br /&gt;
&lt;br /&gt;
==== Naive Implementierung der Suche ====&lt;br /&gt;
  def search(text, s):&lt;br /&gt;
      M, N = len(text), len(s)&lt;br /&gt;
      for k in range(M-N):&lt;br /&gt;
          if s==text[k:k+N]:   # O(N), da N Zeichen verglichen werden müssen&lt;br /&gt;
              return k&lt;br /&gt;
      return -1 #nicht gefunden&lt;br /&gt;
&lt;br /&gt;
==== Idee des Rabin Karp Algorithmus ====&lt;br /&gt;
Statt Vergleichen &amp;lt;tt&amp;gt;s==text[k:k+N]&amp;lt;/tt&amp;gt;, die O(N) benötigen da N Vergleiche der Buchstaben durchgeführt werden müssen, Vergleiche die Hashs von Suchstring und dem zu untersuchenden Textabschnitt: &amp;lt;tt&amp;gt;hash(s) == hash(text[k:k+N])&amp;lt;/tt&amp;gt;. Dabei muss natürlich &amp;lt;tt&amp;gt;hash(s)&amp;lt;/tt&amp;gt; nur einmal berechnet werden, wohingegen &amp;lt;tt&amp;gt;hash(text[k:k+N])&amp;lt;/tt&amp;gt; immer wieder neu berechnet werden muss. Damit der Vergleich O(1) sein kann, ist es deswegen erforderlich, eine solche Hashfunktion zu haben, die nicht alle Zeichen (das wäre O(N) ) einlesen muss, sondern die vorhergehende Hashfunktion mit einbezieht.&lt;br /&gt;
&lt;br /&gt;
Eine solche Hashfunktion heißt ''Running Hash'' und funktioniert analog zum ''Sliding Mean''.&lt;br /&gt;
&lt;br /&gt;
Die Running Hash Funktion berechnet in O(1) den hash von &amp;lt;tt&amp;gt;text[k+1:k+1+N]&amp;lt;/tt&amp;gt; ausgehend vom hash für &amp;lt;tt&amp;gt;text[k:k+N]&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Idee: Interpretiere den Text als Ziffern in einer base d Darstellung:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h_k = \text{text}[k]\cdot d^{N-1} + \text{text}[k]\cdot d^{N-2} + \cdots + \text{text}[k+N-1]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für die Basis 10 (Dezimalsystem) ergibt sich also&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h_k = \text{text}[k]\cdot {10}^{N-1} + \text{text}[k]\cdot {10}^{N-2} + \cdots + \text{text}[k+N-1]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Daraus folgt&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h_{k+1} = 10\cdot h_k - \text{text}[k]\cdot {10}^{N} + \text{text}[k+N]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Komplexität dieses Updates ist O(1), falls man &amp;lt;math&amp;gt;{10}^{N}&amp;lt;/math&amp;gt; vorberechnet hat.&lt;br /&gt;
&lt;br /&gt;
In der Realität wählt man dann d=32 und benutzt noch an einigen Stellen modulo Operationen, um die Zahlen nicht zu groß werden zu lassen.&lt;br /&gt;
&lt;br /&gt;
==== Implementation ====&lt;br /&gt;
  def searchRabinKarp(text, s):&lt;br /&gt;
      ht, hs, dN = 0, 0, 1&lt;br /&gt;
      M, N = len(text), len(s)&lt;br /&gt;
      d, q = 32, 33554393&lt;br /&gt;
      #q ist eine große Primzahl, aber so,&lt;br /&gt;
      #dass d*q &amp;lt; 2**32 (um Überlauf zu vermeiden)&lt;br /&gt;
      &lt;br /&gt;
      #Initialisierung      &lt;br /&gt;
      for k in range(N):&lt;br /&gt;
          ht = (ht*d + ord(text[k])) % q&lt;br /&gt;
          #ord() gibt die ASCIInummer des übergebenen Zeichens zurück&lt;br /&gt;
          ds = (hs*d + ord( s[k] )) % q&lt;br /&gt;
          dN = (dN*a) % q&lt;br /&gt;
      #Die Variablen sind jetzt wie folgt initialisiert:&lt;br /&gt;
      #ht = hash(text[0:N])&lt;br /&gt;
      #hs = hash(s)&lt;br /&gt;
      #dN = (d**N) % q&lt;br /&gt;
      &lt;br /&gt;
      #Hauptschleife&lt;br /&gt;
      k = 0 &lt;br /&gt;
      while k &amp;lt; M-N:&lt;br /&gt;
          if hs == ht and s==text[k:k+N]:&lt;br /&gt;
              return k # serch string an Position k gefunden&lt;br /&gt;
          if k+N &amp;lt; M:&lt;br /&gt;
              ht = (d*ht - dN * ord(text[k]) + dN*q + ord(text[k+N]) ) % q&lt;br /&gt;
          k +=1&lt;br /&gt;
      return -1  # search string nicht gefunden&lt;/div&gt;</summary>
		<author><name>Thorben</name></author>	</entry>

	<entry>
		<id>https://alda.iwr.uni-heidelberg.de/index.php?title=Hashing_und_assoziative_Arrays&amp;diff=1735</id>
		<title>Hashing und assoziative Arrays</title>
		<link rel="alternate" type="text/html" href="https://alda.iwr.uni-heidelberg.de/index.php?title=Hashing_und_assoziative_Arrays&amp;diff=1735"/>
				<updated>2008-06-10T22:32:32Z</updated>
		
		<summary type="html">&lt;p&gt;Thorben: /* Doppeltes Hashing */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Mitschrift gibts [http://hci.iwr.uni-heidelberg.de/alda/images/AlDa.pdf hier] als PDF und [http://hci.iwr.uni-heidelberg.de/alda/images/Alda_source.pdf hier] gibts die TeX-Sourcen, leider als PDF weil man wohl keine .TeXs hochladen darf. Originale gibts auf Anfrage bei kirchner at cl dot uni minus heidelberg dot de. Wird das Package &amp;quot;listings&amp;quot; verwendet, das gibts bei [http://tug.ctan.org/tex-archive/macros/latex/contrib/listings/ http://tug.ctan.org/tex-archive/macros/latex/contrib/listings/] &lt;br /&gt;
&lt;br /&gt;
Tipp- und sonstige Fehler dürfen gerne verbessert und erneut hochgeladen werden, oder gebt mir per Email Bescheid, dann pflege ich die   Korrektur ein :)&lt;br /&gt;
&lt;br /&gt;
Ich Finde dein Aufschrieb sollte ins Wiki übetragen werden, das bietet auch alles, was   &lt;br /&gt;
du mit Latex machen kannst. Die Bäume kannst du z.B. mit Latex zeichnen, einen pro Seite und diese dann in eine png Datei umwandeln. Wie sowas geht kann man z.B. in den Quellen von doxygen oder mediawiki selbst nachlesen. Oder man zoomt rein und macht einen Screenshot :-)&lt;br /&gt;
&lt;br /&gt;
== Hashtabelle mit linearer Verkettung ==&lt;br /&gt;
Pessimistischer Ansatz: Kollisionen treten häufig auf, deshalb wird unter jedem&lt;br /&gt;
Hashindex gleich eine Liste angelegt, in der Einträge aufgenommen werden können.&lt;br /&gt;
&lt;br /&gt;
===Implementation in Python===&lt;br /&gt;
''HashNode'' ist eine Hilfsdatenstruktur, die Schlüssel und Wert speichert&lt;br /&gt;
und mit Hilfe von ''next'' eine verkettete Liste realisiert&lt;br /&gt;
  class HashNode:&lt;br /&gt;
      def __init__(self,key,data,next):&lt;br /&gt;
          self.key = key&lt;br /&gt;
          self.data = data&lt;br /&gt;
          self.next = next # Verkettung!&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Die eigentliche Hashtabelle wird in der Klasse ''HashTable'' implementiert:&lt;br /&gt;
  class HashTable:&lt;br /&gt;
      def __init__(self):&lt;br /&gt;
         self.capacity = ... # Geeignete Werte siehe unten&lt;br /&gt;
         self.size = 0&lt;br /&gt;
         self.array = [None]*self.capacity&lt;br /&gt;
&lt;br /&gt;
In Python ([http://docs.python.org/ref/sequence-types.html Python Docs zum Thema]) wird der Zugriffsoperator ''[ ]'' für eine Datenstruktur wie folgt (innerhalb einer Klasse) implementiert:&lt;br /&gt;
  def __setitem__(self, key, value)&lt;br /&gt;
&lt;br /&gt;
so dass im Programmtext dann folgende Syntax möglich ist: &amp;lt;tt&amp;gt;a[key] = value&amp;lt;/tt&amp;gt; (schreibender Zugriff auf &amp;lt;tt&amp;gt;a[key]&amp;lt;/tt&amp;gt;).&lt;br /&gt;
Analog wird der lesende Zugriff &amp;lt;tt&amp;gt;value = a[key]&amp;lt;/tt&amp;gt; wie folgt umgesetzt:&lt;br /&gt;
  def __getitem__(self, key, value)&lt;br /&gt;
&lt;br /&gt;
Implementierung der &amp;lt;tt&amp;gt;__setitem__&amp;lt;/tt&amp;gt;-Funktion in der &amp;lt;tt&amp;gt;HashTable&amp;lt;/tt&amp;gt;-Klasse:&lt;br /&gt;
  def __setitem__(self, key, value):&lt;br /&gt;
      index = hash(key) % self.capacity&lt;br /&gt;
      node = self.array[index]&lt;br /&gt;
      while node is not None:&lt;br /&gt;
          if node.key == key:&lt;br /&gt;
              # Element key ist schon in der Tabelle&lt;br /&gt;
              #Überschreibe die Daten mit dem neuen Wert&lt;br /&gt;
              node.data = value&lt;br /&gt;
              return&lt;br /&gt;
          # Kollision des Hashwerts, probiere nächsten Key aus&lt;br /&gt;
          node = node.next&lt;br /&gt;
      # Kein Element hatte den richtigen Schlüssel.&lt;br /&gt;
      # ==&amp;gt;Es gibt diesen Schlüssel noch nicht&lt;br /&gt;
      # Füge also ein neues Element in die Hashtabelle ein&lt;br /&gt;
       &lt;br /&gt;
      self.array[index] = HashNode(key, value, self.array[index])&lt;br /&gt;
      # Der alte Anfang der Liste wurde der Nachfolger des neu eingefügten&lt;br /&gt;
      # ersten Elements&lt;br /&gt;
       &lt;br /&gt;
      self.size += 1&lt;br /&gt;
&lt;br /&gt;
Und die Implementierung der &amp;lt;tt&amp;gt;__getitem__&amp;lt;/tt&amp;gt; Funktionen:&lt;br /&gt;
  def __getitem__(self, key):&lt;br /&gt;
      index = hash(key) % self.capacity&lt;br /&gt;
      node = self.array[index]&lt;br /&gt;
      while node is not None:&lt;br /&gt;
           if node.key == key: # Gefunden!&lt;br /&gt;
               return node.data&lt;br /&gt;
           node = node.next&lt;br /&gt;
      raise KeyError(key)&lt;br /&gt;
&lt;br /&gt;
==== Wahl der Kapazität ====&lt;br /&gt;
In der C++ Standardbibliothek (Klasse &amp;lt;tt&amp;gt; [http://www.sgi.com/tech/stl/hash_map.htmlstd::hash_map std::hash_map]&amp;lt;/tt&amp;gt;) wird die Hashtabelle häufig mit Hilfe der linearen Verkettung&lt;br /&gt;
imlementiert. Dabei wird &amp;lt;tt&amp;gt;capacity&amp;lt;/tt&amp;gt; immer als ''Primzahl'' gewählt, wobei sich aufeinanderfolgende Kapazitäten immer ungefähr verdoppeln:&lt;br /&gt;
  53, 97, 193, 398, 769, ...&lt;br /&gt;
[http://gcc.gnu.org/viewcvs/*checkout*/trunk/libstdc++-v3/src/hashtable.cc GCC hashtable.cc (Primzahlen)] [http://gcc.gnu.org/viewcvs/*checkout*/trunk/libstdc++-v3/include/tr1_impl/hashtable_policy.h GCC Hash Implementation]&lt;br /&gt;
&lt;br /&gt;
Das hat zur Folge, dass &amp;lt;tt&amp;gt;hash(key) % self.capacity&amp;lt;/tt&amp;gt; ''alle'' Bits von h benutzt (Eigenschaft aus der Zahlentheorie). Die Kapizität wird vergrößert, wenn &amp;lt;tt&amp;gt;size == capacity&amp;lt;/tt&amp;gt; erreicht wird. Analog zum dynamischen Array werden die Daten dann aus dem alten Array (&amp;lt;tt&amp;gt;self.array&amp;lt;/tt&amp;gt;) in ein entsprechend vergrößertes neues Array kopiert.&lt;br /&gt;
&lt;br /&gt;
== Hashtabelle mit offener Adressierung (offenes Hashing) ==&lt;br /&gt;
[http://de.wikipedia.org/wiki/Hashtabelle#Hashing_mit_offener_Adressierung Wikipedia (de)]&lt;br /&gt;
[http://en.wikipedia.org/wiki/Open_addressing Wikipedia (en)]&lt;br /&gt;
&lt;br /&gt;
Optimistischer Ansatz: Kollisionen werden nicht so häufig auftreten.&lt;br /&gt;
&lt;br /&gt;
=== Idee ===&lt;br /&gt;
Wenn &amp;lt;tt&amp;gt;array[index]&amp;lt;/tt&amp;gt; durch Kollision bereits vergeben ist, probiere einen&lt;br /&gt;
anderen Index aus.&lt;br /&gt;
&lt;br /&gt;
* Das Array enthält pro Element höchstens ein (key,value)-Paar&lt;br /&gt;
* Das Array muss stets mindestens ''einen'' freien Platz haben (sonst gäbe es beim Ausprobieren anderer Indizes eine Endlosschleife). Es gilt immer &amp;lt;tt&amp;gt;self.size &amp;lt; self.capacity&amp;lt;/tt&amp;gt;. Dies war bei der vorigen Hash-Implementation mit linearer Verkettung nicht notwendig (aber im Sinne schneller zugriffszeiten trotzdem wünschenswert).&lt;br /&gt;
&lt;br /&gt;
=== Vorgehen bei Kollisionen ===&lt;br /&gt;
&lt;br /&gt;
==== Sequentielles Sondieren====&lt;br /&gt;
Probiere den nächsten Index: &amp;lt;tt&amp;gt;index = (index+1) % capacity&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Vorteil: einfach&lt;br /&gt;
* Nachteil: Clusterbildung&lt;br /&gt;
&lt;br /&gt;
Clusterbildung heißt, dass sich größere zusammenhängende Bereiche bilden die belegt sind, unterbrochen von Bereichen die komplett frei sind. Beim Versuche des Einfügens eines Elements an einen Platz, der schon belegt ist, muss jetzt das ganze Cluster sequentiell durchlaufen werden, bis ein freier Platz gefunden wird. Damit entspricht die Komplexität der Suche der mittleren Länge der belegten Bereiche, was sich entsprechend in einer langsamen Suche widerspiegelt.&lt;br /&gt;
&lt;br /&gt;
==== Doppeltes Hashing ====&lt;br /&gt;
[http://de.wikipedia.org/wiki/Doppel-Hashing Wikipedia (de)] [http://en.wikipedia.org/wiki/Double_hashing Wikipedia (en)]&lt;br /&gt;
&lt;br /&gt;
Bestimme einen neuen Index (bei Kollisionen) durch eine ''2. Hashfunktion''.&lt;br /&gt;
&lt;br /&gt;
Das doppelte Hashing wird typischerweise in der Praxis angewendet und liegt auch der Python Implementierung des Datentyps [http://docs.python.org/tut/node7.html#SECTION007500000000000000000 Dictionary] (Syntax &amp;lt;tt&amp;gt;{'a':1, 'b':2, 'c':3}&amp;lt;/tt&amp;gt; zugrunde.&lt;br /&gt;
&lt;br /&gt;
Eine effiziente Implementierung dieses Datentyps ist für die Performance der Skriptsprache Python extrem wichtig, da z.B. beim Aufruf einer Funktion der auszuführunde Code in einem Dictionary unter dem Schlüssel ''Funktionsname'' nachgeschlagen wird oder die Werte lokaler Variablen innerhalb einer Funktion ebenfalls in einem Dictionary zu finden sind.&lt;br /&gt;
&lt;br /&gt;
Für die Implementierung in Python werden wieder die obigen Klassen &amp;lt;tt&amp;gt;HashNode&amp;lt;/tt&amp;gt; (das Attribut &amp;lt;tt&amp;gt;next&amp;lt;/tt&amp;gt; kann allerdings jetzt entfernt werden) und &amp;lt;tt&amp;gt;HashTable&amp;lt;/tt&amp;gt; benötigt, es folgen die angepassten Implementationen von &amp;lt;tt&amp;gt;__setitem__&amp;lt;/tt&amp;gt; und &amp;lt;tt&amp;gt;__getitem__&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
  def __setitem__(self, key, value):&lt;br /&gt;
      h = hash(key)&lt;br /&gt;
      index = h % self.capacity&lt;br /&gt;
      while True:&lt;br /&gt;
          if self.array[index] is None or self.array[index].key is None:&lt;br /&gt;
               # das Feld ist frei (1. Abfrage)&lt;br /&gt;
               # oder das Feld ist als frei markiert (2. Abfrage)&lt;br /&gt;
               self.array[index] = HashNode(key, value)&lt;br /&gt;
               self.size +=1&lt;br /&gt;
               return&lt;br /&gt;
          if self.array[index].key == key:&lt;br /&gt;
               # Es gibt diesen Schlüssel schon,&lt;br /&gt;
               # überschreibe die Daten&lt;br /&gt;
               self.array[index].data = value&lt;br /&gt;
               return&lt;br /&gt;
          # Letzter Fall: Kollision =&amp;gt; neuer Index durch 2. Hashfunktion&lt;br /&gt;
          index = (5*index+1+h) % self.capacity&lt;br /&gt;
          h = h &amp;gt;&amp;gt; 5&lt;br /&gt;
&lt;br /&gt;
Die vorgestellte Implementierung orientiert sich an Pythons interner Dictionary Implementierung, der zugehörige Quelltext (mit ausführlichem Kommentar) findet sich unter [http://svn.python.org/view/*checkout*/python/trunk/Objects/dictobject.c dictobject.c Python Implementation (SVN)]&lt;br /&gt;
&lt;br /&gt;
===== Komplexität des offenen Hashings =====&lt;br /&gt;
&lt;br /&gt;
* Annahme: uniformes Hashing, das heißt alle Indizes haben gleiche Wahrscheinlichkeit&lt;br /&gt;
* Füllstand &amp;lt;math&amp;gt;\alpha = \frac{\text{size}}{\text{capacity}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* '''Erfolglose Suche''' (d.h. es wird entweder ein neues Element eingefügt oder ein &amp;lt;tt&amp;gt;KeyError&amp;lt;/tt&amp;gt; geworfen): Untere Schranke für die Komplexität ist &amp;lt;math&amp;gt;\Omega\left(\frac{1}{1-\alpha}\right)&amp;lt;/math&amp;gt; Schritte (= Anzahl der notwendigen index-Berechnungen).&lt;br /&gt;
* '''Erfolgreiche Suche''' &amp;lt;math&amp;gt;\Omega\left(\frac{1}{\alpha}\ln\left(\frac{1}{1-\alpha}\right)\right)&amp;lt;/math&amp;gt; Schritte.&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;5&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
! &amp;lt;math&amp;gt;\alpha&amp;lt;/math&amp;gt;&lt;br /&gt;
! 0.5&lt;br /&gt;
! 0.9&lt;br /&gt;
|- &lt;br /&gt;
| erfolglos&lt;br /&gt;
| 2.0&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| erfolgreich&lt;br /&gt;
| 1.4&lt;br /&gt;
| 2.6&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===== Wahl der Kapazität =====&lt;br /&gt;
In Python wird &amp;lt;tt&amp;gt;capacity&amp;lt;/tt&amp;gt; Aufgrund der obigen Beobachtung so gewählt, dass &amp;lt;math&amp;gt;\alpha \leq 2/3&amp;lt;/math&amp;gt;. Falls &amp;lt;math&amp;gt;\alpha&amp;lt;/math&amp;gt; größer werden sollte, verdopple die Kapazität und kopiere das alte array in das neue Array (analog zum dynamischen Array)&lt;br /&gt;
&lt;br /&gt;
In Python werden die Kapazitätsgrößen als Zweierpotenzen gewählt, also 4,8,16,32,...,&lt;br /&gt;
so dass &amp;lt;tt&amp;gt;h % self.capacity&amp;lt;/tt&amp;gt; nur die unteren Bits von &amp;lt;tt&amp;gt;h&amp;lt;/tt&amp;gt; benutzt.&lt;br /&gt;
&lt;br /&gt;
== Anwendung von Hashing ==&lt;br /&gt;
&lt;br /&gt;
* Hashtabelle, assoziatives Aray&lt;br /&gt;
* Sortieren in linearer Zeit (Übungsaufgabe 6.2)&lt;br /&gt;
* Suchen von Strings in Texten: Rabin-Karp-Algorithmus&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
=== Rabin Karp Algorithmus ===&lt;br /&gt;
[http://de.wikipedia.org/wiki/Rabin-Karp-Algorithmus Wikipedia (de)] [http://en.wikipedia.org/wiki/Rabin-Karp_string_search_algorithm Wikipedia (en)]&lt;br /&gt;
&lt;br /&gt;
In Textverarbeitungsanwendungen ist eine häufig benutzte Funktion die ''Search &amp;amp; Replace'' Funktionalität. Die Suche sollte in O(len(text)) möglich sein, aber ein naiver Algorithmus braucht O(len(text)*len(searchstring))&lt;br /&gt;
&lt;br /&gt;
==== Naive Implementierung der Suche ====&lt;br /&gt;
  def search(text, s):&lt;br /&gt;
      M, N = len(text), len(s)&lt;br /&gt;
      for k in range(M-N):&lt;br /&gt;
          if s==text[k:k+N]:   # O(N), da N Zeichen verglichen werden müssen&lt;br /&gt;
              return k&lt;br /&gt;
      return -1 #nicht gefunden&lt;br /&gt;
&lt;br /&gt;
==== Idee des Rabin Karp Algorithmus ====&lt;br /&gt;
Statt Vergleichen &amp;lt;tt&amp;gt;s==text[k:k+N]&amp;lt;/tt&amp;gt;, die O(N) benötigen da N Vergleiche der Buchstaben durchgeführt werden müssen, Vergleiche die Hashs von Suchstring und dem zu untersuchenden Textabschnitt: &amp;lt;tt&amp;gt;hash(s) == hash(text[k:k+N])&amp;lt;/tt&amp;gt;. Dabei muss natürlich &amp;lt;tt&amp;gt;hash(s)&amp;lt;/tt&amp;gt; nur einmal berechnet werden, wohingegen &amp;lt;tt&amp;gt;hash(text[k:k+N])&amp;lt;/tt&amp;gt; immer wieder neu berechnet werden muss. Damit der Vergleich O(1) sein kann, ist es deswegen erforderlich, eine solche Hashfunktion zu haben, die nicht alle Zeichen (das wäre O(N) ) einlesen muss, sondern die vorhergehende Hashfunktion mit einbezieht.&lt;br /&gt;
&lt;br /&gt;
Eine solche Hashfunktion heißt ''Running Hash'' und funktioniert analog zum ''Sliding Mean''.&lt;br /&gt;
&lt;br /&gt;
Die Running Hash Funktion berechnet in O(1) den hash von &amp;lt;tt&amp;gt;text[k+1:k+1+N]&amp;lt;/tt&amp;gt; ausgehend vom hash für &amp;lt;tt&amp;gt;text[k:k+N]&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Idee: Interpretiere den Text als Ziffern in einer base d Darstellung:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h_k = \text{text}[k]\cdot d^{N-1} + \text{text}[k]\cdot d^{N-2} + \cdots + \text{text}[k+N-1]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für die Basis 10 (Dezimalsystem) ergibt sich also&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h_k = \text{text}[k]\cdot {10}^{N-1} + \text{text}[k]\cdot {10}^{N-2} + \cdots + \text{text}[k+N-1]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Daraus folgt&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h_{k+1} = 10\cdot h_k - \text{text}[k]\cdot {10}^{N} + \text{text}[k+N]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Komplexität dieses Updates ist O(1), falls man &amp;lt;math&amp;gt;{10}^{N}&amp;lt;/math&amp;gt; vorberechnet hat.&lt;br /&gt;
&lt;br /&gt;
In der Realität wählt man dann d=32 und benutzt noch an einigen Stellen modulo Operationen, um die Zahlen nicht zu groß werden zu lassen.&lt;br /&gt;
&lt;br /&gt;
==== Implementation ====&lt;br /&gt;
  def searchRabinKarp(text, s):&lt;br /&gt;
      ht, hs, dN = 0, 0, 1&lt;br /&gt;
      M, N = len(text), len(s)&lt;br /&gt;
      d, q = 32, 33554393&lt;br /&gt;
      #q ist eine große Primzahl, aber so,&lt;br /&gt;
      #dass d*q &amp;lt; 2**32 (um Überlauf zu vermeiden)&lt;br /&gt;
      &lt;br /&gt;
      #Initialisierung      &lt;br /&gt;
      for k in range(N):&lt;br /&gt;
          ht = (ht*d + ord(text[k])) % q&lt;br /&gt;
          #ord() gibt die ASCIInummer des übergebenen Zeichens zurück&lt;br /&gt;
          ds = (hs*d + ord( s[k] )) % q&lt;br /&gt;
          dN = (dN*a) % q&lt;br /&gt;
      #Die Variablen sind jetzt wie folgt initialisiert:&lt;br /&gt;
      #ht = hash(text[0:N])&lt;br /&gt;
      #hs = hash(s)&lt;br /&gt;
      #dN = (d**N) % q&lt;br /&gt;
      &lt;br /&gt;
      #Hauptschleife&lt;br /&gt;
      k = 0 &lt;br /&gt;
      while k &amp;lt; M-N:&lt;br /&gt;
          if hs == ht and s==text[k:k+N]:&lt;br /&gt;
              return k # serch string an Position k gefunden&lt;br /&gt;
          if k+N &amp;lt; M:&lt;br /&gt;
              ht = (d*ht - dN * ord(text[k]) + dN*q + ord(text[k+N]) ) % q&lt;br /&gt;
          k +=1&lt;br /&gt;
      return -1  # search string nicht gefunden&lt;/div&gt;</summary>
		<author><name>Thorben</name></author>	</entry>

	<entry>
		<id>https://alda.iwr.uni-heidelberg.de/index.php?title=Hashing_und_assoziative_Arrays&amp;diff=1734</id>
		<title>Hashing und assoziative Arrays</title>
		<link rel="alternate" type="text/html" href="https://alda.iwr.uni-heidelberg.de/index.php?title=Hashing_und_assoziative_Arrays&amp;diff=1734"/>
				<updated>2008-06-10T22:31:24Z</updated>
		
		<summary type="html">&lt;p&gt;Thorben: /* Doppeltes Hashing */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Mitschrift gibts [http://hci.iwr.uni-heidelberg.de/alda/images/AlDa.pdf hier] als PDF und [http://hci.iwr.uni-heidelberg.de/alda/images/Alda_source.pdf hier] gibts die TeX-Sourcen, leider als PDF weil man wohl keine .TeXs hochladen darf. Originale gibts auf Anfrage bei kirchner at cl dot uni minus heidelberg dot de. Wird das Package &amp;quot;listings&amp;quot; verwendet, das gibts bei [http://tug.ctan.org/tex-archive/macros/latex/contrib/listings/ http://tug.ctan.org/tex-archive/macros/latex/contrib/listings/] &lt;br /&gt;
&lt;br /&gt;
Tipp- und sonstige Fehler dürfen gerne verbessert und erneut hochgeladen werden, oder gebt mir per Email Bescheid, dann pflege ich die   Korrektur ein :)&lt;br /&gt;
&lt;br /&gt;
Ich Finde dein Aufschrieb sollte ins Wiki übetragen werden, das bietet auch alles, was   &lt;br /&gt;
du mit Latex machen kannst. Die Bäume kannst du z.B. mit Latex zeichnen, einen pro Seite und diese dann in eine png Datei umwandeln. Wie sowas geht kann man z.B. in den Quellen von doxygen oder mediawiki selbst nachlesen. Oder man zoomt rein und macht einen Screenshot :-)&lt;br /&gt;
&lt;br /&gt;
== Hashtabelle mit linearer Verkettung ==&lt;br /&gt;
Pessimistischer Ansatz: Kollisionen treten häufig auf, deshalb wird unter jedem&lt;br /&gt;
Hashindex gleich eine Liste angelegt, in der Einträge aufgenommen werden können.&lt;br /&gt;
&lt;br /&gt;
===Implementation in Python===&lt;br /&gt;
''HashNode'' ist eine Hilfsdatenstruktur, die Schlüssel und Wert speichert&lt;br /&gt;
und mit Hilfe von ''next'' eine verkettete Liste realisiert&lt;br /&gt;
  class HashNode:&lt;br /&gt;
      def __init__(self,key,data,next):&lt;br /&gt;
          self.key = key&lt;br /&gt;
          self.data = data&lt;br /&gt;
          self.next = next # Verkettung!&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Die eigentliche Hashtabelle wird in der Klasse ''HashTable'' implementiert:&lt;br /&gt;
  class HashTable:&lt;br /&gt;
      def __init__(self):&lt;br /&gt;
         self.capacity = ... # Geeignete Werte siehe unten&lt;br /&gt;
         self.size = 0&lt;br /&gt;
         self.array = [None]*self.capacity&lt;br /&gt;
&lt;br /&gt;
In Python ([http://docs.python.org/ref/sequence-types.html Python Docs zum Thema]) wird der Zugriffsoperator ''[ ]'' für eine Datenstruktur wie folgt (innerhalb einer Klasse) implementiert:&lt;br /&gt;
  def __setitem__(self, key, value)&lt;br /&gt;
&lt;br /&gt;
so dass im Programmtext dann folgende Syntax möglich ist: &amp;lt;tt&amp;gt;a[key] = value&amp;lt;/tt&amp;gt; (schreibender Zugriff auf &amp;lt;tt&amp;gt;a[key]&amp;lt;/tt&amp;gt;).&lt;br /&gt;
Analog wird der lesende Zugriff &amp;lt;tt&amp;gt;value = a[key]&amp;lt;/tt&amp;gt; wie folgt umgesetzt:&lt;br /&gt;
  def __getitem__(self, key, value)&lt;br /&gt;
&lt;br /&gt;
Implementierung der &amp;lt;tt&amp;gt;__setitem__&amp;lt;/tt&amp;gt;-Funktion in der &amp;lt;tt&amp;gt;HashTable&amp;lt;/tt&amp;gt;-Klasse:&lt;br /&gt;
  def __setitem__(self, key, value):&lt;br /&gt;
      index = hash(key) % self.capacity&lt;br /&gt;
      node = self.array[index]&lt;br /&gt;
      while node is not None:&lt;br /&gt;
          if node.key == key:&lt;br /&gt;
              # Element key ist schon in der Tabelle&lt;br /&gt;
              #Überschreibe die Daten mit dem neuen Wert&lt;br /&gt;
              node.data = value&lt;br /&gt;
              return&lt;br /&gt;
          # Kollision des Hashwerts, probiere nächsten Key aus&lt;br /&gt;
          node = node.next&lt;br /&gt;
      # Kein Element hatte den richtigen Schlüssel.&lt;br /&gt;
      # ==&amp;gt;Es gibt diesen Schlüssel noch nicht&lt;br /&gt;
      # Füge also ein neues Element in die Hashtabelle ein&lt;br /&gt;
       &lt;br /&gt;
      self.array[index] = HashNode(key, value, self.array[index])&lt;br /&gt;
      # Der alte Anfang der Liste wurde der Nachfolger des neu eingefügten&lt;br /&gt;
      # ersten Elements&lt;br /&gt;
       &lt;br /&gt;
      self.size += 1&lt;br /&gt;
&lt;br /&gt;
Und die Implementierung der &amp;lt;tt&amp;gt;__getitem__&amp;lt;/tt&amp;gt; Funktionen:&lt;br /&gt;
  def __getitem__(self, key):&lt;br /&gt;
      index = hash(key) % self.capacity&lt;br /&gt;
      node = self.array[index]&lt;br /&gt;
      while node is not None:&lt;br /&gt;
           if node.key == key: # Gefunden!&lt;br /&gt;
               return node.data&lt;br /&gt;
           node = node.next&lt;br /&gt;
      raise KeyError(key)&lt;br /&gt;
&lt;br /&gt;
==== Wahl der Kapazität ====&lt;br /&gt;
In der C++ Standardbibliothek (Klasse &amp;lt;tt&amp;gt; [http://www.sgi.com/tech/stl/hash_map.htmlstd::hash_map std::hash_map]&amp;lt;/tt&amp;gt;) wird die Hashtabelle häufig mit Hilfe der linearen Verkettung&lt;br /&gt;
imlementiert. Dabei wird &amp;lt;tt&amp;gt;capacity&amp;lt;/tt&amp;gt; immer als ''Primzahl'' gewählt, wobei sich aufeinanderfolgende Kapazitäten immer ungefähr verdoppeln:&lt;br /&gt;
  53, 97, 193, 398, 769, ...&lt;br /&gt;
[http://gcc.gnu.org/viewcvs/*checkout*/trunk/libstdc++-v3/src/hashtable.cc GCC hashtable.cc (Primzahlen)] [http://gcc.gnu.org/viewcvs/*checkout*/trunk/libstdc++-v3/include/tr1_impl/hashtable_policy.h GCC Hash Implementation]&lt;br /&gt;
&lt;br /&gt;
Das hat zur Folge, dass &amp;lt;tt&amp;gt;hash(key) % self.capacity&amp;lt;/tt&amp;gt; ''alle'' Bits von h benutzt (Eigenschaft aus der Zahlentheorie). Die Kapizität wird vergrößert, wenn &amp;lt;tt&amp;gt;size == capacity&amp;lt;/tt&amp;gt; erreicht wird. Analog zum dynamischen Array werden die Daten dann aus dem alten Array (&amp;lt;tt&amp;gt;self.array&amp;lt;/tt&amp;gt;) in ein entsprechend vergrößertes neues Array kopiert.&lt;br /&gt;
&lt;br /&gt;
== Hashtabelle mit offener Adressierung (offenes Hashing) ==&lt;br /&gt;
[http://de.wikipedia.org/wiki/Hashtabelle#Hashing_mit_offener_Adressierung Wikipedia (de)]&lt;br /&gt;
[http://en.wikipedia.org/wiki/Open_addressing Wikipedia (en)]&lt;br /&gt;
&lt;br /&gt;
Optimistischer Ansatz: Kollisionen werden nicht so häufig auftreten.&lt;br /&gt;
&lt;br /&gt;
=== Idee ===&lt;br /&gt;
Wenn &amp;lt;tt&amp;gt;array[index]&amp;lt;/tt&amp;gt; durch Kollision bereits vergeben ist, probiere einen&lt;br /&gt;
anderen Index aus.&lt;br /&gt;
&lt;br /&gt;
* Das Array enthält pro Element höchstens ein (key,value)-Paar&lt;br /&gt;
* Das Array muss stets mindestens ''einen'' freien Platz haben (sonst gäbe es beim Ausprobieren anderer Indizes eine Endlosschleife). Es gilt immer &amp;lt;tt&amp;gt;self.size &amp;lt; self.capacity&amp;lt;/tt&amp;gt;. Dies war bei der vorigen Hash-Implementation mit linearer Verkettung nicht notwendig (aber im Sinne schneller zugriffszeiten trotzdem wünschenswert).&lt;br /&gt;
&lt;br /&gt;
=== Vorgehen bei Kollisionen ===&lt;br /&gt;
&lt;br /&gt;
==== Sequentielles Sondieren====&lt;br /&gt;
Probiere den nächsten Index: &amp;lt;tt&amp;gt;index = (index+1) % capacity&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Vorteil: einfach&lt;br /&gt;
* Nachteil: Clusterbildung&lt;br /&gt;
&lt;br /&gt;
Clusterbildung heißt, dass sich größere zusammenhängende Bereiche bilden die belegt sind, unterbrochen von Bereichen die komplett frei sind. Beim Versuche des Einfügens eines Elements an einen Platz, der schon belegt ist, muss jetzt das ganze Cluster sequentiell durchlaufen werden, bis ein freier Platz gefunden wird. Damit entspricht die Komplexität der Suche der mittleren Länge der belegten Bereiche, was sich entsprechend in einer langsamen Suche widerspiegelt.&lt;br /&gt;
&lt;br /&gt;
==== Doppeltes Hashing ====&lt;br /&gt;
[http://de.wikipedia.org/wiki/Doppel-Hashing Wikipedia (de)] [http://en.wikipedia.org/wiki/Double_hashing Wikipedia (en)]&lt;br /&gt;
&lt;br /&gt;
Bestimme einen neuen Index (bei Kollisionen) durch eine ''2. Hashfunktion''.&lt;br /&gt;
&lt;br /&gt;
Das doppelte Hashing wird typischerweise in der Praxis angewendet und liegt auch der Python Implementierung des Datentyps ''Dictionary'' (Syntax &amp;lt;tt&amp;gt;{'a':1, 'b':2, 'c':3}&amp;lt;/tt&amp;gt; zugrunde.&lt;br /&gt;
&lt;br /&gt;
Eine effiziente Implementierung dieses Datentyps ist für die Performance der Skriptsprache Python extrem wichtig, da z.B. beim Aufruf einer Funktion der auszuführunde Code in einem Dictionary unter dem Schlüssel ''Funktionsname'' nachgeschlagen wird oder die Werte lokaler Variablen innerhalb einer Funktion ebenfalls in einem Dictionary zu finden sind.&lt;br /&gt;
&lt;br /&gt;
Für die Implementierung in Python werden wieder die obigen Klassen &amp;lt;tt&amp;gt;HashNode&amp;lt;/tt&amp;gt; (das Attribut &amp;lt;tt&amp;gt;next&amp;lt;/tt&amp;gt; kann allerdings jetzt entfernt werden) und &amp;lt;tt&amp;gt;HashTable&amp;lt;/tt&amp;gt; benötigt, es folgen die angepassten Implementationen von &amp;lt;tt&amp;gt;__setitem__&amp;lt;/tt&amp;gt; und &amp;lt;tt&amp;gt;__getitem__&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
  def __setitem__(self, key, value):&lt;br /&gt;
      h = hash(key)&lt;br /&gt;
      index = h % self.capacity&lt;br /&gt;
      while True:&lt;br /&gt;
          if self.array[index] is None or self.array[index].key is None:&lt;br /&gt;
               # das Feld ist frei (1. Abfrage)&lt;br /&gt;
               # oder das Feld ist als frei markiert (2. Abfrage)&lt;br /&gt;
               self.array[index] = HashNode(key, value)&lt;br /&gt;
               self.size +=1&lt;br /&gt;
               return&lt;br /&gt;
          if self.array[index].key == key:&lt;br /&gt;
               # Es gibt diesen Schlüssel schon,&lt;br /&gt;
               # überschreibe die Daten&lt;br /&gt;
               self.array[index].data = value&lt;br /&gt;
               return&lt;br /&gt;
          # Letzter Fall: Kollision =&amp;gt; neuer Index durch 2. Hashfunktion&lt;br /&gt;
          index = (5*index+1+h) % self.capacity&lt;br /&gt;
          h = h &amp;gt;&amp;gt; 5&lt;br /&gt;
&lt;br /&gt;
Die vorgestellte Implementierung orientiert sich an Pythons interner Dictionary Implementierung, der zugehörige Quelltext (mit ausführlichem Kommentar) findet sich unter [http://svn.python.org/view/*checkout*/python/trunk/Objects/dictobject.c dictobject.c Python Implementation (SVN)]&lt;br /&gt;
&lt;br /&gt;
===== Komplexität des offenen Hashings =====&lt;br /&gt;
&lt;br /&gt;
* Annahme: uniformes Hashing, das heißt alle Indizes haben gleiche Wahrscheinlichkeit&lt;br /&gt;
* Füllstand &amp;lt;math&amp;gt;\alpha = \frac{\text{size}}{\text{capacity}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* '''Erfolglose Suche''' (d.h. es wird entweder ein neues Element eingefügt oder ein &amp;lt;tt&amp;gt;KeyError&amp;lt;/tt&amp;gt; geworfen): Untere Schranke für die Komplexität ist &amp;lt;math&amp;gt;\Omega\left(\frac{1}{1-\alpha}\right)&amp;lt;/math&amp;gt; Schritte (= Anzahl der notwendigen index-Berechnungen).&lt;br /&gt;
* '''Erfolgreiche Suche''' &amp;lt;math&amp;gt;\Omega\left(\frac{1}{\alpha}\ln\left(\frac{1}{1-\alpha}\right)\right)&amp;lt;/math&amp;gt; Schritte.&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;5&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
! &amp;lt;math&amp;gt;\alpha&amp;lt;/math&amp;gt;&lt;br /&gt;
! 0.5&lt;br /&gt;
! 0.9&lt;br /&gt;
|- &lt;br /&gt;
| erfolglos&lt;br /&gt;
| 2.0&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| erfolgreich&lt;br /&gt;
| 1.4&lt;br /&gt;
| 2.6&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===== Wahl der Kapazität =====&lt;br /&gt;
In Python wird &amp;lt;tt&amp;gt;capacity&amp;lt;/tt&amp;gt; Aufgrund der obigen Beobachtung so gewählt, dass &amp;lt;math&amp;gt;\alpha \leq 2/3&amp;lt;/math&amp;gt;. Falls &amp;lt;math&amp;gt;\alpha&amp;lt;/math&amp;gt; größer werden sollte, verdopple die Kapazität und kopiere das alte array in das neue Array (analog zum dynamischen Array)&lt;br /&gt;
&lt;br /&gt;
In Python werden die Kapazitätsgrößen als Zweierpotenzen gewählt, also 4,8,16,32,...,&lt;br /&gt;
so dass &amp;lt;tt&amp;gt;h % self.capacity&amp;lt;/tt&amp;gt; nur die unteren Bits von &amp;lt;tt&amp;gt;h&amp;lt;/tt&amp;gt; benutzt.&lt;br /&gt;
&lt;br /&gt;
== Anwendung von Hashing ==&lt;br /&gt;
&lt;br /&gt;
* Hashtabelle, assoziatives Aray&lt;br /&gt;
* Sortieren in linearer Zeit (Übungsaufgabe 6.2)&lt;br /&gt;
* Suchen von Strings in Texten: Rabin-Karp-Algorithmus&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
=== Rabin Karp Algorithmus ===&lt;br /&gt;
[http://de.wikipedia.org/wiki/Rabin-Karp-Algorithmus Wikipedia (de)] [http://en.wikipedia.org/wiki/Rabin-Karp_string_search_algorithm Wikipedia (en)]&lt;br /&gt;
&lt;br /&gt;
In Textverarbeitungsanwendungen ist eine häufig benutzte Funktion die ''Search &amp;amp; Replace'' Funktionalität. Die Suche sollte in O(len(text)) möglich sein, aber ein naiver Algorithmus braucht O(len(text)*len(searchstring))&lt;br /&gt;
&lt;br /&gt;
==== Naive Implementierung der Suche ====&lt;br /&gt;
  def search(text, s):&lt;br /&gt;
      M, N = len(text), len(s)&lt;br /&gt;
      for k in range(M-N):&lt;br /&gt;
          if s==text[k:k+N]:   # O(N), da N Zeichen verglichen werden müssen&lt;br /&gt;
              return k&lt;br /&gt;
      return -1 #nicht gefunden&lt;br /&gt;
&lt;br /&gt;
==== Idee des Rabin Karp Algorithmus ====&lt;br /&gt;
Statt Vergleichen &amp;lt;tt&amp;gt;s==text[k:k+N]&amp;lt;/tt&amp;gt;, die O(N) benötigen da N Vergleiche der Buchstaben durchgeführt werden müssen, Vergleiche die Hashs von Suchstring und dem zu untersuchenden Textabschnitt: &amp;lt;tt&amp;gt;hash(s) == hash(text[k:k+N])&amp;lt;/tt&amp;gt;. Dabei muss natürlich &amp;lt;tt&amp;gt;hash(s)&amp;lt;/tt&amp;gt; nur einmal berechnet werden, wohingegen &amp;lt;tt&amp;gt;hash(text[k:k+N])&amp;lt;/tt&amp;gt; immer wieder neu berechnet werden muss. Damit der Vergleich O(1) sein kann, ist es deswegen erforderlich, eine solche Hashfunktion zu haben, die nicht alle Zeichen (das wäre O(N) ) einlesen muss, sondern die vorhergehende Hashfunktion mit einbezieht.&lt;br /&gt;
&lt;br /&gt;
Eine solche Hashfunktion heißt ''Running Hash'' und funktioniert analog zum ''Sliding Mean''.&lt;br /&gt;
&lt;br /&gt;
Die Running Hash Funktion berechnet in O(1) den hash von &amp;lt;tt&amp;gt;text[k+1:k+1+N]&amp;lt;/tt&amp;gt; ausgehend vom hash für &amp;lt;tt&amp;gt;text[k:k+N]&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Idee: Interpretiere den Text als Ziffern in einer base d Darstellung:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h_k = \text{text}[k]\cdot d^{N-1} + \text{text}[k]\cdot d^{N-2} + \cdots + \text{text}[k+N-1]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für die Basis 10 (Dezimalsystem) ergibt sich also&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h_k = \text{text}[k]\cdot {10}^{N-1} + \text{text}[k]\cdot {10}^{N-2} + \cdots + \text{text}[k+N-1]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Daraus folgt&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h_{k+1} = 10\cdot h_k - \text{text}[k]\cdot {10}^{N} + \text{text}[k+N]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Komplexität dieses Updates ist O(1), falls man &amp;lt;math&amp;gt;{10}^{N}&amp;lt;/math&amp;gt; vorberechnet hat.&lt;br /&gt;
&lt;br /&gt;
In der Realität wählt man dann d=32 und benutzt noch an einigen Stellen modulo Operationen, um die Zahlen nicht zu groß werden zu lassen.&lt;br /&gt;
&lt;br /&gt;
==== Implementation ====&lt;br /&gt;
  def searchRabinKarp(text, s):&lt;br /&gt;
      ht, hs, dN = 0, 0, 1&lt;br /&gt;
      M, N = len(text), len(s)&lt;br /&gt;
      d, q = 32, 33554393&lt;br /&gt;
      #q ist eine große Primzahl, aber so,&lt;br /&gt;
      #dass d*q &amp;lt; 2**32 (um Überlauf zu vermeiden)&lt;br /&gt;
      &lt;br /&gt;
      #Initialisierung      &lt;br /&gt;
      for k in range(N):&lt;br /&gt;
          ht = (ht*d + ord(text[k])) % q&lt;br /&gt;
          #ord() gibt die ASCIInummer des übergebenen Zeichens zurück&lt;br /&gt;
          ds = (hs*d + ord( s[k] )) % q&lt;br /&gt;
          dN = (dN*a) % q&lt;br /&gt;
      #Die Variablen sind jetzt wie folgt initialisiert:&lt;br /&gt;
      #ht = hash(text[0:N])&lt;br /&gt;
      #hs = hash(s)&lt;br /&gt;
      #dN = (d**N) % q&lt;br /&gt;
      &lt;br /&gt;
      #Hauptschleife&lt;br /&gt;
      k = 0 &lt;br /&gt;
      while k &amp;lt; M-N:&lt;br /&gt;
          if hs == ht and s==text[k:k+N]:&lt;br /&gt;
              return k # serch string an Position k gefunden&lt;br /&gt;
          if k+N &amp;lt; M:&lt;br /&gt;
              ht = (d*ht - dN * ord(text[k]) + dN*q + ord(text[k+N]) ) % q&lt;br /&gt;
          k +=1&lt;br /&gt;
      return -1  # search string nicht gefunden&lt;/div&gt;</summary>
		<author><name>Thorben</name></author>	</entry>

	<entry>
		<id>https://alda.iwr.uni-heidelberg.de/index.php?title=Hashing_und_assoziative_Arrays&amp;diff=1733</id>
		<title>Hashing und assoziative Arrays</title>
		<link rel="alternate" type="text/html" href="https://alda.iwr.uni-heidelberg.de/index.php?title=Hashing_und_assoziative_Arrays&amp;diff=1733"/>
				<updated>2008-06-10T22:30:33Z</updated>
		
		<summary type="html">&lt;p&gt;Thorben: /* Wahl der Kapazität */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Mitschrift gibts [http://hci.iwr.uni-heidelberg.de/alda/images/AlDa.pdf hier] als PDF und [http://hci.iwr.uni-heidelberg.de/alda/images/Alda_source.pdf hier] gibts die TeX-Sourcen, leider als PDF weil man wohl keine .TeXs hochladen darf. Originale gibts auf Anfrage bei kirchner at cl dot uni minus heidelberg dot de. Wird das Package &amp;quot;listings&amp;quot; verwendet, das gibts bei [http://tug.ctan.org/tex-archive/macros/latex/contrib/listings/ http://tug.ctan.org/tex-archive/macros/latex/contrib/listings/] &lt;br /&gt;
&lt;br /&gt;
Tipp- und sonstige Fehler dürfen gerne verbessert und erneut hochgeladen werden, oder gebt mir per Email Bescheid, dann pflege ich die   Korrektur ein :)&lt;br /&gt;
&lt;br /&gt;
Ich Finde dein Aufschrieb sollte ins Wiki übetragen werden, das bietet auch alles, was   &lt;br /&gt;
du mit Latex machen kannst. Die Bäume kannst du z.B. mit Latex zeichnen, einen pro Seite und diese dann in eine png Datei umwandeln. Wie sowas geht kann man z.B. in den Quellen von doxygen oder mediawiki selbst nachlesen. Oder man zoomt rein und macht einen Screenshot :-)&lt;br /&gt;
&lt;br /&gt;
== Hashtabelle mit linearer Verkettung ==&lt;br /&gt;
Pessimistischer Ansatz: Kollisionen treten häufig auf, deshalb wird unter jedem&lt;br /&gt;
Hashindex gleich eine Liste angelegt, in der Einträge aufgenommen werden können.&lt;br /&gt;
&lt;br /&gt;
===Implementation in Python===&lt;br /&gt;
''HashNode'' ist eine Hilfsdatenstruktur, die Schlüssel und Wert speichert&lt;br /&gt;
und mit Hilfe von ''next'' eine verkettete Liste realisiert&lt;br /&gt;
  class HashNode:&lt;br /&gt;
      def __init__(self,key,data,next):&lt;br /&gt;
          self.key = key&lt;br /&gt;
          self.data = data&lt;br /&gt;
          self.next = next # Verkettung!&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Die eigentliche Hashtabelle wird in der Klasse ''HashTable'' implementiert:&lt;br /&gt;
  class HashTable:&lt;br /&gt;
      def __init__(self):&lt;br /&gt;
         self.capacity = ... # Geeignete Werte siehe unten&lt;br /&gt;
         self.size = 0&lt;br /&gt;
         self.array = [None]*self.capacity&lt;br /&gt;
&lt;br /&gt;
In Python ([http://docs.python.org/ref/sequence-types.html Python Docs zum Thema]) wird der Zugriffsoperator ''[ ]'' für eine Datenstruktur wie folgt (innerhalb einer Klasse) implementiert:&lt;br /&gt;
  def __setitem__(self, key, value)&lt;br /&gt;
&lt;br /&gt;
so dass im Programmtext dann folgende Syntax möglich ist: &amp;lt;tt&amp;gt;a[key] = value&amp;lt;/tt&amp;gt; (schreibender Zugriff auf &amp;lt;tt&amp;gt;a[key]&amp;lt;/tt&amp;gt;).&lt;br /&gt;
Analog wird der lesende Zugriff &amp;lt;tt&amp;gt;value = a[key]&amp;lt;/tt&amp;gt; wie folgt umgesetzt:&lt;br /&gt;
  def __getitem__(self, key, value)&lt;br /&gt;
&lt;br /&gt;
Implementierung der &amp;lt;tt&amp;gt;__setitem__&amp;lt;/tt&amp;gt;-Funktion in der &amp;lt;tt&amp;gt;HashTable&amp;lt;/tt&amp;gt;-Klasse:&lt;br /&gt;
  def __setitem__(self, key, value):&lt;br /&gt;
      index = hash(key) % self.capacity&lt;br /&gt;
      node = self.array[index]&lt;br /&gt;
      while node is not None:&lt;br /&gt;
          if node.key == key:&lt;br /&gt;
              # Element key ist schon in der Tabelle&lt;br /&gt;
              #Überschreibe die Daten mit dem neuen Wert&lt;br /&gt;
              node.data = value&lt;br /&gt;
              return&lt;br /&gt;
          # Kollision des Hashwerts, probiere nächsten Key aus&lt;br /&gt;
          node = node.next&lt;br /&gt;
      # Kein Element hatte den richtigen Schlüssel.&lt;br /&gt;
      # ==&amp;gt;Es gibt diesen Schlüssel noch nicht&lt;br /&gt;
      # Füge also ein neues Element in die Hashtabelle ein&lt;br /&gt;
       &lt;br /&gt;
      self.array[index] = HashNode(key, value, self.array[index])&lt;br /&gt;
      # Der alte Anfang der Liste wurde der Nachfolger des neu eingefügten&lt;br /&gt;
      # ersten Elements&lt;br /&gt;
       &lt;br /&gt;
      self.size += 1&lt;br /&gt;
&lt;br /&gt;
Und die Implementierung der &amp;lt;tt&amp;gt;__getitem__&amp;lt;/tt&amp;gt; Funktionen:&lt;br /&gt;
  def __getitem__(self, key):&lt;br /&gt;
      index = hash(key) % self.capacity&lt;br /&gt;
      node = self.array[index]&lt;br /&gt;
      while node is not None:&lt;br /&gt;
           if node.key == key: # Gefunden!&lt;br /&gt;
               return node.data&lt;br /&gt;
           node = node.next&lt;br /&gt;
      raise KeyError(key)&lt;br /&gt;
&lt;br /&gt;
==== Wahl der Kapazität ====&lt;br /&gt;
In der C++ Standardbibliothek (Klasse &amp;lt;tt&amp;gt; [http://www.sgi.com/tech/stl/hash_map.htmlstd::hash_map std::hash_map]&amp;lt;/tt&amp;gt;) wird die Hashtabelle häufig mit Hilfe der linearen Verkettung&lt;br /&gt;
imlementiert. Dabei wird &amp;lt;tt&amp;gt;capacity&amp;lt;/tt&amp;gt; immer als ''Primzahl'' gewählt, wobei sich aufeinanderfolgende Kapazitäten immer ungefähr verdoppeln:&lt;br /&gt;
  53, 97, 193, 398, 769, ...&lt;br /&gt;
[http://gcc.gnu.org/viewcvs/*checkout*/trunk/libstdc++-v3/src/hashtable.cc GCC hashtable.cc (Primzahlen)] [http://gcc.gnu.org/viewcvs/*checkout*/trunk/libstdc++-v3/include/tr1_impl/hashtable_policy.h GCC Hash Implementation]&lt;br /&gt;
&lt;br /&gt;
Das hat zur Folge, dass &amp;lt;tt&amp;gt;hash(key) % self.capacity&amp;lt;/tt&amp;gt; ''alle'' Bits von h benutzt (Eigenschaft aus der Zahlentheorie). Die Kapizität wird vergrößert, wenn &amp;lt;tt&amp;gt;size == capacity&amp;lt;/tt&amp;gt; erreicht wird. Analog zum dynamischen Array werden die Daten dann aus dem alten Array (&amp;lt;tt&amp;gt;self.array&amp;lt;/tt&amp;gt;) in ein entsprechend vergrößertes neues Array kopiert.&lt;br /&gt;
&lt;br /&gt;
== Hashtabelle mit offener Adressierung (offenes Hashing) ==&lt;br /&gt;
[http://de.wikipedia.org/wiki/Hashtabelle#Hashing_mit_offener_Adressierung Wikipedia (de)]&lt;br /&gt;
[http://en.wikipedia.org/wiki/Open_addressing Wikipedia (en)]&lt;br /&gt;
&lt;br /&gt;
Optimistischer Ansatz: Kollisionen werden nicht so häufig auftreten.&lt;br /&gt;
&lt;br /&gt;
=== Idee ===&lt;br /&gt;
Wenn &amp;lt;tt&amp;gt;array[index]&amp;lt;/tt&amp;gt; durch Kollision bereits vergeben ist, probiere einen&lt;br /&gt;
anderen Index aus.&lt;br /&gt;
&lt;br /&gt;
* Das Array enthält pro Element höchstens ein (key,value)-Paar&lt;br /&gt;
* Das Array muss stets mindestens ''einen'' freien Platz haben (sonst gäbe es beim Ausprobieren anderer Indizes eine Endlosschleife). Es gilt immer &amp;lt;tt&amp;gt;self.size &amp;lt; self.capacity&amp;lt;/tt&amp;gt;. Dies war bei der vorigen Hash-Implementation mit linearer Verkettung nicht notwendig (aber im Sinne schneller zugriffszeiten trotzdem wünschenswert).&lt;br /&gt;
&lt;br /&gt;
=== Vorgehen bei Kollisionen ===&lt;br /&gt;
&lt;br /&gt;
==== Sequentielles Sondieren====&lt;br /&gt;
Probiere den nächsten Index: &amp;lt;tt&amp;gt;index = (index+1) % capacity&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Vorteil: einfach&lt;br /&gt;
* Nachteil: Clusterbildung&lt;br /&gt;
&lt;br /&gt;
Clusterbildung heißt, dass sich größere zusammenhängende Bereiche bilden die belegt sind, unterbrochen von Bereichen die komplett frei sind. Beim Versuche des Einfügens eines Elements an einen Platz, der schon belegt ist, muss jetzt das ganze Cluster sequentiell durchlaufen werden, bis ein freier Platz gefunden wird. Damit entspricht die Komplexität der Suche der mittleren Länge der belegten Bereiche, was sich entsprechend in einer langsamen Suche widerspiegelt.&lt;br /&gt;
&lt;br /&gt;
==== Doppeltes Hashing ====&lt;br /&gt;
[http://de.wikipedia.org/wiki/Doppel-Hashing Wikipedia (de)] [http://en.wikipedia.org/wiki/Double_hashing Wikipedia (en)]&lt;br /&gt;
&lt;br /&gt;
Bestimme einen neuen Index (bei Kollisionen) durch eine ''2. Hashfunktion''.&lt;br /&gt;
&lt;br /&gt;
Das doppelte Hashing wird typischerweise in der Praxis angewendet und liegt auch der Python Implementierung des Datentyps ''Dictionary'' (Syntax &amp;lt;tt&amp;gt;{'a':1, 'b':2, 'c':3}&amp;lt;/tt&amp;gt; zugrunde.&lt;br /&gt;
&lt;br /&gt;
Eine effiziente Implementierung dieses Datentyps ist für die Performance der Skriptsprache Python extrem wichtig, da z.B. beim Aufruf einer Funktion der auszuführunde Code in einem Dictionary unter dem Schlüssel ''Funktionsname'' nachgeschlagen wird oder die Werte lokaler Variablen innerhalb einer Funktion ebenfalls in einem Dictionary zu finden sind.&lt;br /&gt;
&lt;br /&gt;
Für die Implementierung in Python werden wieder die obigen Klassen &amp;lt;tt&amp;gt;HashNode&amp;lt;/tt&amp;gt; (das Attribut &amp;lt;tt&amp;gt;next&amp;lt;/tt&amp;gt; kann allerdings jetzt entfernt werden) und &amp;lt;tt&amp;gt;HashTable&amp;lt;/tt&amp;gt; benötigt, es folgen die angepassten Implementationen von &amp;lt;tt&amp;gt;__setitem&amp;lt;/tt&amp;gt; und &amp;lt;tt&amp;gt;__getitem__&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
  def __setitem__(self, key, value):&lt;br /&gt;
      h = hash(key)&lt;br /&gt;
      index = h % self.capacity&lt;br /&gt;
      while True:&lt;br /&gt;
          if self.array[index] is None or self.array[index].key is None:&lt;br /&gt;
               # das Feld ist frei (1. Abfrage)&lt;br /&gt;
               # oder das Feld ist als frei markiert (2. Abfrage)&lt;br /&gt;
               self.array[index] = HashNode(key, value)&lt;br /&gt;
               self.size +=1&lt;br /&gt;
               return&lt;br /&gt;
          if self.array[index].key == key:&lt;br /&gt;
               # Es gibt diesen Schlüssel schon,&lt;br /&gt;
               # überschreibe die Daten&lt;br /&gt;
               self.array[index].data = value&lt;br /&gt;
               return&lt;br /&gt;
          # Letzter Fall: Kollision =&amp;gt; neuer Index durch 2. Hashfunktion&lt;br /&gt;
          index = (5*index+1+h) % self.capacity&lt;br /&gt;
          h = h &amp;gt;&amp;gt; 5&lt;br /&gt;
&lt;br /&gt;
Die vorgestellte Implementierung orientiert sich an Pythons interner Dictionary Implementierung, der zugehörige Quelltext (mit ausführlichem Kommentar) findet sich unter [http://svn.python.org/view/*checkout*/python/trunk/Objects/dictobject.c dictobject.c Python Implementation (SVN)]&lt;br /&gt;
&lt;br /&gt;
===== Komplexität des offenen Hashings =====&lt;br /&gt;
&lt;br /&gt;
* Annahme: uniformes Hashing, das heißt alle Indizes haben gleiche Wahrscheinlichkeit&lt;br /&gt;
* Füllstand &amp;lt;math&amp;gt;\alpha = \frac{\text{size}}{\text{capacity}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* '''Erfolglose Suche''' (d.h. es wird entweder ein neues Element eingefügt oder ein &amp;lt;tt&amp;gt;KeyError&amp;lt;/tt&amp;gt; geworfen): Untere Schranke für die Komplexität ist &amp;lt;math&amp;gt;\Omega\left(\frac{1}{1-\alpha}\right)&amp;lt;/math&amp;gt; Schritte (= Anzahl der notwendigen index-Berechnungen).&lt;br /&gt;
* '''Erfolgreiche Suche''' &amp;lt;math&amp;gt;\Omega\left(\frac{1}{\alpha}\ln\left(\frac{1}{1-\alpha}\right)\right)&amp;lt;/math&amp;gt; Schritte.&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;5&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
! &amp;lt;math&amp;gt;\alpha&amp;lt;/math&amp;gt;&lt;br /&gt;
! 0.5&lt;br /&gt;
! 0.9&lt;br /&gt;
|- &lt;br /&gt;
| erfolglos&lt;br /&gt;
| 2.0&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| erfolgreich&lt;br /&gt;
| 1.4&lt;br /&gt;
| 2.6&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===== Wahl der Kapazität =====&lt;br /&gt;
In Python wird &amp;lt;tt&amp;gt;capacity&amp;lt;/tt&amp;gt; Aufgrund der obigen Beobachtung so gewählt, dass &amp;lt;math&amp;gt;\alpha \leq 2/3&amp;lt;/math&amp;gt;. Falls &amp;lt;math&amp;gt;\alpha&amp;lt;/math&amp;gt; größer werden sollte, verdopple die Kapazität und kopiere das alte array in das neue Array (analog zum dynamischen Array)&lt;br /&gt;
&lt;br /&gt;
In Python werden die Kapazitätsgrößen als Zweierpotenzen gewählt, also 4,8,16,32,...,&lt;br /&gt;
so dass &amp;lt;tt&amp;gt;h % self.capacity&amp;lt;/tt&amp;gt; nur die unteren Bits von &amp;lt;tt&amp;gt;h&amp;lt;/tt&amp;gt; benutzt.&lt;br /&gt;
&lt;br /&gt;
== Anwendung von Hashing ==&lt;br /&gt;
&lt;br /&gt;
* Hashtabelle, assoziatives Aray&lt;br /&gt;
* Sortieren in linearer Zeit (Übungsaufgabe 6.2)&lt;br /&gt;
* Suchen von Strings in Texten: Rabin-Karp-Algorithmus&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
=== Rabin Karp Algorithmus ===&lt;br /&gt;
[http://de.wikipedia.org/wiki/Rabin-Karp-Algorithmus Wikipedia (de)] [http://en.wikipedia.org/wiki/Rabin-Karp_string_search_algorithm Wikipedia (en)]&lt;br /&gt;
&lt;br /&gt;
In Textverarbeitungsanwendungen ist eine häufig benutzte Funktion die ''Search &amp;amp; Replace'' Funktionalität. Die Suche sollte in O(len(text)) möglich sein, aber ein naiver Algorithmus braucht O(len(text)*len(searchstring))&lt;br /&gt;
&lt;br /&gt;
==== Naive Implementierung der Suche ====&lt;br /&gt;
  def search(text, s):&lt;br /&gt;
      M, N = len(text), len(s)&lt;br /&gt;
      for k in range(M-N):&lt;br /&gt;
          if s==text[k:k+N]:   # O(N), da N Zeichen verglichen werden müssen&lt;br /&gt;
              return k&lt;br /&gt;
      return -1 #nicht gefunden&lt;br /&gt;
&lt;br /&gt;
==== Idee des Rabin Karp Algorithmus ====&lt;br /&gt;
Statt Vergleichen &amp;lt;tt&amp;gt;s==text[k:k+N]&amp;lt;/tt&amp;gt;, die O(N) benötigen da N Vergleiche der Buchstaben durchgeführt werden müssen, Vergleiche die Hashs von Suchstring und dem zu untersuchenden Textabschnitt: &amp;lt;tt&amp;gt;hash(s) == hash(text[k:k+N])&amp;lt;/tt&amp;gt;. Dabei muss natürlich &amp;lt;tt&amp;gt;hash(s)&amp;lt;/tt&amp;gt; nur einmal berechnet werden, wohingegen &amp;lt;tt&amp;gt;hash(text[k:k+N])&amp;lt;/tt&amp;gt; immer wieder neu berechnet werden muss. Damit der Vergleich O(1) sein kann, ist es deswegen erforderlich, eine solche Hashfunktion zu haben, die nicht alle Zeichen (das wäre O(N) ) einlesen muss, sondern die vorhergehende Hashfunktion mit einbezieht.&lt;br /&gt;
&lt;br /&gt;
Eine solche Hashfunktion heißt ''Running Hash'' und funktioniert analog zum ''Sliding Mean''.&lt;br /&gt;
&lt;br /&gt;
Die Running Hash Funktion berechnet in O(1) den hash von &amp;lt;tt&amp;gt;text[k+1:k+1+N]&amp;lt;/tt&amp;gt; ausgehend vom hash für &amp;lt;tt&amp;gt;text[k:k+N]&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Idee: Interpretiere den Text als Ziffern in einer base d Darstellung:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h_k = \text{text}[k]\cdot d^{N-1} + \text{text}[k]\cdot d^{N-2} + \cdots + \text{text}[k+N-1]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für die Basis 10 (Dezimalsystem) ergibt sich also&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h_k = \text{text}[k]\cdot {10}^{N-1} + \text{text}[k]\cdot {10}^{N-2} + \cdots + \text{text}[k+N-1]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Daraus folgt&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h_{k+1} = 10\cdot h_k - \text{text}[k]\cdot {10}^{N} + \text{text}[k+N]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Komplexität dieses Updates ist O(1), falls man &amp;lt;math&amp;gt;{10}^{N}&amp;lt;/math&amp;gt; vorberechnet hat.&lt;br /&gt;
&lt;br /&gt;
In der Realität wählt man dann d=32 und benutzt noch an einigen Stellen modulo Operationen, um die Zahlen nicht zu groß werden zu lassen.&lt;br /&gt;
&lt;br /&gt;
==== Implementation ====&lt;br /&gt;
  def searchRabinKarp(text, s):&lt;br /&gt;
      ht, hs, dN = 0, 0, 1&lt;br /&gt;
      M, N = len(text), len(s)&lt;br /&gt;
      d, q = 32, 33554393&lt;br /&gt;
      #q ist eine große Primzahl, aber so,&lt;br /&gt;
      #dass d*q &amp;lt; 2**32 (um Überlauf zu vermeiden)&lt;br /&gt;
      &lt;br /&gt;
      #Initialisierung      &lt;br /&gt;
      for k in range(N):&lt;br /&gt;
          ht = (ht*d + ord(text[k])) % q&lt;br /&gt;
          #ord() gibt die ASCIInummer des übergebenen Zeichens zurück&lt;br /&gt;
          ds = (hs*d + ord( s[k] )) % q&lt;br /&gt;
          dN = (dN*a) % q&lt;br /&gt;
      #Die Variablen sind jetzt wie folgt initialisiert:&lt;br /&gt;
      #ht = hash(text[0:N])&lt;br /&gt;
      #hs = hash(s)&lt;br /&gt;
      #dN = (d**N) % q&lt;br /&gt;
      &lt;br /&gt;
      #Hauptschleife&lt;br /&gt;
      k = 0 &lt;br /&gt;
      while k &amp;lt; M-N:&lt;br /&gt;
          if hs == ht and s==text[k:k+N]:&lt;br /&gt;
              return k # serch string an Position k gefunden&lt;br /&gt;
          if k+N &amp;lt; M:&lt;br /&gt;
              ht = (d*ht - dN * ord(text[k]) + dN*q + ord(text[k+N]) ) % q&lt;br /&gt;
          k +=1&lt;br /&gt;
      return -1  # search string nicht gefunden&lt;/div&gt;</summary>
		<author><name>Thorben</name></author>	</entry>

	<entry>
		<id>https://alda.iwr.uni-heidelberg.de/index.php?title=Hashing_und_assoziative_Arrays&amp;diff=1732</id>
		<title>Hashing und assoziative Arrays</title>
		<link rel="alternate" type="text/html" href="https://alda.iwr.uni-heidelberg.de/index.php?title=Hashing_und_assoziative_Arrays&amp;diff=1732"/>
				<updated>2008-06-10T22:28:19Z</updated>
		
		<summary type="html">&lt;p&gt;Thorben: /* Implementation in Python */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Mitschrift gibts [http://hci.iwr.uni-heidelberg.de/alda/images/AlDa.pdf hier] als PDF und [http://hci.iwr.uni-heidelberg.de/alda/images/Alda_source.pdf hier] gibts die TeX-Sourcen, leider als PDF weil man wohl keine .TeXs hochladen darf. Originale gibts auf Anfrage bei kirchner at cl dot uni minus heidelberg dot de. Wird das Package &amp;quot;listings&amp;quot; verwendet, das gibts bei [http://tug.ctan.org/tex-archive/macros/latex/contrib/listings/ http://tug.ctan.org/tex-archive/macros/latex/contrib/listings/] &lt;br /&gt;
&lt;br /&gt;
Tipp- und sonstige Fehler dürfen gerne verbessert und erneut hochgeladen werden, oder gebt mir per Email Bescheid, dann pflege ich die   Korrektur ein :)&lt;br /&gt;
&lt;br /&gt;
Ich Finde dein Aufschrieb sollte ins Wiki übetragen werden, das bietet auch alles, was   &lt;br /&gt;
du mit Latex machen kannst. Die Bäume kannst du z.B. mit Latex zeichnen, einen pro Seite und diese dann in eine png Datei umwandeln. Wie sowas geht kann man z.B. in den Quellen von doxygen oder mediawiki selbst nachlesen. Oder man zoomt rein und macht einen Screenshot :-)&lt;br /&gt;
&lt;br /&gt;
== Hashtabelle mit linearer Verkettung ==&lt;br /&gt;
Pessimistischer Ansatz: Kollisionen treten häufig auf, deshalb wird unter jedem&lt;br /&gt;
Hashindex gleich eine Liste angelegt, in der Einträge aufgenommen werden können.&lt;br /&gt;
&lt;br /&gt;
===Implementation in Python===&lt;br /&gt;
''HashNode'' ist eine Hilfsdatenstruktur, die Schlüssel und Wert speichert&lt;br /&gt;
und mit Hilfe von ''next'' eine verkettete Liste realisiert&lt;br /&gt;
  class HashNode:&lt;br /&gt;
      def __init__(self,key,data,next):&lt;br /&gt;
          self.key = key&lt;br /&gt;
          self.data = data&lt;br /&gt;
          self.next = next # Verkettung!&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Die eigentliche Hashtabelle wird in der Klasse ''HashTable'' implementiert:&lt;br /&gt;
  class HashTable:&lt;br /&gt;
      def __init__(self):&lt;br /&gt;
         self.capacity = ... # Geeignete Werte siehe unten&lt;br /&gt;
         self.size = 0&lt;br /&gt;
         self.array = [None]*self.capacity&lt;br /&gt;
&lt;br /&gt;
In Python ([http://docs.python.org/ref/sequence-types.html Python Docs zum Thema]) wird der Zugriffsoperator ''[ ]'' für eine Datenstruktur wie folgt (innerhalb einer Klasse) implementiert:&lt;br /&gt;
  def __setitem__(self, key, value)&lt;br /&gt;
&lt;br /&gt;
so dass im Programmtext dann folgende Syntax möglich ist: &amp;lt;tt&amp;gt;a[key] = value&amp;lt;/tt&amp;gt; (schreibender Zugriff auf &amp;lt;tt&amp;gt;a[key]&amp;lt;/tt&amp;gt;).&lt;br /&gt;
Analog wird der lesende Zugriff &amp;lt;tt&amp;gt;value = a[key]&amp;lt;/tt&amp;gt; wie folgt umgesetzt:&lt;br /&gt;
  def __getitem__(self, key, value)&lt;br /&gt;
&lt;br /&gt;
Implementierung der &amp;lt;tt&amp;gt;__setitem__&amp;lt;/tt&amp;gt;-Funktion in der &amp;lt;tt&amp;gt;HashTable&amp;lt;/tt&amp;gt;-Klasse:&lt;br /&gt;
  def __setitem__(self, key, value):&lt;br /&gt;
      index = hash(key) % self.capacity&lt;br /&gt;
      node = self.array[index]&lt;br /&gt;
      while node is not None:&lt;br /&gt;
          if node.key == key:&lt;br /&gt;
              # Element key ist schon in der Tabelle&lt;br /&gt;
              #Überschreibe die Daten mit dem neuen Wert&lt;br /&gt;
              node.data = value&lt;br /&gt;
              return&lt;br /&gt;
          # Kollision des Hashwerts, probiere nächsten Key aus&lt;br /&gt;
          node = node.next&lt;br /&gt;
      # Kein Element hatte den richtigen Schlüssel.&lt;br /&gt;
      # ==&amp;gt;Es gibt diesen Schlüssel noch nicht&lt;br /&gt;
      # Füge also ein neues Element in die Hashtabelle ein&lt;br /&gt;
       &lt;br /&gt;
      self.array[index] = HashNode(key, value, self.array[index])&lt;br /&gt;
      # Der alte Anfang der Liste wurde der Nachfolger des neu eingefügten&lt;br /&gt;
      # ersten Elements&lt;br /&gt;
       &lt;br /&gt;
      self.size += 1&lt;br /&gt;
&lt;br /&gt;
Und die Implementierung der &amp;lt;tt&amp;gt;__getitem__&amp;lt;/tt&amp;gt; Funktionen:&lt;br /&gt;
  def __getitem__(self, key):&lt;br /&gt;
      index = hash(key) % self.capacity&lt;br /&gt;
      node = self.array[index]&lt;br /&gt;
      while node is not None:&lt;br /&gt;
           if node.key == key: # Gefunden!&lt;br /&gt;
               return node.data&lt;br /&gt;
           node = node.next&lt;br /&gt;
      raise KeyError(key)&lt;br /&gt;
&lt;br /&gt;
==== Wahl der Kapazität ====&lt;br /&gt;
In der C++ Standardbibliothek (Klasse &amp;lt;tt&amp;gt; [http://www.sgi.com/tech/stl/hash_map.htmlstd::hash_map std::hash_map]&amp;lt;/tt&amp;gt;) wird die Hashtabelle häufig mit Hilfe der linearen Verkettung&lt;br /&gt;
imlementiert. Dabei wird &amp;lt;tt&amp;gt;capacity&amp;lt;/tt&amp;gt; immer als ''Primzahl'' gewählt, wobei sich aufeinanderfolgende Kapazitäten immer ungefähr verdoppeln:&lt;br /&gt;
  53, 97, 193, 398, 769, ...&lt;br /&gt;
[http://gcc.gnu.org/viewcvs/*checkout*/trunk/libstdc++-v3/src/hashtable.cc Gcc hashtable.cc (Primzahlen)] [http://gcc.gnu.org/viewcvs/*checkout*/trunk/libstdc++-v3/include/tr1_impl/hashtable_policy.h GCC Hash Implementation]&lt;br /&gt;
&lt;br /&gt;
Das hat zur Folge, dass &amp;lt;tt&amp;gt;hash(key) % self.capacity&amp;lt;/tt&amp;gt; ''alle'' Bits von h benutzt (Eigenschaft aus der Zahlentheorie). Die Kapizität wird vergrößert, wenn &amp;lt;tt&amp;gt;size == capacity&amp;lt;/tt&amp;gt; erreicht wird. Analog zum dynamischen Array werden die Daten dann aus dem alten Array (&amp;lt;tt&amp;gt;self.array&amp;lt;/tt&amp;gt;) in ein entsprechend vergrößertes neues Array kopiert.&lt;br /&gt;
&lt;br /&gt;
== Hashtabelle mit offener Adressierung (offenes Hashing) ==&lt;br /&gt;
[http://de.wikipedia.org/wiki/Hashtabelle#Hashing_mit_offener_Adressierung Wikipedia (de)]&lt;br /&gt;
[http://en.wikipedia.org/wiki/Open_addressing Wikipedia (en)]&lt;br /&gt;
&lt;br /&gt;
Optimistischer Ansatz: Kollisionen werden nicht so häufig auftreten.&lt;br /&gt;
&lt;br /&gt;
=== Idee ===&lt;br /&gt;
Wenn &amp;lt;tt&amp;gt;array[index]&amp;lt;/tt&amp;gt; durch Kollision bereits vergeben ist, probiere einen&lt;br /&gt;
anderen Index aus.&lt;br /&gt;
&lt;br /&gt;
* Das Array enthält pro Element höchstens ein (key,value)-Paar&lt;br /&gt;
* Das Array muss stets mindestens ''einen'' freien Platz haben (sonst gäbe es beim Ausprobieren anderer Indizes eine Endlosschleife). Es gilt immer &amp;lt;tt&amp;gt;self.size &amp;lt; self.capacity&amp;lt;/tt&amp;gt;. Dies war bei der vorigen Hash-Implementation mit linearer Verkettung nicht notwendig (aber im Sinne schneller zugriffszeiten trotzdem wünschenswert).&lt;br /&gt;
&lt;br /&gt;
=== Vorgehen bei Kollisionen ===&lt;br /&gt;
&lt;br /&gt;
==== Sequentielles Sondieren====&lt;br /&gt;
Probiere den nächsten Index: &amp;lt;tt&amp;gt;index = (index+1) % capacity&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Vorteil: einfach&lt;br /&gt;
* Nachteil: Clusterbildung&lt;br /&gt;
&lt;br /&gt;
Clusterbildung heißt, dass sich größere zusammenhängende Bereiche bilden die belegt sind, unterbrochen von Bereichen die komplett frei sind. Beim Versuche des Einfügens eines Elements an einen Platz, der schon belegt ist, muss jetzt das ganze Cluster sequentiell durchlaufen werden, bis ein freier Platz gefunden wird. Damit entspricht die Komplexität der Suche der mittleren Länge der belegten Bereiche, was sich entsprechend in einer langsamen Suche widerspiegelt.&lt;br /&gt;
&lt;br /&gt;
==== Doppeltes Hashing ====&lt;br /&gt;
[http://de.wikipedia.org/wiki/Doppel-Hashing Wikipedia (de)] [http://en.wikipedia.org/wiki/Double_hashing Wikipedia (en)]&lt;br /&gt;
&lt;br /&gt;
Bestimme einen neuen Index (bei Kollisionen) durch eine ''2. Hashfunktion''.&lt;br /&gt;
&lt;br /&gt;
Das doppelte Hashing wird typischerweise in der Praxis angewendet und liegt auch der Python Implementierung des Datentyps ''Dictionary'' (Syntax &amp;lt;tt&amp;gt;{'a':1, 'b':2, 'c':3}&amp;lt;/tt&amp;gt; zugrunde.&lt;br /&gt;
&lt;br /&gt;
Eine effiziente Implementierung dieses Datentyps ist für die Performance der Skriptsprache Python extrem wichtig, da z.B. beim Aufruf einer Funktion der auszuführunde Code in einem Dictionary unter dem Schlüssel ''Funktionsname'' nachgeschlagen wird oder die Werte lokaler Variablen innerhalb einer Funktion ebenfalls in einem Dictionary zu finden sind.&lt;br /&gt;
&lt;br /&gt;
Für die Implementierung in Python werden wieder die obigen Klassen &amp;lt;tt&amp;gt;HashNode&amp;lt;/tt&amp;gt; (das Attribut &amp;lt;tt&amp;gt;next&amp;lt;/tt&amp;gt; kann allerdings jetzt entfernt werden) und &amp;lt;tt&amp;gt;HashTable&amp;lt;/tt&amp;gt; benötigt, es folgen die angepassten Implementationen von &amp;lt;tt&amp;gt;__setitem&amp;lt;/tt&amp;gt; und &amp;lt;tt&amp;gt;__getitem__&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
  def __setitem__(self, key, value):&lt;br /&gt;
      h = hash(key)&lt;br /&gt;
      index = h % self.capacity&lt;br /&gt;
      while True:&lt;br /&gt;
          if self.array[index] is None or self.array[index].key is None:&lt;br /&gt;
               # das Feld ist frei (1. Abfrage)&lt;br /&gt;
               # oder das Feld ist als frei markiert (2. Abfrage)&lt;br /&gt;
               self.array[index] = HashNode(key, value)&lt;br /&gt;
               self.size +=1&lt;br /&gt;
               return&lt;br /&gt;
          if self.array[index].key == key:&lt;br /&gt;
               # Es gibt diesen Schlüssel schon,&lt;br /&gt;
               # überschreibe die Daten&lt;br /&gt;
               self.array[index].data = value&lt;br /&gt;
               return&lt;br /&gt;
          # Letzter Fall: Kollision =&amp;gt; neuer Index durch 2. Hashfunktion&lt;br /&gt;
          index = (5*index+1+h) % self.capacity&lt;br /&gt;
          h = h &amp;gt;&amp;gt; 5&lt;br /&gt;
&lt;br /&gt;
Die vorgestellte Implementierung orientiert sich an Pythons interner Dictionary Implementierung, der zugehörige Quelltext (mit ausführlichem Kommentar) findet sich unter [http://svn.python.org/view/*checkout*/python/trunk/Objects/dictobject.c dictobject.c Python Implementation (SVN)]&lt;br /&gt;
&lt;br /&gt;
===== Komplexität des offenen Hashings =====&lt;br /&gt;
&lt;br /&gt;
* Annahme: uniformes Hashing, das heißt alle Indizes haben gleiche Wahrscheinlichkeit&lt;br /&gt;
* Füllstand &amp;lt;math&amp;gt;\alpha = \frac{\text{size}}{\text{capacity}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* '''Erfolglose Suche''' (d.h. es wird entweder ein neues Element eingefügt oder ein &amp;lt;tt&amp;gt;KeyError&amp;lt;/tt&amp;gt; geworfen): Untere Schranke für die Komplexität ist &amp;lt;math&amp;gt;\Omega\left(\frac{1}{1-\alpha}\right)&amp;lt;/math&amp;gt; Schritte (= Anzahl der notwendigen index-Berechnungen).&lt;br /&gt;
* '''Erfolgreiche Suche''' &amp;lt;math&amp;gt;\Omega\left(\frac{1}{\alpha}\ln\left(\frac{1}{1-\alpha}\right)\right)&amp;lt;/math&amp;gt; Schritte.&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;5&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
! &amp;lt;math&amp;gt;\alpha&amp;lt;/math&amp;gt;&lt;br /&gt;
! 0.5&lt;br /&gt;
! 0.9&lt;br /&gt;
|- &lt;br /&gt;
| erfolglos&lt;br /&gt;
| 2.0&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| erfolgreich&lt;br /&gt;
| 1.4&lt;br /&gt;
| 2.6&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===== Wahl der Kapazität =====&lt;br /&gt;
In Python wird &amp;lt;tt&amp;gt;capacity&amp;lt;/tt&amp;gt; Aufgrund der obigen Beobachtung so gewählt, dass &amp;lt;math&amp;gt;\alpha \leq 2/3&amp;lt;/math&amp;gt;. Falls &amp;lt;math&amp;gt;\alpha&amp;lt;/math&amp;gt; größer werden sollte, verdopple die Kapazität und kopiere das alte array in das neue Array (analog zum dynamischen Array)&lt;br /&gt;
&lt;br /&gt;
In Python werden die Kapazitätsgrößen als Zweierpotenzen gewählt, also 4,8,16,32,...,&lt;br /&gt;
so dass &amp;lt;tt&amp;gt;h % self.capacity&amp;lt;/tt&amp;gt; nur die unteren Bits von &amp;lt;tt&amp;gt;h&amp;lt;/tt&amp;gt; benutzt.&lt;br /&gt;
&lt;br /&gt;
== Anwendung von Hashing ==&lt;br /&gt;
&lt;br /&gt;
* Hashtabelle, assoziatives Aray&lt;br /&gt;
* Sortieren in linearer Zeit (Übungsaufgabe 6.2)&lt;br /&gt;
* Suchen von Strings in Texten: Rabin-Karp-Algorithmus&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
=== Rabin Karp Algorithmus ===&lt;br /&gt;
[http://de.wikipedia.org/wiki/Rabin-Karp-Algorithmus Wikipedia (de)] [http://en.wikipedia.org/wiki/Rabin-Karp_string_search_algorithm Wikipedia (en)]&lt;br /&gt;
&lt;br /&gt;
In Textverarbeitungsanwendungen ist eine häufig benutzte Funktion die ''Search &amp;amp; Replace'' Funktionalität. Die Suche sollte in O(len(text)) möglich sein, aber ein naiver Algorithmus braucht O(len(text)*len(searchstring))&lt;br /&gt;
&lt;br /&gt;
==== Naive Implementierung der Suche ====&lt;br /&gt;
  def search(text, s):&lt;br /&gt;
      M, N = len(text), len(s)&lt;br /&gt;
      for k in range(M-N):&lt;br /&gt;
          if s==text[k:k+N]:   # O(N), da N Zeichen verglichen werden müssen&lt;br /&gt;
              return k&lt;br /&gt;
      return -1 #nicht gefunden&lt;br /&gt;
&lt;br /&gt;
==== Idee des Rabin Karp Algorithmus ====&lt;br /&gt;
Statt Vergleichen &amp;lt;tt&amp;gt;s==text[k:k+N]&amp;lt;/tt&amp;gt;, die O(N) benötigen da N Vergleiche der Buchstaben durchgeführt werden müssen, Vergleiche die Hashs von Suchstring und dem zu untersuchenden Textabschnitt: &amp;lt;tt&amp;gt;hash(s) == hash(text[k:k+N])&amp;lt;/tt&amp;gt;. Dabei muss natürlich &amp;lt;tt&amp;gt;hash(s)&amp;lt;/tt&amp;gt; nur einmal berechnet werden, wohingegen &amp;lt;tt&amp;gt;hash(text[k:k+N])&amp;lt;/tt&amp;gt; immer wieder neu berechnet werden muss. Damit der Vergleich O(1) sein kann, ist es deswegen erforderlich, eine solche Hashfunktion zu haben, die nicht alle Zeichen (das wäre O(N) ) einlesen muss, sondern die vorhergehende Hashfunktion mit einbezieht.&lt;br /&gt;
&lt;br /&gt;
Eine solche Hashfunktion heißt ''Running Hash'' und funktioniert analog zum ''Sliding Mean''.&lt;br /&gt;
&lt;br /&gt;
Die Running Hash Funktion berechnet in O(1) den hash von &amp;lt;tt&amp;gt;text[k+1:k+1+N]&amp;lt;/tt&amp;gt; ausgehend vom hash für &amp;lt;tt&amp;gt;text[k:k+N]&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Idee: Interpretiere den Text als Ziffern in einer base d Darstellung:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h_k = \text{text}[k]\cdot d^{N-1} + \text{text}[k]\cdot d^{N-2} + \cdots + \text{text}[k+N-1]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für die Basis 10 (Dezimalsystem) ergibt sich also&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h_k = \text{text}[k]\cdot {10}^{N-1} + \text{text}[k]\cdot {10}^{N-2} + \cdots + \text{text}[k+N-1]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Daraus folgt&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h_{k+1} = 10\cdot h_k - \text{text}[k]\cdot {10}^{N} + \text{text}[k+N]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Komplexität dieses Updates ist O(1), falls man &amp;lt;math&amp;gt;{10}^{N}&amp;lt;/math&amp;gt; vorberechnet hat.&lt;br /&gt;
&lt;br /&gt;
In der Realität wählt man dann d=32 und benutzt noch an einigen Stellen modulo Operationen, um die Zahlen nicht zu groß werden zu lassen.&lt;br /&gt;
&lt;br /&gt;
==== Implementation ====&lt;br /&gt;
  def searchRabinKarp(text, s):&lt;br /&gt;
      ht, hs, dN = 0, 0, 1&lt;br /&gt;
      M, N = len(text), len(s)&lt;br /&gt;
      d, q = 32, 33554393&lt;br /&gt;
      #q ist eine große Primzahl, aber so,&lt;br /&gt;
      #dass d*q &amp;lt; 2**32 (um Überlauf zu vermeiden)&lt;br /&gt;
      &lt;br /&gt;
      #Initialisierung      &lt;br /&gt;
      for k in range(N):&lt;br /&gt;
          ht = (ht*d + ord(text[k])) % q&lt;br /&gt;
          #ord() gibt die ASCIInummer des übergebenen Zeichens zurück&lt;br /&gt;
          ds = (hs*d + ord( s[k] )) % q&lt;br /&gt;
          dN = (dN*a) % q&lt;br /&gt;
      #Die Variablen sind jetzt wie folgt initialisiert:&lt;br /&gt;
      #ht = hash(text[0:N])&lt;br /&gt;
      #hs = hash(s)&lt;br /&gt;
      #dN = (d**N) % q&lt;br /&gt;
      &lt;br /&gt;
      #Hauptschleife&lt;br /&gt;
      k = 0 &lt;br /&gt;
      while k &amp;lt; M-N:&lt;br /&gt;
          if hs == ht and s==text[k:k+N]:&lt;br /&gt;
              return k # serch string an Position k gefunden&lt;br /&gt;
          if k+N &amp;lt; M:&lt;br /&gt;
              ht = (d*ht - dN * ord(text[k]) + dN*q + ord(text[k+N]) ) % q&lt;br /&gt;
          k +=1&lt;br /&gt;
      return -1  # search string nicht gefunden&lt;/div&gt;</summary>
		<author><name>Thorben</name></author>	</entry>

	<entry>
		<id>https://alda.iwr.uni-heidelberg.de/index.php?title=Hashing_und_assoziative_Arrays&amp;diff=1731</id>
		<title>Hashing und assoziative Arrays</title>
		<link rel="alternate" type="text/html" href="https://alda.iwr.uni-heidelberg.de/index.php?title=Hashing_und_assoziative_Arrays&amp;diff=1731"/>
				<updated>2008-06-10T22:28:00Z</updated>
		
		<summary type="html">&lt;p&gt;Thorben: /* Implementation in Python */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Mitschrift gibts [http://hci.iwr.uni-heidelberg.de/alda/images/AlDa.pdf hier] als PDF und [http://hci.iwr.uni-heidelberg.de/alda/images/Alda_source.pdf hier] gibts die TeX-Sourcen, leider als PDF weil man wohl keine .TeXs hochladen darf. Originale gibts auf Anfrage bei kirchner at cl dot uni minus heidelberg dot de. Wird das Package &amp;quot;listings&amp;quot; verwendet, das gibts bei [http://tug.ctan.org/tex-archive/macros/latex/contrib/listings/ http://tug.ctan.org/tex-archive/macros/latex/contrib/listings/] &lt;br /&gt;
&lt;br /&gt;
Tipp- und sonstige Fehler dürfen gerne verbessert und erneut hochgeladen werden, oder gebt mir per Email Bescheid, dann pflege ich die   Korrektur ein :)&lt;br /&gt;
&lt;br /&gt;
Ich Finde dein Aufschrieb sollte ins Wiki übetragen werden, das bietet auch alles, was   &lt;br /&gt;
du mit Latex machen kannst. Die Bäume kannst du z.B. mit Latex zeichnen, einen pro Seite und diese dann in eine png Datei umwandeln. Wie sowas geht kann man z.B. in den Quellen von doxygen oder mediawiki selbst nachlesen. Oder man zoomt rein und macht einen Screenshot :-)&lt;br /&gt;
&lt;br /&gt;
== Hashtabelle mit linearer Verkettung ==&lt;br /&gt;
Pessimistischer Ansatz: Kollisionen treten häufig auf, deshalb wird unter jedem&lt;br /&gt;
Hashindex gleich eine Liste angelegt, in der Einträge aufgenommen werden können.&lt;br /&gt;
&lt;br /&gt;
===Implementation in Python===&lt;br /&gt;
''HashNode'' ist eine Hilfsdatenstruktur, die Schlüssel und Wert speichert&lt;br /&gt;
und mit Hilfe von ''next'' eine verkettete Liste realisiert&lt;br /&gt;
  class HashNode:&lt;br /&gt;
      def __init__(self,key,data,next):&lt;br /&gt;
          self.key = key&lt;br /&gt;
          self.data = data&lt;br /&gt;
          self.next = next # Verkettung!&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Die eigentliche Hashtabelle wird in der Klasse ''HashTable'' implementiert:&lt;br /&gt;
  class HashTable:&lt;br /&gt;
      def __init__(self):&lt;br /&gt;
         self.capacity = ... # Geeignete Werte siehe unten&lt;br /&gt;
         self.size = 0&lt;br /&gt;
         self.array = [None]*self.capacity&lt;br /&gt;
&lt;br /&gt;
In Python ([ http://docs.python.org/ref/sequence-types.html Python Docs zum Thema]) wird der Zugriffsoperator ''[ ]'' für eine Datenstruktur wie folgt (innerhalb einer Klasse) implementiert:&lt;br /&gt;
  def __setitem__(self, key, value)&lt;br /&gt;
&lt;br /&gt;
so dass im Programmtext dann folgende Syntax möglich ist: &amp;lt;tt&amp;gt;a[key] = value&amp;lt;/tt&amp;gt; (schreibender Zugriff auf &amp;lt;tt&amp;gt;a[key]&amp;lt;/tt&amp;gt;).&lt;br /&gt;
Analog wird der lesende Zugriff &amp;lt;tt&amp;gt;value = a[key]&amp;lt;/tt&amp;gt; wie folgt umgesetzt:&lt;br /&gt;
  def __getitem__(self, key, value)&lt;br /&gt;
&lt;br /&gt;
Implementierung der &amp;lt;tt&amp;gt;__setitem__&amp;lt;/tt&amp;gt;-Funktion in der &amp;lt;tt&amp;gt;HashTable&amp;lt;/tt&amp;gt;-Klasse:&lt;br /&gt;
  def __setitem__(self, key, value):&lt;br /&gt;
      index = hash(key) % self.capacity&lt;br /&gt;
      node = self.array[index]&lt;br /&gt;
      while node is not None:&lt;br /&gt;
          if node.key == key:&lt;br /&gt;
              # Element key ist schon in der Tabelle&lt;br /&gt;
              #Überschreibe die Daten mit dem neuen Wert&lt;br /&gt;
              node.data = value&lt;br /&gt;
              return&lt;br /&gt;
          # Kollision des Hashwerts, probiere nächsten Key aus&lt;br /&gt;
          node = node.next&lt;br /&gt;
      # Kein Element hatte den richtigen Schlüssel.&lt;br /&gt;
      # ==&amp;gt;Es gibt diesen Schlüssel noch nicht&lt;br /&gt;
      # Füge also ein neues Element in die Hashtabelle ein&lt;br /&gt;
       &lt;br /&gt;
      self.array[index] = HashNode(key, value, self.array[index])&lt;br /&gt;
      # Der alte Anfang der Liste wurde der Nachfolger des neu eingefügten&lt;br /&gt;
      # ersten Elements&lt;br /&gt;
       &lt;br /&gt;
      self.size += 1&lt;br /&gt;
&lt;br /&gt;
Und die Implementierung der &amp;lt;tt&amp;gt;__getitem__&amp;lt;/tt&amp;gt; Funktionen:&lt;br /&gt;
  def __getitem__(self, key):&lt;br /&gt;
      index = hash(key) % self.capacity&lt;br /&gt;
      node = self.array[index]&lt;br /&gt;
      while node is not None:&lt;br /&gt;
           if node.key == key: # Gefunden!&lt;br /&gt;
               return node.data&lt;br /&gt;
           node = node.next&lt;br /&gt;
      raise KeyError(key)&lt;br /&gt;
&lt;br /&gt;
==== Wahl der Kapazität ====&lt;br /&gt;
In der C++ Standardbibliothek (Klasse &amp;lt;tt&amp;gt; [http://www.sgi.com/tech/stl/hash_map.htmlstd::hash_map std::hash_map]&amp;lt;/tt&amp;gt;) wird die Hashtabelle häufig mit Hilfe der linearen Verkettung&lt;br /&gt;
imlementiert. Dabei wird &amp;lt;tt&amp;gt;capacity&amp;lt;/tt&amp;gt; immer als ''Primzahl'' gewählt, wobei sich aufeinanderfolgende Kapazitäten immer ungefähr verdoppeln:&lt;br /&gt;
  53, 97, 193, 398, 769, ...&lt;br /&gt;
[http://gcc.gnu.org/viewcvs/*checkout*/trunk/libstdc++-v3/src/hashtable.cc Gcc hashtable.cc (Primzahlen)] [http://gcc.gnu.org/viewcvs/*checkout*/trunk/libstdc++-v3/include/tr1_impl/hashtable_policy.h GCC Hash Implementation]&lt;br /&gt;
&lt;br /&gt;
Das hat zur Folge, dass &amp;lt;tt&amp;gt;hash(key) % self.capacity&amp;lt;/tt&amp;gt; ''alle'' Bits von h benutzt (Eigenschaft aus der Zahlentheorie). Die Kapizität wird vergrößert, wenn &amp;lt;tt&amp;gt;size == capacity&amp;lt;/tt&amp;gt; erreicht wird. Analog zum dynamischen Array werden die Daten dann aus dem alten Array (&amp;lt;tt&amp;gt;self.array&amp;lt;/tt&amp;gt;) in ein entsprechend vergrößertes neues Array kopiert.&lt;br /&gt;
&lt;br /&gt;
== Hashtabelle mit offener Adressierung (offenes Hashing) ==&lt;br /&gt;
[http://de.wikipedia.org/wiki/Hashtabelle#Hashing_mit_offener_Adressierung Wikipedia (de)]&lt;br /&gt;
[http://en.wikipedia.org/wiki/Open_addressing Wikipedia (en)]&lt;br /&gt;
&lt;br /&gt;
Optimistischer Ansatz: Kollisionen werden nicht so häufig auftreten.&lt;br /&gt;
&lt;br /&gt;
=== Idee ===&lt;br /&gt;
Wenn &amp;lt;tt&amp;gt;array[index]&amp;lt;/tt&amp;gt; durch Kollision bereits vergeben ist, probiere einen&lt;br /&gt;
anderen Index aus.&lt;br /&gt;
&lt;br /&gt;
* Das Array enthält pro Element höchstens ein (key,value)-Paar&lt;br /&gt;
* Das Array muss stets mindestens ''einen'' freien Platz haben (sonst gäbe es beim Ausprobieren anderer Indizes eine Endlosschleife). Es gilt immer &amp;lt;tt&amp;gt;self.size &amp;lt; self.capacity&amp;lt;/tt&amp;gt;. Dies war bei der vorigen Hash-Implementation mit linearer Verkettung nicht notwendig (aber im Sinne schneller zugriffszeiten trotzdem wünschenswert).&lt;br /&gt;
&lt;br /&gt;
=== Vorgehen bei Kollisionen ===&lt;br /&gt;
&lt;br /&gt;
==== Sequentielles Sondieren====&lt;br /&gt;
Probiere den nächsten Index: &amp;lt;tt&amp;gt;index = (index+1) % capacity&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Vorteil: einfach&lt;br /&gt;
* Nachteil: Clusterbildung&lt;br /&gt;
&lt;br /&gt;
Clusterbildung heißt, dass sich größere zusammenhängende Bereiche bilden die belegt sind, unterbrochen von Bereichen die komplett frei sind. Beim Versuche des Einfügens eines Elements an einen Platz, der schon belegt ist, muss jetzt das ganze Cluster sequentiell durchlaufen werden, bis ein freier Platz gefunden wird. Damit entspricht die Komplexität der Suche der mittleren Länge der belegten Bereiche, was sich entsprechend in einer langsamen Suche widerspiegelt.&lt;br /&gt;
&lt;br /&gt;
==== Doppeltes Hashing ====&lt;br /&gt;
[http://de.wikipedia.org/wiki/Doppel-Hashing Wikipedia (de)] [http://en.wikipedia.org/wiki/Double_hashing Wikipedia (en)]&lt;br /&gt;
&lt;br /&gt;
Bestimme einen neuen Index (bei Kollisionen) durch eine ''2. Hashfunktion''.&lt;br /&gt;
&lt;br /&gt;
Das doppelte Hashing wird typischerweise in der Praxis angewendet und liegt auch der Python Implementierung des Datentyps ''Dictionary'' (Syntax &amp;lt;tt&amp;gt;{'a':1, 'b':2, 'c':3}&amp;lt;/tt&amp;gt; zugrunde.&lt;br /&gt;
&lt;br /&gt;
Eine effiziente Implementierung dieses Datentyps ist für die Performance der Skriptsprache Python extrem wichtig, da z.B. beim Aufruf einer Funktion der auszuführunde Code in einem Dictionary unter dem Schlüssel ''Funktionsname'' nachgeschlagen wird oder die Werte lokaler Variablen innerhalb einer Funktion ebenfalls in einem Dictionary zu finden sind.&lt;br /&gt;
&lt;br /&gt;
Für die Implementierung in Python werden wieder die obigen Klassen &amp;lt;tt&amp;gt;HashNode&amp;lt;/tt&amp;gt; (das Attribut &amp;lt;tt&amp;gt;next&amp;lt;/tt&amp;gt; kann allerdings jetzt entfernt werden) und &amp;lt;tt&amp;gt;HashTable&amp;lt;/tt&amp;gt; benötigt, es folgen die angepassten Implementationen von &amp;lt;tt&amp;gt;__setitem&amp;lt;/tt&amp;gt; und &amp;lt;tt&amp;gt;__getitem__&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
  def __setitem__(self, key, value):&lt;br /&gt;
      h = hash(key)&lt;br /&gt;
      index = h % self.capacity&lt;br /&gt;
      while True:&lt;br /&gt;
          if self.array[index] is None or self.array[index].key is None:&lt;br /&gt;
               # das Feld ist frei (1. Abfrage)&lt;br /&gt;
               # oder das Feld ist als frei markiert (2. Abfrage)&lt;br /&gt;
               self.array[index] = HashNode(key, value)&lt;br /&gt;
               self.size +=1&lt;br /&gt;
               return&lt;br /&gt;
          if self.array[index].key == key:&lt;br /&gt;
               # Es gibt diesen Schlüssel schon,&lt;br /&gt;
               # überschreibe die Daten&lt;br /&gt;
               self.array[index].data = value&lt;br /&gt;
               return&lt;br /&gt;
          # Letzter Fall: Kollision =&amp;gt; neuer Index durch 2. Hashfunktion&lt;br /&gt;
          index = (5*index+1+h) % self.capacity&lt;br /&gt;
          h = h &amp;gt;&amp;gt; 5&lt;br /&gt;
&lt;br /&gt;
Die vorgestellte Implementierung orientiert sich an Pythons interner Dictionary Implementierung, der zugehörige Quelltext (mit ausführlichem Kommentar) findet sich unter [http://svn.python.org/view/*checkout*/python/trunk/Objects/dictobject.c dictobject.c Python Implementation (SVN)]&lt;br /&gt;
&lt;br /&gt;
===== Komplexität des offenen Hashings =====&lt;br /&gt;
&lt;br /&gt;
* Annahme: uniformes Hashing, das heißt alle Indizes haben gleiche Wahrscheinlichkeit&lt;br /&gt;
* Füllstand &amp;lt;math&amp;gt;\alpha = \frac{\text{size}}{\text{capacity}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* '''Erfolglose Suche''' (d.h. es wird entweder ein neues Element eingefügt oder ein &amp;lt;tt&amp;gt;KeyError&amp;lt;/tt&amp;gt; geworfen): Untere Schranke für die Komplexität ist &amp;lt;math&amp;gt;\Omega\left(\frac{1}{1-\alpha}\right)&amp;lt;/math&amp;gt; Schritte (= Anzahl der notwendigen index-Berechnungen).&lt;br /&gt;
* '''Erfolgreiche Suche''' &amp;lt;math&amp;gt;\Omega\left(\frac{1}{\alpha}\ln\left(\frac{1}{1-\alpha}\right)\right)&amp;lt;/math&amp;gt; Schritte.&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;5&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
! &amp;lt;math&amp;gt;\alpha&amp;lt;/math&amp;gt;&lt;br /&gt;
! 0.5&lt;br /&gt;
! 0.9&lt;br /&gt;
|- &lt;br /&gt;
| erfolglos&lt;br /&gt;
| 2.0&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| erfolgreich&lt;br /&gt;
| 1.4&lt;br /&gt;
| 2.6&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===== Wahl der Kapazität =====&lt;br /&gt;
In Python wird &amp;lt;tt&amp;gt;capacity&amp;lt;/tt&amp;gt; Aufgrund der obigen Beobachtung so gewählt, dass &amp;lt;math&amp;gt;\alpha \leq 2/3&amp;lt;/math&amp;gt;. Falls &amp;lt;math&amp;gt;\alpha&amp;lt;/math&amp;gt; größer werden sollte, verdopple die Kapazität und kopiere das alte array in das neue Array (analog zum dynamischen Array)&lt;br /&gt;
&lt;br /&gt;
In Python werden die Kapazitätsgrößen als Zweierpotenzen gewählt, also 4,8,16,32,...,&lt;br /&gt;
so dass &amp;lt;tt&amp;gt;h % self.capacity&amp;lt;/tt&amp;gt; nur die unteren Bits von &amp;lt;tt&amp;gt;h&amp;lt;/tt&amp;gt; benutzt.&lt;br /&gt;
&lt;br /&gt;
== Anwendung von Hashing ==&lt;br /&gt;
&lt;br /&gt;
* Hashtabelle, assoziatives Aray&lt;br /&gt;
* Sortieren in linearer Zeit (Übungsaufgabe 6.2)&lt;br /&gt;
* Suchen von Strings in Texten: Rabin-Karp-Algorithmus&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
=== Rabin Karp Algorithmus ===&lt;br /&gt;
[http://de.wikipedia.org/wiki/Rabin-Karp-Algorithmus Wikipedia (de)] [http://en.wikipedia.org/wiki/Rabin-Karp_string_search_algorithm Wikipedia (en)]&lt;br /&gt;
&lt;br /&gt;
In Textverarbeitungsanwendungen ist eine häufig benutzte Funktion die ''Search &amp;amp; Replace'' Funktionalität. Die Suche sollte in O(len(text)) möglich sein, aber ein naiver Algorithmus braucht O(len(text)*len(searchstring))&lt;br /&gt;
&lt;br /&gt;
==== Naive Implementierung der Suche ====&lt;br /&gt;
  def search(text, s):&lt;br /&gt;
      M, N = len(text), len(s)&lt;br /&gt;
      for k in range(M-N):&lt;br /&gt;
          if s==text[k:k+N]:   # O(N), da N Zeichen verglichen werden müssen&lt;br /&gt;
              return k&lt;br /&gt;
      return -1 #nicht gefunden&lt;br /&gt;
&lt;br /&gt;
==== Idee des Rabin Karp Algorithmus ====&lt;br /&gt;
Statt Vergleichen &amp;lt;tt&amp;gt;s==text[k:k+N]&amp;lt;/tt&amp;gt;, die O(N) benötigen da N Vergleiche der Buchstaben durchgeführt werden müssen, Vergleiche die Hashs von Suchstring und dem zu untersuchenden Textabschnitt: &amp;lt;tt&amp;gt;hash(s) == hash(text[k:k+N])&amp;lt;/tt&amp;gt;. Dabei muss natürlich &amp;lt;tt&amp;gt;hash(s)&amp;lt;/tt&amp;gt; nur einmal berechnet werden, wohingegen &amp;lt;tt&amp;gt;hash(text[k:k+N])&amp;lt;/tt&amp;gt; immer wieder neu berechnet werden muss. Damit der Vergleich O(1) sein kann, ist es deswegen erforderlich, eine solche Hashfunktion zu haben, die nicht alle Zeichen (das wäre O(N) ) einlesen muss, sondern die vorhergehende Hashfunktion mit einbezieht.&lt;br /&gt;
&lt;br /&gt;
Eine solche Hashfunktion heißt ''Running Hash'' und funktioniert analog zum ''Sliding Mean''.&lt;br /&gt;
&lt;br /&gt;
Die Running Hash Funktion berechnet in O(1) den hash von &amp;lt;tt&amp;gt;text[k+1:k+1+N]&amp;lt;/tt&amp;gt; ausgehend vom hash für &amp;lt;tt&amp;gt;text[k:k+N]&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Idee: Interpretiere den Text als Ziffern in einer base d Darstellung:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h_k = \text{text}[k]\cdot d^{N-1} + \text{text}[k]\cdot d^{N-2} + \cdots + \text{text}[k+N-1]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für die Basis 10 (Dezimalsystem) ergibt sich also&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h_k = \text{text}[k]\cdot {10}^{N-1} + \text{text}[k]\cdot {10}^{N-2} + \cdots + \text{text}[k+N-1]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Daraus folgt&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h_{k+1} = 10\cdot h_k - \text{text}[k]\cdot {10}^{N} + \text{text}[k+N]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Komplexität dieses Updates ist O(1), falls man &amp;lt;math&amp;gt;{10}^{N}&amp;lt;/math&amp;gt; vorberechnet hat.&lt;br /&gt;
&lt;br /&gt;
In der Realität wählt man dann d=32 und benutzt noch an einigen Stellen modulo Operationen, um die Zahlen nicht zu groß werden zu lassen.&lt;br /&gt;
&lt;br /&gt;
==== Implementation ====&lt;br /&gt;
  def searchRabinKarp(text, s):&lt;br /&gt;
      ht, hs, dN = 0, 0, 1&lt;br /&gt;
      M, N = len(text), len(s)&lt;br /&gt;
      d, q = 32, 33554393&lt;br /&gt;
      #q ist eine große Primzahl, aber so,&lt;br /&gt;
      #dass d*q &amp;lt; 2**32 (um Überlauf zu vermeiden)&lt;br /&gt;
      &lt;br /&gt;
      #Initialisierung      &lt;br /&gt;
      for k in range(N):&lt;br /&gt;
          ht = (ht*d + ord(text[k])) % q&lt;br /&gt;
          #ord() gibt die ASCIInummer des übergebenen Zeichens zurück&lt;br /&gt;
          ds = (hs*d + ord( s[k] )) % q&lt;br /&gt;
          dN = (dN*a) % q&lt;br /&gt;
      #Die Variablen sind jetzt wie folgt initialisiert:&lt;br /&gt;
      #ht = hash(text[0:N])&lt;br /&gt;
      #hs = hash(s)&lt;br /&gt;
      #dN = (d**N) % q&lt;br /&gt;
      &lt;br /&gt;
      #Hauptschleife&lt;br /&gt;
      k = 0 &lt;br /&gt;
      while k &amp;lt; M-N:&lt;br /&gt;
          if hs == ht and s==text[k:k+N]:&lt;br /&gt;
              return k # serch string an Position k gefunden&lt;br /&gt;
          if k+N &amp;lt; M:&lt;br /&gt;
              ht = (d*ht - dN * ord(text[k]) + dN*q + ord(text[k+N]) ) % q&lt;br /&gt;
          k +=1&lt;br /&gt;
      return -1  # search string nicht gefunden&lt;/div&gt;</summary>
		<author><name>Thorben</name></author>	</entry>

	<entry>
		<id>https://alda.iwr.uni-heidelberg.de/index.php?title=Hashing_und_assoziative_Arrays&amp;diff=1730</id>
		<title>Hashing und assoziative Arrays</title>
		<link rel="alternate" type="text/html" href="https://alda.iwr.uni-heidelberg.de/index.php?title=Hashing_und_assoziative_Arrays&amp;diff=1730"/>
				<updated>2008-06-10T22:24:46Z</updated>
		
		<summary type="html">&lt;p&gt;Thorben: /* Wahl der Kapazität */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Mitschrift gibts [http://hci.iwr.uni-heidelberg.de/alda/images/AlDa.pdf hier] als PDF und [http://hci.iwr.uni-heidelberg.de/alda/images/Alda_source.pdf hier] gibts die TeX-Sourcen, leider als PDF weil man wohl keine .TeXs hochladen darf. Originale gibts auf Anfrage bei kirchner at cl dot uni minus heidelberg dot de. Wird das Package &amp;quot;listings&amp;quot; verwendet, das gibts bei [http://tug.ctan.org/tex-archive/macros/latex/contrib/listings/ http://tug.ctan.org/tex-archive/macros/latex/contrib/listings/] &lt;br /&gt;
&lt;br /&gt;
Tipp- und sonstige Fehler dürfen gerne verbessert und erneut hochgeladen werden, oder gebt mir per Email Bescheid, dann pflege ich die   Korrektur ein :)&lt;br /&gt;
&lt;br /&gt;
Ich Finde dein Aufschrieb sollte ins Wiki übetragen werden, das bietet auch alles, was   &lt;br /&gt;
du mit Latex machen kannst. Die Bäume kannst du z.B. mit Latex zeichnen, einen pro Seite und diese dann in eine png Datei umwandeln. Wie sowas geht kann man z.B. in den Quellen von doxygen oder mediawiki selbst nachlesen. Oder man zoomt rein und macht einen Screenshot :-)&lt;br /&gt;
&lt;br /&gt;
== Hashtabelle mit linearer Verkettung ==&lt;br /&gt;
Pessimistischer Ansatz: Kollisionen treten häufig auf, deshalb wird unter jedem&lt;br /&gt;
Hashindex gleich eine Liste angelegt, in der Einträge aufgenommen werden können.&lt;br /&gt;
&lt;br /&gt;
===Implementation in Python===&lt;br /&gt;
''HashNode'' ist eine Hilfsdatenstruktur, die Schlüssel und Wert speichert&lt;br /&gt;
und mit Hilfe von ''next'' eine verkettete Liste realisiert&lt;br /&gt;
  class HashNode:&lt;br /&gt;
      def __init__(self,key,data,next):&lt;br /&gt;
          self.key = key&lt;br /&gt;
          self.data = data&lt;br /&gt;
          self.next = next # Verkettung!&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Die eigentliche Hashtabelle wird in der Klasse ''HashTable'' implementiert:&lt;br /&gt;
  class HashTable:&lt;br /&gt;
      def __init__(self):&lt;br /&gt;
         self.capacity = ... # Geeignete Werte siehe unten&lt;br /&gt;
         self.size = 0&lt;br /&gt;
         self.array = [None]*self.capacity&lt;br /&gt;
&lt;br /&gt;
In Python wird der Zugriffsoperator ''[ ]'' für eine Datenstruktur wie folgt (innerhalb einer Klasse) implementiert:&lt;br /&gt;
  def __setitem__(self, key, value)&lt;br /&gt;
&lt;br /&gt;
so dass im Programmtext dann folgende Syntax möglich ist: &amp;lt;tt&amp;gt;a[key] = value&amp;lt;/tt&amp;gt; (schreibender Zugriff auf &amp;lt;tt&amp;gt;a[key]&amp;lt;/tt&amp;gt;).&lt;br /&gt;
Analog wird der lesende Zugriff &amp;lt;tt&amp;gt;value = a[key]&amp;lt;/tt&amp;gt; wie folgt umgesetzt:&lt;br /&gt;
  def __getitem__(self, key, value)&lt;br /&gt;
&lt;br /&gt;
Implementierung der &amp;lt;tt&amp;gt;__setitem__&amp;lt;/tt&amp;gt;-Funktion in der &amp;lt;tt&amp;gt;HashTable&amp;lt;/tt&amp;gt;-Klasse:&lt;br /&gt;
  def __setitem__(self, key, value):&lt;br /&gt;
      index = hash(key) % self.capacity&lt;br /&gt;
      node = self.array[index]&lt;br /&gt;
      while node is not None:&lt;br /&gt;
          if node.key == key:&lt;br /&gt;
              # Element key ist schon in der Tabelle&lt;br /&gt;
              #Überschreibe die Daten mit dem neuen Wert&lt;br /&gt;
              node.data = value&lt;br /&gt;
              return&lt;br /&gt;
          # Kollision des Hashwerts, probiere nächsten Key aus&lt;br /&gt;
          node = node.next&lt;br /&gt;
      # Kein Element hatte den richtigen Schlüssel.&lt;br /&gt;
      # ==&amp;gt;Es gibt diesen Schlüssel noch nicht&lt;br /&gt;
      # Füge also ein neues Element in die Hashtabelle ein&lt;br /&gt;
       &lt;br /&gt;
      self.array[index] = HashNode(key, value, self.array[index])&lt;br /&gt;
      # Der alte Anfang der Liste wurde der Nachfolger des neu eingefügten&lt;br /&gt;
      # ersten Elements&lt;br /&gt;
       &lt;br /&gt;
      self.size += 1&lt;br /&gt;
&lt;br /&gt;
Und die Implementierung der &amp;lt;tt&amp;gt;__getitem__&amp;lt;/tt&amp;gt; Funktionen:&lt;br /&gt;
  def __getitem__(self, key):&lt;br /&gt;
      index = hash(key) % self.capacity&lt;br /&gt;
      node = self.array[index]&lt;br /&gt;
      while node is not None:&lt;br /&gt;
           if node.key == key: # Gefunden!&lt;br /&gt;
               return node.data&lt;br /&gt;
           node = node.next&lt;br /&gt;
      raise KeyError(key)&lt;br /&gt;
&lt;br /&gt;
==== Wahl der Kapazität ====&lt;br /&gt;
In der C++ Standardbibliothek (Klasse &amp;lt;tt&amp;gt; [http://www.sgi.com/tech/stl/hash_map.htmlstd::hash_map std::hash_map]&amp;lt;/tt&amp;gt;) wird die Hashtabelle häufig mit Hilfe der linearen Verkettung&lt;br /&gt;
imlementiert. Dabei wird &amp;lt;tt&amp;gt;capacity&amp;lt;/tt&amp;gt; immer als ''Primzahl'' gewählt, wobei sich aufeinanderfolgende Kapazitäten immer ungefähr verdoppeln:&lt;br /&gt;
  53, 97, 193, 398, 769, ...&lt;br /&gt;
[http://gcc.gnu.org/viewcvs/*checkout*/trunk/libstdc++-v3/src/hashtable.cc Gcc hashtable.cc (Primzahlen)] [http://gcc.gnu.org/viewcvs/*checkout*/trunk/libstdc++-v3/include/tr1_impl/hashtable_policy.h GCC Hash Implementation]&lt;br /&gt;
&lt;br /&gt;
Das hat zur Folge, dass &amp;lt;tt&amp;gt;hash(key) % self.capacity&amp;lt;/tt&amp;gt; ''alle'' Bits von h benutzt (Eigenschaft aus der Zahlentheorie). Die Kapizität wird vergrößert, wenn &amp;lt;tt&amp;gt;size == capacity&amp;lt;/tt&amp;gt; erreicht wird. Analog zum dynamischen Array werden die Daten dann aus dem alten Array (&amp;lt;tt&amp;gt;self.array&amp;lt;/tt&amp;gt;) in ein entsprechend vergrößertes neues Array kopiert.&lt;br /&gt;
&lt;br /&gt;
== Hashtabelle mit offener Adressierung (offenes Hashing) ==&lt;br /&gt;
[http://de.wikipedia.org/wiki/Hashtabelle#Hashing_mit_offener_Adressierung Wikipedia (de)]&lt;br /&gt;
[http://en.wikipedia.org/wiki/Open_addressing Wikipedia (en)]&lt;br /&gt;
&lt;br /&gt;
Optimistischer Ansatz: Kollisionen werden nicht so häufig auftreten.&lt;br /&gt;
&lt;br /&gt;
=== Idee ===&lt;br /&gt;
Wenn &amp;lt;tt&amp;gt;array[index]&amp;lt;/tt&amp;gt; durch Kollision bereits vergeben ist, probiere einen&lt;br /&gt;
anderen Index aus.&lt;br /&gt;
&lt;br /&gt;
* Das Array enthält pro Element höchstens ein (key,value)-Paar&lt;br /&gt;
* Das Array muss stets mindestens ''einen'' freien Platz haben (sonst gäbe es beim Ausprobieren anderer Indizes eine Endlosschleife). Es gilt immer &amp;lt;tt&amp;gt;self.size &amp;lt; self.capacity&amp;lt;/tt&amp;gt;. Dies war bei der vorigen Hash-Implementation mit linearer Verkettung nicht notwendig (aber im Sinne schneller zugriffszeiten trotzdem wünschenswert).&lt;br /&gt;
&lt;br /&gt;
=== Vorgehen bei Kollisionen ===&lt;br /&gt;
&lt;br /&gt;
==== Sequentielles Sondieren====&lt;br /&gt;
Probiere den nächsten Index: &amp;lt;tt&amp;gt;index = (index+1) % capacity&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Vorteil: einfach&lt;br /&gt;
* Nachteil: Clusterbildung&lt;br /&gt;
&lt;br /&gt;
Clusterbildung heißt, dass sich größere zusammenhängende Bereiche bilden die belegt sind, unterbrochen von Bereichen die komplett frei sind. Beim Versuche des Einfügens eines Elements an einen Platz, der schon belegt ist, muss jetzt das ganze Cluster sequentiell durchlaufen werden, bis ein freier Platz gefunden wird. Damit entspricht die Komplexität der Suche der mittleren Länge der belegten Bereiche, was sich entsprechend in einer langsamen Suche widerspiegelt.&lt;br /&gt;
&lt;br /&gt;
==== Doppeltes Hashing ====&lt;br /&gt;
[http://de.wikipedia.org/wiki/Doppel-Hashing Wikipedia (de)] [http://en.wikipedia.org/wiki/Double_hashing Wikipedia (en)]&lt;br /&gt;
&lt;br /&gt;
Bestimme einen neuen Index (bei Kollisionen) durch eine ''2. Hashfunktion''.&lt;br /&gt;
&lt;br /&gt;
Das doppelte Hashing wird typischerweise in der Praxis angewendet und liegt auch der Python Implementierung des Datentyps ''Dictionary'' (Syntax &amp;lt;tt&amp;gt;{'a':1, 'b':2, 'c':3}&amp;lt;/tt&amp;gt; zugrunde.&lt;br /&gt;
&lt;br /&gt;
Eine effiziente Implementierung dieses Datentyps ist für die Performance der Skriptsprache Python extrem wichtig, da z.B. beim Aufruf einer Funktion der auszuführunde Code in einem Dictionary unter dem Schlüssel ''Funktionsname'' nachgeschlagen wird oder die Werte lokaler Variablen innerhalb einer Funktion ebenfalls in einem Dictionary zu finden sind.&lt;br /&gt;
&lt;br /&gt;
Für die Implementierung in Python werden wieder die obigen Klassen &amp;lt;tt&amp;gt;HashNode&amp;lt;/tt&amp;gt; (das Attribut &amp;lt;tt&amp;gt;next&amp;lt;/tt&amp;gt; kann allerdings jetzt entfernt werden) und &amp;lt;tt&amp;gt;HashTable&amp;lt;/tt&amp;gt; benötigt, es folgen die angepassten Implementationen von &amp;lt;tt&amp;gt;__setitem&amp;lt;/tt&amp;gt; und &amp;lt;tt&amp;gt;__getitem__&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
  def __setitem__(self, key, value):&lt;br /&gt;
      h = hash(key)&lt;br /&gt;
      index = h % self.capacity&lt;br /&gt;
      while True:&lt;br /&gt;
          if self.array[index] is None or self.array[index].key is None:&lt;br /&gt;
               # das Feld ist frei (1. Abfrage)&lt;br /&gt;
               # oder das Feld ist als frei markiert (2. Abfrage)&lt;br /&gt;
               self.array[index] = HashNode(key, value)&lt;br /&gt;
               self.size +=1&lt;br /&gt;
               return&lt;br /&gt;
          if self.array[index].key == key:&lt;br /&gt;
               # Es gibt diesen Schlüssel schon,&lt;br /&gt;
               # überschreibe die Daten&lt;br /&gt;
               self.array[index].data = value&lt;br /&gt;
               return&lt;br /&gt;
          # Letzter Fall: Kollision =&amp;gt; neuer Index durch 2. Hashfunktion&lt;br /&gt;
          index = (5*index+1+h) % self.capacity&lt;br /&gt;
          h = h &amp;gt;&amp;gt; 5&lt;br /&gt;
&lt;br /&gt;
Die vorgestellte Implementierung orientiert sich an Pythons interner Dictionary Implementierung, der zugehörige Quelltext (mit ausführlichem Kommentar) findet sich unter [http://svn.python.org/view/*checkout*/python/trunk/Objects/dictobject.c dictobject.c Python Implementation (SVN)]&lt;br /&gt;
&lt;br /&gt;
===== Komplexität des offenen Hashings =====&lt;br /&gt;
&lt;br /&gt;
* Annahme: uniformes Hashing, das heißt alle Indizes haben gleiche Wahrscheinlichkeit&lt;br /&gt;
* Füllstand &amp;lt;math&amp;gt;\alpha = \frac{\text{size}}{\text{capacity}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* '''Erfolglose Suche''' (d.h. es wird entweder ein neues Element eingefügt oder ein &amp;lt;tt&amp;gt;KeyError&amp;lt;/tt&amp;gt; geworfen): Untere Schranke für die Komplexität ist &amp;lt;math&amp;gt;\Omega\left(\frac{1}{1-\alpha}\right)&amp;lt;/math&amp;gt; Schritte (= Anzahl der notwendigen index-Berechnungen).&lt;br /&gt;
* '''Erfolgreiche Suche''' &amp;lt;math&amp;gt;\Omega\left(\frac{1}{\alpha}\ln\left(\frac{1}{1-\alpha}\right)\right)&amp;lt;/math&amp;gt; Schritte.&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;5&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
! &amp;lt;math&amp;gt;\alpha&amp;lt;/math&amp;gt;&lt;br /&gt;
! 0.5&lt;br /&gt;
! 0.9&lt;br /&gt;
|- &lt;br /&gt;
| erfolglos&lt;br /&gt;
| 2.0&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| erfolgreich&lt;br /&gt;
| 1.4&lt;br /&gt;
| 2.6&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===== Wahl der Kapazität =====&lt;br /&gt;
In Python wird &amp;lt;tt&amp;gt;capacity&amp;lt;/tt&amp;gt; Aufgrund der obigen Beobachtung so gewählt, dass &amp;lt;math&amp;gt;\alpha \leq 2/3&amp;lt;/math&amp;gt;. Falls &amp;lt;math&amp;gt;\alpha&amp;lt;/math&amp;gt; größer werden sollte, verdopple die Kapazität und kopiere das alte array in das neue Array (analog zum dynamischen Array)&lt;br /&gt;
&lt;br /&gt;
In Python werden die Kapazitätsgrößen als Zweierpotenzen gewählt, also 4,8,16,32,...,&lt;br /&gt;
so dass &amp;lt;tt&amp;gt;h % self.capacity&amp;lt;/tt&amp;gt; nur die unteren Bits von &amp;lt;tt&amp;gt;h&amp;lt;/tt&amp;gt; benutzt.&lt;br /&gt;
&lt;br /&gt;
== Anwendung von Hashing ==&lt;br /&gt;
&lt;br /&gt;
* Hashtabelle, assoziatives Aray&lt;br /&gt;
* Sortieren in linearer Zeit (Übungsaufgabe 6.2)&lt;br /&gt;
* Suchen von Strings in Texten: Rabin-Karp-Algorithmus&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
=== Rabin Karp Algorithmus ===&lt;br /&gt;
[http://de.wikipedia.org/wiki/Rabin-Karp-Algorithmus Wikipedia (de)] [http://en.wikipedia.org/wiki/Rabin-Karp_string_search_algorithm Wikipedia (en)]&lt;br /&gt;
&lt;br /&gt;
In Textverarbeitungsanwendungen ist eine häufig benutzte Funktion die ''Search &amp;amp; Replace'' Funktionalität. Die Suche sollte in O(len(text)) möglich sein, aber ein naiver Algorithmus braucht O(len(text)*len(searchstring))&lt;br /&gt;
&lt;br /&gt;
==== Naive Implementierung der Suche ====&lt;br /&gt;
  def search(text, s):&lt;br /&gt;
      M, N = len(text), len(s)&lt;br /&gt;
      for k in range(M-N):&lt;br /&gt;
          if s==text[k:k+N]:   # O(N), da N Zeichen verglichen werden müssen&lt;br /&gt;
              return k&lt;br /&gt;
      return -1 #nicht gefunden&lt;br /&gt;
&lt;br /&gt;
==== Idee des Rabin Karp Algorithmus ====&lt;br /&gt;
Statt Vergleichen &amp;lt;tt&amp;gt;s==text[k:k+N]&amp;lt;/tt&amp;gt;, die O(N) benötigen da N Vergleiche der Buchstaben durchgeführt werden müssen, Vergleiche die Hashs von Suchstring und dem zu untersuchenden Textabschnitt: &amp;lt;tt&amp;gt;hash(s) == hash(text[k:k+N])&amp;lt;/tt&amp;gt;. Dabei muss natürlich &amp;lt;tt&amp;gt;hash(s)&amp;lt;/tt&amp;gt; nur einmal berechnet werden, wohingegen &amp;lt;tt&amp;gt;hash(text[k:k+N])&amp;lt;/tt&amp;gt; immer wieder neu berechnet werden muss. Damit der Vergleich O(1) sein kann, ist es deswegen erforderlich, eine solche Hashfunktion zu haben, die nicht alle Zeichen (das wäre O(N) ) einlesen muss, sondern die vorhergehende Hashfunktion mit einbezieht.&lt;br /&gt;
&lt;br /&gt;
Eine solche Hashfunktion heißt ''Running Hash'' und funktioniert analog zum ''Sliding Mean''.&lt;br /&gt;
&lt;br /&gt;
Die Running Hash Funktion berechnet in O(1) den hash von &amp;lt;tt&amp;gt;text[k+1:k+1+N]&amp;lt;/tt&amp;gt; ausgehend vom hash für &amp;lt;tt&amp;gt;text[k:k+N]&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Idee: Interpretiere den Text als Ziffern in einer base d Darstellung:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h_k = \text{text}[k]\cdot d^{N-1} + \text{text}[k]\cdot d^{N-2} + \cdots + \text{text}[k+N-1]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für die Basis 10 (Dezimalsystem) ergibt sich also&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h_k = \text{text}[k]\cdot {10}^{N-1} + \text{text}[k]\cdot {10}^{N-2} + \cdots + \text{text}[k+N-1]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Daraus folgt&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h_{k+1} = 10\cdot h_k - \text{text}[k]\cdot {10}^{N} + \text{text}[k+N]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Komplexität dieses Updates ist O(1), falls man &amp;lt;math&amp;gt;{10}^{N}&amp;lt;/math&amp;gt; vorberechnet hat.&lt;br /&gt;
&lt;br /&gt;
In der Realität wählt man dann d=32 und benutzt noch an einigen Stellen modulo Operationen, um die Zahlen nicht zu groß werden zu lassen.&lt;br /&gt;
&lt;br /&gt;
==== Implementation ====&lt;br /&gt;
  def searchRabinKarp(text, s):&lt;br /&gt;
      ht, hs, dN = 0, 0, 1&lt;br /&gt;
      M, N = len(text), len(s)&lt;br /&gt;
      d, q = 32, 33554393&lt;br /&gt;
      #q ist eine große Primzahl, aber so,&lt;br /&gt;
      #dass d*q &amp;lt; 2**32 (um Überlauf zu vermeiden)&lt;br /&gt;
      &lt;br /&gt;
      #Initialisierung      &lt;br /&gt;
      for k in range(N):&lt;br /&gt;
          ht = (ht*d + ord(text[k])) % q&lt;br /&gt;
          #ord() gibt die ASCIInummer des übergebenen Zeichens zurück&lt;br /&gt;
          ds = (hs*d + ord( s[k] )) % q&lt;br /&gt;
          dN = (dN*a) % q&lt;br /&gt;
      #Die Variablen sind jetzt wie folgt initialisiert:&lt;br /&gt;
      #ht = hash(text[0:N])&lt;br /&gt;
      #hs = hash(s)&lt;br /&gt;
      #dN = (d**N) % q&lt;br /&gt;
      &lt;br /&gt;
      #Hauptschleife&lt;br /&gt;
      k = 0 &lt;br /&gt;
      while k &amp;lt; M-N:&lt;br /&gt;
          if hs == ht and s==text[k:k+N]:&lt;br /&gt;
              return k # serch string an Position k gefunden&lt;br /&gt;
          if k+N &amp;lt; M:&lt;br /&gt;
              ht = (d*ht - dN * ord(text[k]) + dN*q + ord(text[k+N]) ) % q&lt;br /&gt;
          k +=1&lt;br /&gt;
      return -1  # search string nicht gefunden&lt;/div&gt;</summary>
		<author><name>Thorben</name></author>	</entry>

	<entry>
		<id>https://alda.iwr.uni-heidelberg.de/index.php?title=Hashing_und_assoziative_Arrays&amp;diff=1729</id>
		<title>Hashing und assoziative Arrays</title>
		<link rel="alternate" type="text/html" href="https://alda.iwr.uni-heidelberg.de/index.php?title=Hashing_und_assoziative_Arrays&amp;diff=1729"/>
				<updated>2008-06-10T21:47:13Z</updated>
		
		<summary type="html">&lt;p&gt;Thorben: /* Implementation */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Mitschrift gibts [http://hci.iwr.uni-heidelberg.de/alda/images/AlDa.pdf hier] als PDF und [http://hci.iwr.uni-heidelberg.de/alda/images/Alda_source.pdf hier] gibts die TeX-Sourcen, leider als PDF weil man wohl keine .TeXs hochladen darf. Originale gibts auf Anfrage bei kirchner at cl dot uni minus heidelberg dot de. Wird das Package &amp;quot;listings&amp;quot; verwendet, das gibts bei [http://tug.ctan.org/tex-archive/macros/latex/contrib/listings/ http://tug.ctan.org/tex-archive/macros/latex/contrib/listings/] &lt;br /&gt;
&lt;br /&gt;
Tipp- und sonstige Fehler dürfen gerne verbessert und erneut hochgeladen werden, oder gebt mir per Email Bescheid, dann pflege ich die   Korrektur ein :)&lt;br /&gt;
&lt;br /&gt;
Ich Finde dein Aufschrieb sollte ins Wiki übetragen werden, das bietet auch alles, was   &lt;br /&gt;
du mit Latex machen kannst. Die Bäume kannst du z.B. mit Latex zeichnen, einen pro Seite und diese dann in eine png Datei umwandeln. Wie sowas geht kann man z.B. in den Quellen von doxygen oder mediawiki selbst nachlesen. Oder man zoomt rein und macht einen Screenshot :-)&lt;br /&gt;
&lt;br /&gt;
== Hashtabelle mit linearer Verkettung ==&lt;br /&gt;
Pessimistischer Ansatz: Kollisionen treten häufig auf, deshalb wird unter jedem&lt;br /&gt;
Hashindex gleich eine Liste angelegt, in der Einträge aufgenommen werden können.&lt;br /&gt;
&lt;br /&gt;
===Implementation in Python===&lt;br /&gt;
''HashNode'' ist eine Hilfsdatenstruktur, die Schlüssel und Wert speichert&lt;br /&gt;
und mit Hilfe von ''next'' eine verkettete Liste realisiert&lt;br /&gt;
  class HashNode:&lt;br /&gt;
      def __init__(self,key,data,next):&lt;br /&gt;
          self.key = key&lt;br /&gt;
          self.data = data&lt;br /&gt;
          self.next = next # Verkettung!&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Die eigentliche Hashtabelle wird in der Klasse ''HashTable'' implementiert:&lt;br /&gt;
  class HashTable:&lt;br /&gt;
      def __init__(self):&lt;br /&gt;
         self.capacity = ... # Geeignete Werte siehe unten&lt;br /&gt;
         self.size = 0&lt;br /&gt;
         self.array = [None]*self.capacity&lt;br /&gt;
&lt;br /&gt;
In Python wird der Zugriffsoperator ''[ ]'' für eine Datenstruktur wie folgt (innerhalb einer Klasse) implementiert:&lt;br /&gt;
  def __setitem__(self, key, value)&lt;br /&gt;
&lt;br /&gt;
so dass im Programmtext dann folgende Syntax möglich ist: &amp;lt;tt&amp;gt;a[key] = value&amp;lt;/tt&amp;gt; (schreibender Zugriff auf &amp;lt;tt&amp;gt;a[key]&amp;lt;/tt&amp;gt;).&lt;br /&gt;
Analog wird der lesende Zugriff &amp;lt;tt&amp;gt;value = a[key]&amp;lt;/tt&amp;gt; wie folgt umgesetzt:&lt;br /&gt;
  def __getitem__(self, key, value)&lt;br /&gt;
&lt;br /&gt;
Implementierung der &amp;lt;tt&amp;gt;__setitem__&amp;lt;/tt&amp;gt;-Funktion in der &amp;lt;tt&amp;gt;HashTable&amp;lt;/tt&amp;gt;-Klasse:&lt;br /&gt;
  def __setitem__(self, key, value):&lt;br /&gt;
      index = hash(key) % self.capacity&lt;br /&gt;
      node = self.array[index]&lt;br /&gt;
      while node is not None:&lt;br /&gt;
          if node.key == key:&lt;br /&gt;
              # Element key ist schon in der Tabelle&lt;br /&gt;
              #Überschreibe die Daten mit dem neuen Wert&lt;br /&gt;
              node.data = value&lt;br /&gt;
              return&lt;br /&gt;
          # Kollision des Hashwerts, probiere nächsten Key aus&lt;br /&gt;
          node = node.next&lt;br /&gt;
      # Kein Element hatte den richtigen Schlüssel.&lt;br /&gt;
      # ==&amp;gt;Es gibt diesen Schlüssel noch nicht&lt;br /&gt;
      # Füge also ein neues Element in die Hashtabelle ein&lt;br /&gt;
       &lt;br /&gt;
      self.array[index] = HashNode(key, value, self.array[index])&lt;br /&gt;
      # Der alte Anfang der Liste wurde der Nachfolger des neu eingefügten&lt;br /&gt;
      # ersten Elements&lt;br /&gt;
       &lt;br /&gt;
      self.size += 1&lt;br /&gt;
&lt;br /&gt;
Und die Implementierung der &amp;lt;tt&amp;gt;__getitem__&amp;lt;/tt&amp;gt; Funktionen:&lt;br /&gt;
  def __getitem__(self, key):&lt;br /&gt;
      index = hash(key) % self.capacity&lt;br /&gt;
      node = self.array[index]&lt;br /&gt;
      while node is not None:&lt;br /&gt;
           if node.key == key: # Gefunden!&lt;br /&gt;
               return node.data&lt;br /&gt;
           node = node.next&lt;br /&gt;
      raise KeyError(key)&lt;br /&gt;
&lt;br /&gt;
==== Wahl der Kapazität ====&lt;br /&gt;
In der C++ Standardbibliothek (Klasse &amp;lt;tt&amp;gt;std::hash_map&amp;lt;/tt&amp;gt;) wird die Hashtabelle häufig mit Hilfe der linearen Verkettung&lt;br /&gt;
imlementiert. Dabei wird &amp;lt;tt&amp;gt;capacity&amp;lt;/tt&amp;gt; immer als ''Primzahl'' gewählt, wobei sich aufeinanderfolgende Kapazitäten immer ungefähr verdoppeln:&lt;br /&gt;
  53, 97, 193, 398, 769, ...&lt;br /&gt;
&lt;br /&gt;
Das hat zur Folge, dass &amp;lt;tt&amp;gt;hash(key) % self.capacity&amp;lt;/tt&amp;gt; ''alle'' Bits von h benutzt (Eigenschaft aus der Zahlentheorie). Die Kapizität wird vergrößert, wenn &amp;lt;tt&amp;gt;size == capacity&amp;lt;/tt&amp;gt; erreicht wird. Analog zum dynamischen Array werden die Daten dann aus dem alten Array (&amp;lt;tt&amp;gt;self.array&amp;lt;/tt&amp;gt;) in ein entsprechend vergrößertes neues Array kopiert.&lt;br /&gt;
&lt;br /&gt;
== Hashtabelle mit offener Adressierung (offenes Hashing) ==&lt;br /&gt;
[http://de.wikipedia.org/wiki/Hashtabelle#Hashing_mit_offener_Adressierung Wikipedia (de)]&lt;br /&gt;
[http://en.wikipedia.org/wiki/Open_addressing Wikipedia (en)]&lt;br /&gt;
&lt;br /&gt;
Optimistischer Ansatz: Kollisionen werden nicht so häufig auftreten.&lt;br /&gt;
&lt;br /&gt;
=== Idee ===&lt;br /&gt;
Wenn &amp;lt;tt&amp;gt;array[index]&amp;lt;/tt&amp;gt; durch Kollision bereits vergeben ist, probiere einen&lt;br /&gt;
anderen Index aus.&lt;br /&gt;
&lt;br /&gt;
* Das Array enthält pro Element höchstens ein (key,value)-Paar&lt;br /&gt;
* Das Array muss stets mindestens ''einen'' freien Platz haben (sonst gäbe es beim Ausprobieren anderer Indizes eine Endlosschleife). Es gilt immer &amp;lt;tt&amp;gt;self.size &amp;lt; self.capacity&amp;lt;/tt&amp;gt;. Dies war bei der vorigen Hash-Implementation mit linearer Verkettung nicht notwendig (aber im Sinne schneller zugriffszeiten trotzdem wünschenswert).&lt;br /&gt;
&lt;br /&gt;
=== Vorgehen bei Kollisionen ===&lt;br /&gt;
&lt;br /&gt;
==== Sequentielles Sondieren====&lt;br /&gt;
Probiere den nächsten Index: &amp;lt;tt&amp;gt;index = (index+1) % capacity&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Vorteil: einfach&lt;br /&gt;
* Nachteil: Clusterbildung&lt;br /&gt;
&lt;br /&gt;
Clusterbildung heißt, dass sich größere zusammenhängende Bereiche bilden die belegt sind, unterbrochen von Bereichen die komplett frei sind. Beim Versuche des Einfügens eines Elements an einen Platz, der schon belegt ist, muss jetzt das ganze Cluster sequentiell durchlaufen werden, bis ein freier Platz gefunden wird. Damit entspricht die Komplexität der Suche der mittleren Länge der belegten Bereiche, was sich entsprechend in einer langsamen Suche widerspiegelt.&lt;br /&gt;
&lt;br /&gt;
==== Doppeltes Hashing ====&lt;br /&gt;
[http://de.wikipedia.org/wiki/Doppel-Hashing Wikipedia (de)] [http://en.wikipedia.org/wiki/Double_hashing Wikipedia (en)]&lt;br /&gt;
&lt;br /&gt;
Bestimme einen neuen Index (bei Kollisionen) durch eine ''2. Hashfunktion''.&lt;br /&gt;
&lt;br /&gt;
Das doppelte Hashing wird typischerweise in der Praxis angewendet und liegt auch der Python Implementierung des Datentyps ''Dictionary'' (Syntax &amp;lt;tt&amp;gt;{'a':1, 'b':2, 'c':3}&amp;lt;/tt&amp;gt; zugrunde.&lt;br /&gt;
&lt;br /&gt;
Eine effiziente Implementierung dieses Datentyps ist für die Performance der Skriptsprache Python extrem wichtig, da z.B. beim Aufruf einer Funktion der auszuführunde Code in einem Dictionary unter dem Schlüssel ''Funktionsname'' nachgeschlagen wird oder die Werte lokaler Variablen innerhalb einer Funktion ebenfalls in einem Dictionary zu finden sind.&lt;br /&gt;
&lt;br /&gt;
Für die Implementierung in Python werden wieder die obigen Klassen &amp;lt;tt&amp;gt;HashNode&amp;lt;/tt&amp;gt; (das Attribut &amp;lt;tt&amp;gt;next&amp;lt;/tt&amp;gt; kann allerdings jetzt entfernt werden) und &amp;lt;tt&amp;gt;HashTable&amp;lt;/tt&amp;gt; benötigt, es folgen die angepassten Implementationen von &amp;lt;tt&amp;gt;__setitem&amp;lt;/tt&amp;gt; und &amp;lt;tt&amp;gt;__getitem__&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
  def __setitem__(self, key, value):&lt;br /&gt;
      h = hash(key)&lt;br /&gt;
      index = h % self.capacity&lt;br /&gt;
      while True:&lt;br /&gt;
          if self.array[index] is None or self.array[index].key is None:&lt;br /&gt;
               # das Feld ist frei (1. Abfrage)&lt;br /&gt;
               # oder das Feld ist als frei markiert (2. Abfrage)&lt;br /&gt;
               self.array[index] = HashNode(key, value)&lt;br /&gt;
               self.size +=1&lt;br /&gt;
               return&lt;br /&gt;
          if self.array[index].key == key:&lt;br /&gt;
               # Es gibt diesen Schlüssel schon,&lt;br /&gt;
               # überschreibe die Daten&lt;br /&gt;
               self.array[index].data = value&lt;br /&gt;
               return&lt;br /&gt;
          # Letzter Fall: Kollision =&amp;gt; neuer Index durch 2. Hashfunktion&lt;br /&gt;
          index = (5*index+1+h) % self.capacity&lt;br /&gt;
          h = h &amp;gt;&amp;gt; 5&lt;br /&gt;
&lt;br /&gt;
Die vorgestellte Implementierung orientiert sich an Pythons interner Dictionary Implementierung, der zugehörige Quelltext (mit ausführlichem Kommentar) findet sich unter [http://svn.python.org/view/*checkout*/python/trunk/Objects/dictobject.c dictobject.c Python Implementation (SVN)]&lt;br /&gt;
&lt;br /&gt;
===== Komplexität des offenen Hashings =====&lt;br /&gt;
&lt;br /&gt;
* Annahme: uniformes Hashing, das heißt alle Indizes haben gleiche Wahrscheinlichkeit&lt;br /&gt;
* Füllstand &amp;lt;math&amp;gt;\alpha = \frac{\text{size}}{\text{capacity}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* '''Erfolglose Suche''' (d.h. es wird entweder ein neues Element eingefügt oder ein &amp;lt;tt&amp;gt;KeyError&amp;lt;/tt&amp;gt; geworfen): Untere Schranke für die Komplexität ist &amp;lt;math&amp;gt;\Omega\left(\frac{1}{1-\alpha}\right)&amp;lt;/math&amp;gt; Schritte (= Anzahl der notwendigen index-Berechnungen).&lt;br /&gt;
* '''Erfolgreiche Suche''' &amp;lt;math&amp;gt;\Omega\left(\frac{1}{\alpha}\ln\left(\frac{1}{1-\alpha}\right)\right)&amp;lt;/math&amp;gt; Schritte.&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;5&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
! &amp;lt;math&amp;gt;\alpha&amp;lt;/math&amp;gt;&lt;br /&gt;
! 0.5&lt;br /&gt;
! 0.9&lt;br /&gt;
|- &lt;br /&gt;
| erfolglos&lt;br /&gt;
| 2.0&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| erfolgreich&lt;br /&gt;
| 1.4&lt;br /&gt;
| 2.6&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===== Wahl der Kapazität =====&lt;br /&gt;
In Python wird &amp;lt;tt&amp;gt;capacity&amp;lt;/tt&amp;gt; Aufgrund der obigen Beobachtung so gewählt, dass &amp;lt;math&amp;gt;\alpha \leq 2/3&amp;lt;/math&amp;gt;. Falls &amp;lt;math&amp;gt;\alpha&amp;lt;/math&amp;gt; größer werden sollte, verdopple die Kapazität und kopiere das alte array in das neue Array (analog zum dynamischen Array)&lt;br /&gt;
&lt;br /&gt;
In Python werden die Kapazitätsgrößen als Zweierpotenzen gewählt, also 4,8,16,32,...,&lt;br /&gt;
so dass &amp;lt;tt&amp;gt;h % self.capacity&amp;lt;/tt&amp;gt; nur die unteren Bits von &amp;lt;tt&amp;gt;h&amp;lt;/tt&amp;gt; benutzt.&lt;br /&gt;
&lt;br /&gt;
== Anwendung von Hashing ==&lt;br /&gt;
&lt;br /&gt;
* Hashtabelle, assoziatives Aray&lt;br /&gt;
* Sortieren in linearer Zeit (Übungsaufgabe 6.2)&lt;br /&gt;
* Suchen von Strings in Texten: Rabin-Karp-Algorithmus&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
=== Rabin Karp Algorithmus ===&lt;br /&gt;
[http://de.wikipedia.org/wiki/Rabin-Karp-Algorithmus Wikipedia (de)] [http://en.wikipedia.org/wiki/Rabin-Karp_string_search_algorithm Wikipedia (en)]&lt;br /&gt;
&lt;br /&gt;
In Textverarbeitungsanwendungen ist eine häufig benutzte Funktion die ''Search &amp;amp; Replace'' Funktionalität. Die Suche sollte in O(len(text)) möglich sein, aber ein naiver Algorithmus braucht O(len(text)*len(searchstring))&lt;br /&gt;
&lt;br /&gt;
==== Naive Implementierung der Suche ====&lt;br /&gt;
  def search(text, s):&lt;br /&gt;
      M, N = len(text), len(s)&lt;br /&gt;
      for k in range(M-N):&lt;br /&gt;
          if s==text[k:k+N]:   # O(N), da N Zeichen verglichen werden müssen&lt;br /&gt;
              return k&lt;br /&gt;
      return -1 #nicht gefunden&lt;br /&gt;
&lt;br /&gt;
==== Idee des Rabin Karp Algorithmus ====&lt;br /&gt;
Statt Vergleichen &amp;lt;tt&amp;gt;s==text[k:k+N]&amp;lt;/tt&amp;gt;, die O(N) benötigen da N Vergleiche der Buchstaben durchgeführt werden müssen, Vergleiche die Hashs von Suchstring und dem zu untersuchenden Textabschnitt: &amp;lt;tt&amp;gt;hash(s) == hash(text[k:k+N])&amp;lt;/tt&amp;gt;. Dabei muss natürlich &amp;lt;tt&amp;gt;hash(s)&amp;lt;/tt&amp;gt; nur einmal berechnet werden, wohingegen &amp;lt;tt&amp;gt;hash(text[k:k+N])&amp;lt;/tt&amp;gt; immer wieder neu berechnet werden muss. Damit der Vergleich O(1) sein kann, ist es deswegen erforderlich, eine solche Hashfunktion zu haben, die nicht alle Zeichen (das wäre O(N) ) einlesen muss, sondern die vorhergehende Hashfunktion mit einbezieht.&lt;br /&gt;
&lt;br /&gt;
Eine solche Hashfunktion heißt ''Running Hash'' und funktioniert analog zum ''Sliding Mean''.&lt;br /&gt;
&lt;br /&gt;
Die Running Hash Funktion berechnet in O(1) den hash von &amp;lt;tt&amp;gt;text[k+1:k+1+N]&amp;lt;/tt&amp;gt; ausgehend vom hash für &amp;lt;tt&amp;gt;text[k:k+N]&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Idee: Interpretiere den Text als Ziffern in einer base d Darstellung:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h_k = \text{text}[k]\cdot d^{N-1} + \text{text}[k]\cdot d^{N-2} + \cdots + \text{text}[k+N-1]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für die Basis 10 (Dezimalsystem) ergibt sich also&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h_k = \text{text}[k]\cdot {10}^{N-1} + \text{text}[k]\cdot {10}^{N-2} + \cdots + \text{text}[k+N-1]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Daraus folgt&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h_{k+1} = 10\cdot h_k - \text{text}[k]\cdot {10}^{N} + \text{text}[k+N]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Komplexität dieses Updates ist O(1), falls man &amp;lt;math&amp;gt;{10}^{N}&amp;lt;/math&amp;gt; vorberechnet hat.&lt;br /&gt;
&lt;br /&gt;
In der Realität wählt man dann d=32 und benutzt noch an einigen Stellen modulo Operationen, um die Zahlen nicht zu groß werden zu lassen.&lt;br /&gt;
&lt;br /&gt;
==== Implementation ====&lt;br /&gt;
  def searchRabinKarp(text, s):&lt;br /&gt;
      ht, hs, dN = 0, 0, 1&lt;br /&gt;
      M, N = len(text), len(s)&lt;br /&gt;
      d, q = 32, 33554393&lt;br /&gt;
      #q ist eine große Primzahl, aber so,&lt;br /&gt;
      #dass d*q &amp;lt; 2**32 (um Überlauf zu vermeiden)&lt;br /&gt;
      &lt;br /&gt;
      #Initialisierung      &lt;br /&gt;
      for k in range(N):&lt;br /&gt;
          ht = (ht*d + ord(text[k])) % q&lt;br /&gt;
          #ord() gibt die ASCIInummer des übergebenen Zeichens zurück&lt;br /&gt;
          ds = (hs*d + ord( s[k] )) % q&lt;br /&gt;
          dN = (dN*a) % q&lt;br /&gt;
      #Die Variablen sind jetzt wie folgt initialisiert:&lt;br /&gt;
      #ht = hash(text[0:N])&lt;br /&gt;
      #hs = hash(s)&lt;br /&gt;
      #dN = (d**N) % q&lt;br /&gt;
      &lt;br /&gt;
      #Hauptschleife&lt;br /&gt;
      k = 0 &lt;br /&gt;
      while k &amp;lt; M-N:&lt;br /&gt;
          if hs == ht and s==text[k:k+N]:&lt;br /&gt;
              return k # serch string an Position k gefunden&lt;br /&gt;
          if k+N &amp;lt; M:&lt;br /&gt;
              ht = (d*ht - dN * ord(text[k]) + dN*q + ord(text[k+N]) ) % q&lt;br /&gt;
          k +=1&lt;br /&gt;
      return -1  # search string nicht gefunden&lt;/div&gt;</summary>
		<author><name>Thorben</name></author>	</entry>

	<entry>
		<id>https://alda.iwr.uni-heidelberg.de/index.php?title=Hashing_und_assoziative_Arrays&amp;diff=1728</id>
		<title>Hashing und assoziative Arrays</title>
		<link rel="alternate" type="text/html" href="https://alda.iwr.uni-heidelberg.de/index.php?title=Hashing_und_assoziative_Arrays&amp;diff=1728"/>
				<updated>2008-06-10T21:45:14Z</updated>
		
		<summary type="html">&lt;p&gt;Thorben: /* Rabin Karp Algorithmus */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Mitschrift gibts [http://hci.iwr.uni-heidelberg.de/alda/images/AlDa.pdf hier] als PDF und [http://hci.iwr.uni-heidelberg.de/alda/images/Alda_source.pdf hier] gibts die TeX-Sourcen, leider als PDF weil man wohl keine .TeXs hochladen darf. Originale gibts auf Anfrage bei kirchner at cl dot uni minus heidelberg dot de. Wird das Package &amp;quot;listings&amp;quot; verwendet, das gibts bei [http://tug.ctan.org/tex-archive/macros/latex/contrib/listings/ http://tug.ctan.org/tex-archive/macros/latex/contrib/listings/] &lt;br /&gt;
&lt;br /&gt;
Tipp- und sonstige Fehler dürfen gerne verbessert und erneut hochgeladen werden, oder gebt mir per Email Bescheid, dann pflege ich die   Korrektur ein :)&lt;br /&gt;
&lt;br /&gt;
Ich Finde dein Aufschrieb sollte ins Wiki übetragen werden, das bietet auch alles, was   &lt;br /&gt;
du mit Latex machen kannst. Die Bäume kannst du z.B. mit Latex zeichnen, einen pro Seite und diese dann in eine png Datei umwandeln. Wie sowas geht kann man z.B. in den Quellen von doxygen oder mediawiki selbst nachlesen. Oder man zoomt rein und macht einen Screenshot :-)&lt;br /&gt;
&lt;br /&gt;
== Hashtabelle mit linearer Verkettung ==&lt;br /&gt;
Pessimistischer Ansatz: Kollisionen treten häufig auf, deshalb wird unter jedem&lt;br /&gt;
Hashindex gleich eine Liste angelegt, in der Einträge aufgenommen werden können.&lt;br /&gt;
&lt;br /&gt;
===Implementation in Python===&lt;br /&gt;
''HashNode'' ist eine Hilfsdatenstruktur, die Schlüssel und Wert speichert&lt;br /&gt;
und mit Hilfe von ''next'' eine verkettete Liste realisiert&lt;br /&gt;
  class HashNode:&lt;br /&gt;
      def __init__(self,key,data,next):&lt;br /&gt;
          self.key = key&lt;br /&gt;
          self.data = data&lt;br /&gt;
          self.next = next # Verkettung!&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Die eigentliche Hashtabelle wird in der Klasse ''HashTable'' implementiert:&lt;br /&gt;
  class HashTable:&lt;br /&gt;
      def __init__(self):&lt;br /&gt;
         self.capacity = ... # Geeignete Werte siehe unten&lt;br /&gt;
         self.size = 0&lt;br /&gt;
         self.array = [None]*self.capacity&lt;br /&gt;
&lt;br /&gt;
In Python wird der Zugriffsoperator ''[ ]'' für eine Datenstruktur wie folgt (innerhalb einer Klasse) implementiert:&lt;br /&gt;
  def __setitem__(self, key, value)&lt;br /&gt;
&lt;br /&gt;
so dass im Programmtext dann folgende Syntax möglich ist: &amp;lt;tt&amp;gt;a[key] = value&amp;lt;/tt&amp;gt; (schreibender Zugriff auf &amp;lt;tt&amp;gt;a[key]&amp;lt;/tt&amp;gt;).&lt;br /&gt;
Analog wird der lesende Zugriff &amp;lt;tt&amp;gt;value = a[key]&amp;lt;/tt&amp;gt; wie folgt umgesetzt:&lt;br /&gt;
  def __getitem__(self, key, value)&lt;br /&gt;
&lt;br /&gt;
Implementierung der &amp;lt;tt&amp;gt;__setitem__&amp;lt;/tt&amp;gt;-Funktion in der &amp;lt;tt&amp;gt;HashTable&amp;lt;/tt&amp;gt;-Klasse:&lt;br /&gt;
  def __setitem__(self, key, value):&lt;br /&gt;
      index = hash(key) % self.capacity&lt;br /&gt;
      node = self.array[index]&lt;br /&gt;
      while node is not None:&lt;br /&gt;
          if node.key == key:&lt;br /&gt;
              # Element key ist schon in der Tabelle&lt;br /&gt;
              #Überschreibe die Daten mit dem neuen Wert&lt;br /&gt;
              node.data = value&lt;br /&gt;
              return&lt;br /&gt;
          # Kollision des Hashwerts, probiere nächsten Key aus&lt;br /&gt;
          node = node.next&lt;br /&gt;
      # Kein Element hatte den richtigen Schlüssel.&lt;br /&gt;
      # ==&amp;gt;Es gibt diesen Schlüssel noch nicht&lt;br /&gt;
      # Füge also ein neues Element in die Hashtabelle ein&lt;br /&gt;
       &lt;br /&gt;
      self.array[index] = HashNode(key, value, self.array[index])&lt;br /&gt;
      # Der alte Anfang der Liste wurde der Nachfolger des neu eingefügten&lt;br /&gt;
      # ersten Elements&lt;br /&gt;
       &lt;br /&gt;
      self.size += 1&lt;br /&gt;
&lt;br /&gt;
Und die Implementierung der &amp;lt;tt&amp;gt;__getitem__&amp;lt;/tt&amp;gt; Funktionen:&lt;br /&gt;
  def __getitem__(self, key):&lt;br /&gt;
      index = hash(key) % self.capacity&lt;br /&gt;
      node = self.array[index]&lt;br /&gt;
      while node is not None:&lt;br /&gt;
           if node.key == key: # Gefunden!&lt;br /&gt;
               return node.data&lt;br /&gt;
           node = node.next&lt;br /&gt;
      raise KeyError(key)&lt;br /&gt;
&lt;br /&gt;
==== Wahl der Kapazität ====&lt;br /&gt;
In der C++ Standardbibliothek (Klasse &amp;lt;tt&amp;gt;std::hash_map&amp;lt;/tt&amp;gt;) wird die Hashtabelle häufig mit Hilfe der linearen Verkettung&lt;br /&gt;
imlementiert. Dabei wird &amp;lt;tt&amp;gt;capacity&amp;lt;/tt&amp;gt; immer als ''Primzahl'' gewählt, wobei sich aufeinanderfolgende Kapazitäten immer ungefähr verdoppeln:&lt;br /&gt;
  53, 97, 193, 398, 769, ...&lt;br /&gt;
&lt;br /&gt;
Das hat zur Folge, dass &amp;lt;tt&amp;gt;hash(key) % self.capacity&amp;lt;/tt&amp;gt; ''alle'' Bits von h benutzt (Eigenschaft aus der Zahlentheorie). Die Kapizität wird vergrößert, wenn &amp;lt;tt&amp;gt;size == capacity&amp;lt;/tt&amp;gt; erreicht wird. Analog zum dynamischen Array werden die Daten dann aus dem alten Array (&amp;lt;tt&amp;gt;self.array&amp;lt;/tt&amp;gt;) in ein entsprechend vergrößertes neues Array kopiert.&lt;br /&gt;
&lt;br /&gt;
== Hashtabelle mit offener Adressierung (offenes Hashing) ==&lt;br /&gt;
[http://de.wikipedia.org/wiki/Hashtabelle#Hashing_mit_offener_Adressierung Wikipedia (de)]&lt;br /&gt;
[http://en.wikipedia.org/wiki/Open_addressing Wikipedia (en)]&lt;br /&gt;
&lt;br /&gt;
Optimistischer Ansatz: Kollisionen werden nicht so häufig auftreten.&lt;br /&gt;
&lt;br /&gt;
=== Idee ===&lt;br /&gt;
Wenn &amp;lt;tt&amp;gt;array[index]&amp;lt;/tt&amp;gt; durch Kollision bereits vergeben ist, probiere einen&lt;br /&gt;
anderen Index aus.&lt;br /&gt;
&lt;br /&gt;
* Das Array enthält pro Element höchstens ein (key,value)-Paar&lt;br /&gt;
* Das Array muss stets mindestens ''einen'' freien Platz haben (sonst gäbe es beim Ausprobieren anderer Indizes eine Endlosschleife). Es gilt immer &amp;lt;tt&amp;gt;self.size &amp;lt; self.capacity&amp;lt;/tt&amp;gt;. Dies war bei der vorigen Hash-Implementation mit linearer Verkettung nicht notwendig (aber im Sinne schneller zugriffszeiten trotzdem wünschenswert).&lt;br /&gt;
&lt;br /&gt;
=== Vorgehen bei Kollisionen ===&lt;br /&gt;
&lt;br /&gt;
==== Sequentielles Sondieren====&lt;br /&gt;
Probiere den nächsten Index: &amp;lt;tt&amp;gt;index = (index+1) % capacity&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Vorteil: einfach&lt;br /&gt;
* Nachteil: Clusterbildung&lt;br /&gt;
&lt;br /&gt;
Clusterbildung heißt, dass sich größere zusammenhängende Bereiche bilden die belegt sind, unterbrochen von Bereichen die komplett frei sind. Beim Versuche des Einfügens eines Elements an einen Platz, der schon belegt ist, muss jetzt das ganze Cluster sequentiell durchlaufen werden, bis ein freier Platz gefunden wird. Damit entspricht die Komplexität der Suche der mittleren Länge der belegten Bereiche, was sich entsprechend in einer langsamen Suche widerspiegelt.&lt;br /&gt;
&lt;br /&gt;
==== Doppeltes Hashing ====&lt;br /&gt;
[http://de.wikipedia.org/wiki/Doppel-Hashing Wikipedia (de)] [http://en.wikipedia.org/wiki/Double_hashing Wikipedia (en)]&lt;br /&gt;
&lt;br /&gt;
Bestimme einen neuen Index (bei Kollisionen) durch eine ''2. Hashfunktion''.&lt;br /&gt;
&lt;br /&gt;
Das doppelte Hashing wird typischerweise in der Praxis angewendet und liegt auch der Python Implementierung des Datentyps ''Dictionary'' (Syntax &amp;lt;tt&amp;gt;{'a':1, 'b':2, 'c':3}&amp;lt;/tt&amp;gt; zugrunde.&lt;br /&gt;
&lt;br /&gt;
Eine effiziente Implementierung dieses Datentyps ist für die Performance der Skriptsprache Python extrem wichtig, da z.B. beim Aufruf einer Funktion der auszuführunde Code in einem Dictionary unter dem Schlüssel ''Funktionsname'' nachgeschlagen wird oder die Werte lokaler Variablen innerhalb einer Funktion ebenfalls in einem Dictionary zu finden sind.&lt;br /&gt;
&lt;br /&gt;
Für die Implementierung in Python werden wieder die obigen Klassen &amp;lt;tt&amp;gt;HashNode&amp;lt;/tt&amp;gt; (das Attribut &amp;lt;tt&amp;gt;next&amp;lt;/tt&amp;gt; kann allerdings jetzt entfernt werden) und &amp;lt;tt&amp;gt;HashTable&amp;lt;/tt&amp;gt; benötigt, es folgen die angepassten Implementationen von &amp;lt;tt&amp;gt;__setitem&amp;lt;/tt&amp;gt; und &amp;lt;tt&amp;gt;__getitem__&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
  def __setitem__(self, key, value):&lt;br /&gt;
      h = hash(key)&lt;br /&gt;
      index = h % self.capacity&lt;br /&gt;
      while True:&lt;br /&gt;
          if self.array[index] is None or self.array[index].key is None:&lt;br /&gt;
               # das Feld ist frei (1. Abfrage)&lt;br /&gt;
               # oder das Feld ist als frei markiert (2. Abfrage)&lt;br /&gt;
               self.array[index] = HashNode(key, value)&lt;br /&gt;
               self.size +=1&lt;br /&gt;
               return&lt;br /&gt;
          if self.array[index].key == key:&lt;br /&gt;
               # Es gibt diesen Schlüssel schon,&lt;br /&gt;
               # überschreibe die Daten&lt;br /&gt;
               self.array[index].data = value&lt;br /&gt;
               return&lt;br /&gt;
          # Letzter Fall: Kollision =&amp;gt; neuer Index durch 2. Hashfunktion&lt;br /&gt;
          index = (5*index+1+h) % self.capacity&lt;br /&gt;
          h = h &amp;gt;&amp;gt; 5&lt;br /&gt;
&lt;br /&gt;
Die vorgestellte Implementierung orientiert sich an Pythons interner Dictionary Implementierung, der zugehörige Quelltext (mit ausführlichem Kommentar) findet sich unter [http://svn.python.org/view/*checkout*/python/trunk/Objects/dictobject.c dictobject.c Python Implementation (SVN)]&lt;br /&gt;
&lt;br /&gt;
===== Komplexität des offenen Hashings =====&lt;br /&gt;
&lt;br /&gt;
* Annahme: uniformes Hashing, das heißt alle Indizes haben gleiche Wahrscheinlichkeit&lt;br /&gt;
* Füllstand &amp;lt;math&amp;gt;\alpha = \frac{\text{size}}{\text{capacity}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* '''Erfolglose Suche''' (d.h. es wird entweder ein neues Element eingefügt oder ein &amp;lt;tt&amp;gt;KeyError&amp;lt;/tt&amp;gt; geworfen): Untere Schranke für die Komplexität ist &amp;lt;math&amp;gt;\Omega\left(\frac{1}{1-\alpha}\right)&amp;lt;/math&amp;gt; Schritte (= Anzahl der notwendigen index-Berechnungen).&lt;br /&gt;
* '''Erfolgreiche Suche''' &amp;lt;math&amp;gt;\Omega\left(\frac{1}{\alpha}\ln\left(\frac{1}{1-\alpha}\right)\right)&amp;lt;/math&amp;gt; Schritte.&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;5&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
! &amp;lt;math&amp;gt;\alpha&amp;lt;/math&amp;gt;&lt;br /&gt;
! 0.5&lt;br /&gt;
! 0.9&lt;br /&gt;
|- &lt;br /&gt;
| erfolglos&lt;br /&gt;
| 2.0&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| erfolgreich&lt;br /&gt;
| 1.4&lt;br /&gt;
| 2.6&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===== Wahl der Kapazität =====&lt;br /&gt;
In Python wird &amp;lt;tt&amp;gt;capacity&amp;lt;/tt&amp;gt; Aufgrund der obigen Beobachtung so gewählt, dass &amp;lt;math&amp;gt;\alpha \leq 2/3&amp;lt;/math&amp;gt;. Falls &amp;lt;math&amp;gt;\alpha&amp;lt;/math&amp;gt; größer werden sollte, verdopple die Kapazität und kopiere das alte array in das neue Array (analog zum dynamischen Array)&lt;br /&gt;
&lt;br /&gt;
In Python werden die Kapazitätsgrößen als Zweierpotenzen gewählt, also 4,8,16,32,...,&lt;br /&gt;
so dass &amp;lt;tt&amp;gt;h % self.capacity&amp;lt;/tt&amp;gt; nur die unteren Bits von &amp;lt;tt&amp;gt;h&amp;lt;/tt&amp;gt; benutzt.&lt;br /&gt;
&lt;br /&gt;
== Anwendung von Hashing ==&lt;br /&gt;
&lt;br /&gt;
* Hashtabelle, assoziatives Aray&lt;br /&gt;
* Sortieren in linearer Zeit (Übungsaufgabe 6.2)&lt;br /&gt;
* Suchen von Strings in Texten: Rabin-Karp-Algorithmus&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
=== Rabin Karp Algorithmus ===&lt;br /&gt;
[http://de.wikipedia.org/wiki/Rabin-Karp-Algorithmus Wikipedia (de)] [http://en.wikipedia.org/wiki/Rabin-Karp_string_search_algorithm Wikipedia (en)]&lt;br /&gt;
&lt;br /&gt;
In Textverarbeitungsanwendungen ist eine häufig benutzte Funktion die ''Search &amp;amp; Replace'' Funktionalität. Die Suche sollte in O(len(text)) möglich sein, aber ein naiver Algorithmus braucht O(len(text)*len(searchstring))&lt;br /&gt;
&lt;br /&gt;
==== Naive Implementierung der Suche ====&lt;br /&gt;
  def search(text, s):&lt;br /&gt;
      M, N = len(text), len(s)&lt;br /&gt;
      for k in range(M-N):&lt;br /&gt;
          if s==text[k:k+N]:   # O(N), da N Zeichen verglichen werden müssen&lt;br /&gt;
              return k&lt;br /&gt;
      return -1 #nicht gefunden&lt;br /&gt;
&lt;br /&gt;
==== Idee des Rabin Karp Algorithmus ====&lt;br /&gt;
Statt Vergleichen &amp;lt;tt&amp;gt;s==text[k:k+N]&amp;lt;/tt&amp;gt;, die O(N) benötigen da N Vergleiche der Buchstaben durchgeführt werden müssen, Vergleiche die Hashs von Suchstring und dem zu untersuchenden Textabschnitt: &amp;lt;tt&amp;gt;hash(s) == hash(text[k:k+N])&amp;lt;/tt&amp;gt;. Dabei muss natürlich &amp;lt;tt&amp;gt;hash(s)&amp;lt;/tt&amp;gt; nur einmal berechnet werden, wohingegen &amp;lt;tt&amp;gt;hash(text[k:k+N])&amp;lt;/tt&amp;gt; immer wieder neu berechnet werden muss. Damit der Vergleich O(1) sein kann, ist es deswegen erforderlich, eine solche Hashfunktion zu haben, die nicht alle Zeichen (das wäre O(N) ) einlesen muss, sondern die vorhergehende Hashfunktion mit einbezieht.&lt;br /&gt;
&lt;br /&gt;
Eine solche Hashfunktion heißt ''Running Hash'' und funktioniert analog zum ''Sliding Mean''.&lt;br /&gt;
&lt;br /&gt;
Die Running Hash Funktion berechnet in O(1) den hash von &amp;lt;tt&amp;gt;text[k+1:k+1+N]&amp;lt;/tt&amp;gt; ausgehend vom hash für &amp;lt;tt&amp;gt;text[k:k+N]&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Idee: Interpretiere den Text als Ziffern in einer base d Darstellung:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h_k = \text{text}[k]\cdot d^{N-1} + \text{text}[k]\cdot d^{N-2} + \cdots + \text{text}[k+N-1]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für die Basis 10 (Dezimalsystem) ergibt sich also&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h_k = \text{text}[k]\cdot {10}^{N-1} + \text{text}[k]\cdot {10}^{N-2} + \cdots + \text{text}[k+N-1]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Daraus folgt&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h_{k+1} = 10\cdot h_k - \text{text}[k]\cdot {10}^{N} + \text{text}[k+N]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Komplexität dieses Updates ist O(1), falls man &amp;lt;math&amp;gt;{10}^{N}&amp;lt;/math&amp;gt; vorberechnet hat.&lt;br /&gt;
&lt;br /&gt;
In der Realität wählt man dann d=32 und benutzt noch an einigen Stellen modulo Operationen, um die Zahlen nicht zu groß werden zu lassen.&lt;br /&gt;
&lt;br /&gt;
==== Implementation ====&lt;br /&gt;
  def searchRabinKarp(text, s):&lt;br /&gt;
      ht, hs, dN = 0, 0, 1&lt;br /&gt;
      M, N = len(text), len(s)&lt;br /&gt;
      d, q = 32, 33554393  # q ist eine große Primzahl, aber so, dass d*q &amp;lt; 2**32 (um Überlauf zu vermeiden)&lt;br /&gt;
      &lt;br /&gt;
      #Initialisierung      &lt;br /&gt;
      for k in range(N):&lt;br /&gt;
          ht = (ht*d + ord(text[k])) % q&lt;br /&gt;
          #ord() gibt die ASCIInummer des übergebenen Zeichens zurück&lt;br /&gt;
          ds = (hs*d + ord( s[k] )) % q&lt;br /&gt;
          dN = (dN*a) % q&lt;br /&gt;
      #Die Variablen sind jetzt wie folgt initialisiert:&lt;br /&gt;
      #ht = hash(text[0:N])&lt;br /&gt;
      #hs = hash(s)&lt;br /&gt;
      #dN = (d**N) % q&lt;br /&gt;
      &lt;br /&gt;
      #Hauptschleife&lt;br /&gt;
      k = 0 &lt;br /&gt;
      while k &amp;lt; M-N:&lt;br /&gt;
          if hs == ht and s==text[k:k+N]:&lt;br /&gt;
              return k # serch string an Position k gefunden&lt;br /&gt;
          if k+N &amp;lt; M:&lt;br /&gt;
              ht = (d*ht - dN * ord(text[k]) + dN*q + ord(text[k+N]) ) % q&lt;br /&gt;
          k +=1&lt;br /&gt;
      return -1  # search string nicht gefunden&lt;/div&gt;</summary>
		<author><name>Thorben</name></author>	</entry>

	<entry>
		<id>https://alda.iwr.uni-heidelberg.de/index.php?title=Hashing_und_assoziative_Arrays&amp;diff=1727</id>
		<title>Hashing und assoziative Arrays</title>
		<link rel="alternate" type="text/html" href="https://alda.iwr.uni-heidelberg.de/index.php?title=Hashing_und_assoziative_Arrays&amp;diff=1727"/>
				<updated>2008-06-10T21:42:31Z</updated>
		
		<summary type="html">&lt;p&gt;Thorben: /* Doppeltes Hashing */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Mitschrift gibts [http://hci.iwr.uni-heidelberg.de/alda/images/AlDa.pdf hier] als PDF und [http://hci.iwr.uni-heidelberg.de/alda/images/Alda_source.pdf hier] gibts die TeX-Sourcen, leider als PDF weil man wohl keine .TeXs hochladen darf. Originale gibts auf Anfrage bei kirchner at cl dot uni minus heidelberg dot de. Wird das Package &amp;quot;listings&amp;quot; verwendet, das gibts bei [http://tug.ctan.org/tex-archive/macros/latex/contrib/listings/ http://tug.ctan.org/tex-archive/macros/latex/contrib/listings/] &lt;br /&gt;
&lt;br /&gt;
Tipp- und sonstige Fehler dürfen gerne verbessert und erneut hochgeladen werden, oder gebt mir per Email Bescheid, dann pflege ich die   Korrektur ein :)&lt;br /&gt;
&lt;br /&gt;
Ich Finde dein Aufschrieb sollte ins Wiki übetragen werden, das bietet auch alles, was   &lt;br /&gt;
du mit Latex machen kannst. Die Bäume kannst du z.B. mit Latex zeichnen, einen pro Seite und diese dann in eine png Datei umwandeln. Wie sowas geht kann man z.B. in den Quellen von doxygen oder mediawiki selbst nachlesen. Oder man zoomt rein und macht einen Screenshot :-)&lt;br /&gt;
&lt;br /&gt;
== Hashtabelle mit linearer Verkettung ==&lt;br /&gt;
Pessimistischer Ansatz: Kollisionen treten häufig auf, deshalb wird unter jedem&lt;br /&gt;
Hashindex gleich eine Liste angelegt, in der Einträge aufgenommen werden können.&lt;br /&gt;
&lt;br /&gt;
===Implementation in Python===&lt;br /&gt;
''HashNode'' ist eine Hilfsdatenstruktur, die Schlüssel und Wert speichert&lt;br /&gt;
und mit Hilfe von ''next'' eine verkettete Liste realisiert&lt;br /&gt;
  class HashNode:&lt;br /&gt;
      def __init__(self,key,data,next):&lt;br /&gt;
          self.key = key&lt;br /&gt;
          self.data = data&lt;br /&gt;
          self.next = next # Verkettung!&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Die eigentliche Hashtabelle wird in der Klasse ''HashTable'' implementiert:&lt;br /&gt;
  class HashTable:&lt;br /&gt;
      def __init__(self):&lt;br /&gt;
         self.capacity = ... # Geeignete Werte siehe unten&lt;br /&gt;
         self.size = 0&lt;br /&gt;
         self.array = [None]*self.capacity&lt;br /&gt;
&lt;br /&gt;
In Python wird der Zugriffsoperator ''[ ]'' für eine Datenstruktur wie folgt (innerhalb einer Klasse) implementiert:&lt;br /&gt;
  def __setitem__(self, key, value)&lt;br /&gt;
&lt;br /&gt;
so dass im Programmtext dann folgende Syntax möglich ist: &amp;lt;tt&amp;gt;a[key] = value&amp;lt;/tt&amp;gt; (schreibender Zugriff auf &amp;lt;tt&amp;gt;a[key]&amp;lt;/tt&amp;gt;).&lt;br /&gt;
Analog wird der lesende Zugriff &amp;lt;tt&amp;gt;value = a[key]&amp;lt;/tt&amp;gt; wie folgt umgesetzt:&lt;br /&gt;
  def __getitem__(self, key, value)&lt;br /&gt;
&lt;br /&gt;
Implementierung der &amp;lt;tt&amp;gt;__setitem__&amp;lt;/tt&amp;gt;-Funktion in der &amp;lt;tt&amp;gt;HashTable&amp;lt;/tt&amp;gt;-Klasse:&lt;br /&gt;
  def __setitem__(self, key, value):&lt;br /&gt;
      index = hash(key) % self.capacity&lt;br /&gt;
      node = self.array[index]&lt;br /&gt;
      while node is not None:&lt;br /&gt;
          if node.key == key:&lt;br /&gt;
              # Element key ist schon in der Tabelle&lt;br /&gt;
              #Überschreibe die Daten mit dem neuen Wert&lt;br /&gt;
              node.data = value&lt;br /&gt;
              return&lt;br /&gt;
          # Kollision des Hashwerts, probiere nächsten Key aus&lt;br /&gt;
          node = node.next&lt;br /&gt;
      # Kein Element hatte den richtigen Schlüssel.&lt;br /&gt;
      # ==&amp;gt;Es gibt diesen Schlüssel noch nicht&lt;br /&gt;
      # Füge also ein neues Element in die Hashtabelle ein&lt;br /&gt;
       &lt;br /&gt;
      self.array[index] = HashNode(key, value, self.array[index])&lt;br /&gt;
      # Der alte Anfang der Liste wurde der Nachfolger des neu eingefügten&lt;br /&gt;
      # ersten Elements&lt;br /&gt;
       &lt;br /&gt;
      self.size += 1&lt;br /&gt;
&lt;br /&gt;
Und die Implementierung der &amp;lt;tt&amp;gt;__getitem__&amp;lt;/tt&amp;gt; Funktionen:&lt;br /&gt;
  def __getitem__(self, key):&lt;br /&gt;
      index = hash(key) % self.capacity&lt;br /&gt;
      node = self.array[index]&lt;br /&gt;
      while node is not None:&lt;br /&gt;
           if node.key == key: # Gefunden!&lt;br /&gt;
               return node.data&lt;br /&gt;
           node = node.next&lt;br /&gt;
      raise KeyError(key)&lt;br /&gt;
&lt;br /&gt;
==== Wahl der Kapazität ====&lt;br /&gt;
In der C++ Standardbibliothek (Klasse &amp;lt;tt&amp;gt;std::hash_map&amp;lt;/tt&amp;gt;) wird die Hashtabelle häufig mit Hilfe der linearen Verkettung&lt;br /&gt;
imlementiert. Dabei wird &amp;lt;tt&amp;gt;capacity&amp;lt;/tt&amp;gt; immer als ''Primzahl'' gewählt, wobei sich aufeinanderfolgende Kapazitäten immer ungefähr verdoppeln:&lt;br /&gt;
  53, 97, 193, 398, 769, ...&lt;br /&gt;
&lt;br /&gt;
Das hat zur Folge, dass &amp;lt;tt&amp;gt;hash(key) % self.capacity&amp;lt;/tt&amp;gt; ''alle'' Bits von h benutzt (Eigenschaft aus der Zahlentheorie). Die Kapizität wird vergrößert, wenn &amp;lt;tt&amp;gt;size == capacity&amp;lt;/tt&amp;gt; erreicht wird. Analog zum dynamischen Array werden die Daten dann aus dem alten Array (&amp;lt;tt&amp;gt;self.array&amp;lt;/tt&amp;gt;) in ein entsprechend vergrößertes neues Array kopiert.&lt;br /&gt;
&lt;br /&gt;
== Hashtabelle mit offener Adressierung (offenes Hashing) ==&lt;br /&gt;
[http://de.wikipedia.org/wiki/Hashtabelle#Hashing_mit_offener_Adressierung Wikipedia (de)]&lt;br /&gt;
[http://en.wikipedia.org/wiki/Open_addressing Wikipedia (en)]&lt;br /&gt;
&lt;br /&gt;
Optimistischer Ansatz: Kollisionen werden nicht so häufig auftreten.&lt;br /&gt;
&lt;br /&gt;
=== Idee ===&lt;br /&gt;
Wenn &amp;lt;tt&amp;gt;array[index]&amp;lt;/tt&amp;gt; durch Kollision bereits vergeben ist, probiere einen&lt;br /&gt;
anderen Index aus.&lt;br /&gt;
&lt;br /&gt;
* Das Array enthält pro Element höchstens ein (key,value)-Paar&lt;br /&gt;
* Das Array muss stets mindestens ''einen'' freien Platz haben (sonst gäbe es beim Ausprobieren anderer Indizes eine Endlosschleife). Es gilt immer &amp;lt;tt&amp;gt;self.size &amp;lt; self.capacity&amp;lt;/tt&amp;gt;. Dies war bei der vorigen Hash-Implementation mit linearer Verkettung nicht notwendig (aber im Sinne schneller zugriffszeiten trotzdem wünschenswert).&lt;br /&gt;
&lt;br /&gt;
=== Vorgehen bei Kollisionen ===&lt;br /&gt;
&lt;br /&gt;
==== Sequentielles Sondieren====&lt;br /&gt;
Probiere den nächsten Index: &amp;lt;tt&amp;gt;index = (index+1) % capacity&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Vorteil: einfach&lt;br /&gt;
* Nachteil: Clusterbildung&lt;br /&gt;
&lt;br /&gt;
Clusterbildung heißt, dass sich größere zusammenhängende Bereiche bilden die belegt sind, unterbrochen von Bereichen die komplett frei sind. Beim Versuche des Einfügens eines Elements an einen Platz, der schon belegt ist, muss jetzt das ganze Cluster sequentiell durchlaufen werden, bis ein freier Platz gefunden wird. Damit entspricht die Komplexität der Suche der mittleren Länge der belegten Bereiche, was sich entsprechend in einer langsamen Suche widerspiegelt.&lt;br /&gt;
&lt;br /&gt;
==== Doppeltes Hashing ====&lt;br /&gt;
[http://de.wikipedia.org/wiki/Doppel-Hashing Wikipedia (de)] [http://en.wikipedia.org/wiki/Double_hashing Wikipedia (en)]&lt;br /&gt;
&lt;br /&gt;
Bestimme einen neuen Index (bei Kollisionen) durch eine ''2. Hashfunktion''.&lt;br /&gt;
&lt;br /&gt;
Das doppelte Hashing wird typischerweise in der Praxis angewendet und liegt auch der Python Implementierung des Datentyps ''Dictionary'' (Syntax &amp;lt;tt&amp;gt;{'a':1, 'b':2, 'c':3}&amp;lt;/tt&amp;gt; zugrunde.&lt;br /&gt;
&lt;br /&gt;
Eine effiziente Implementierung dieses Datentyps ist für die Performance der Skriptsprache Python extrem wichtig, da z.B. beim Aufruf einer Funktion der auszuführunde Code in einem Dictionary unter dem Schlüssel ''Funktionsname'' nachgeschlagen wird oder die Werte lokaler Variablen innerhalb einer Funktion ebenfalls in einem Dictionary zu finden sind.&lt;br /&gt;
&lt;br /&gt;
Für die Implementierung in Python werden wieder die obigen Klassen &amp;lt;tt&amp;gt;HashNode&amp;lt;/tt&amp;gt; (das Attribut &amp;lt;tt&amp;gt;next&amp;lt;/tt&amp;gt; kann allerdings jetzt entfernt werden) und &amp;lt;tt&amp;gt;HashTable&amp;lt;/tt&amp;gt; benötigt, es folgen die angepassten Implementationen von &amp;lt;tt&amp;gt;__setitem&amp;lt;/tt&amp;gt; und &amp;lt;tt&amp;gt;__getitem__&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
  def __setitem__(self, key, value):&lt;br /&gt;
      h = hash(key)&lt;br /&gt;
      index = h % self.capacity&lt;br /&gt;
      while True:&lt;br /&gt;
          if self.array[index] is None or self.array[index].key is None:&lt;br /&gt;
               # das Feld ist frei (1. Abfrage)&lt;br /&gt;
               # oder das Feld ist als frei markiert (2. Abfrage)&lt;br /&gt;
               self.array[index] = HashNode(key, value)&lt;br /&gt;
               self.size +=1&lt;br /&gt;
               return&lt;br /&gt;
          if self.array[index].key == key:&lt;br /&gt;
               # Es gibt diesen Schlüssel schon,&lt;br /&gt;
               # überschreibe die Daten&lt;br /&gt;
               self.array[index].data = value&lt;br /&gt;
               return&lt;br /&gt;
          # Letzter Fall: Kollision =&amp;gt; neuer Index durch 2. Hashfunktion&lt;br /&gt;
          index = (5*index+1+h) % self.capacity&lt;br /&gt;
          h = h &amp;gt;&amp;gt; 5&lt;br /&gt;
&lt;br /&gt;
Die vorgestellte Implementierung orientiert sich an Pythons interner Dictionary Implementierung, der zugehörige Quelltext (mit ausführlichem Kommentar) findet sich unter [http://svn.python.org/view/*checkout*/python/trunk/Objects/dictobject.c dictobject.c Python Implementation (SVN)]&lt;br /&gt;
&lt;br /&gt;
===== Komplexität des offenen Hashings =====&lt;br /&gt;
&lt;br /&gt;
* Annahme: uniformes Hashing, das heißt alle Indizes haben gleiche Wahrscheinlichkeit&lt;br /&gt;
* Füllstand &amp;lt;math&amp;gt;\alpha = \frac{\text{size}}{\text{capacity}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* '''Erfolglose Suche''' (d.h. es wird entweder ein neues Element eingefügt oder ein &amp;lt;tt&amp;gt;KeyError&amp;lt;/tt&amp;gt; geworfen): Untere Schranke für die Komplexität ist &amp;lt;math&amp;gt;\Omega\left(\frac{1}{1-\alpha}\right)&amp;lt;/math&amp;gt; Schritte (= Anzahl der notwendigen index-Berechnungen).&lt;br /&gt;
* '''Erfolgreiche Suche''' &amp;lt;math&amp;gt;\Omega\left(\frac{1}{\alpha}\ln\left(\frac{1}{1-\alpha}\right)\right)&amp;lt;/math&amp;gt; Schritte.&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;5&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
! &amp;lt;math&amp;gt;\alpha&amp;lt;/math&amp;gt;&lt;br /&gt;
! 0.5&lt;br /&gt;
! 0.9&lt;br /&gt;
|- &lt;br /&gt;
| erfolglos&lt;br /&gt;
| 2.0&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| erfolgreich&lt;br /&gt;
| 1.4&lt;br /&gt;
| 2.6&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===== Wahl der Kapazität =====&lt;br /&gt;
In Python wird &amp;lt;tt&amp;gt;capacity&amp;lt;/tt&amp;gt; Aufgrund der obigen Beobachtung so gewählt, dass &amp;lt;math&amp;gt;\alpha \leq 2/3&amp;lt;/math&amp;gt;. Falls &amp;lt;math&amp;gt;\alpha&amp;lt;/math&amp;gt; größer werden sollte, verdopple die Kapazität und kopiere das alte array in das neue Array (analog zum dynamischen Array)&lt;br /&gt;
&lt;br /&gt;
In Python werden die Kapazitätsgrößen als Zweierpotenzen gewählt, also 4,8,16,32,...,&lt;br /&gt;
so dass &amp;lt;tt&amp;gt;h % self.capacity&amp;lt;/tt&amp;gt; nur die unteren Bits von &amp;lt;tt&amp;gt;h&amp;lt;/tt&amp;gt; benutzt.&lt;br /&gt;
&lt;br /&gt;
== Anwendung von Hashing ==&lt;br /&gt;
&lt;br /&gt;
* Hashtabelle, assoziatives Aray&lt;br /&gt;
* Sortieren in linearer Zeit (Übungsaufgabe 6.2)&lt;br /&gt;
* Suchen von Strings in Texten: Rabin-Karp-Algorithmus&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
=== Rabin Karp Algorithmus ===&lt;br /&gt;
In Textverarbeitungsanwendungen ist eine häufig benutzte Funktion die ''Search &amp;amp; Replace'' Funktionalität. Die Suche sollte in O(len(text)) möglich sein, aber ein naiver Algorithmus braucht O(len(text)*len(searchstring))&lt;br /&gt;
&lt;br /&gt;
==== Naive Implementierung der Suche ====&lt;br /&gt;
  def search(text, s):&lt;br /&gt;
      M, N = len(text), len(s)&lt;br /&gt;
      for k in range(M-N):&lt;br /&gt;
          if s==text[k:k+N]:   # O(N), da N Zeichen verglichen werden müssen&lt;br /&gt;
              return k&lt;br /&gt;
      return -1 #nicht gefunden&lt;br /&gt;
&lt;br /&gt;
==== Idee des Rabin Karp Algorithmus ====&lt;br /&gt;
Statt Vergleichen &amp;lt;tt&amp;gt;s==text[k:k+N]&amp;lt;/tt&amp;gt;, die O(N) benötigen da N Vergleiche der Buchstaben durchgeführt werden müssen, Vergleiche die Hashs von Suchstring und dem zu untersuchenden Textabschnitt: &amp;lt;tt&amp;gt;hash(s) == hash(text[k:k+N])&amp;lt;/tt&amp;gt;. Dabei muss natürlich &amp;lt;tt&amp;gt;hash(s)&amp;lt;/tt&amp;gt; nur einmal berechnet werden, wohingegen &amp;lt;tt&amp;gt;hash(text[k:k+N])&amp;lt;/tt&amp;gt; immer wieder neu berechnet werden muss. Damit der Vergleich O(1) sein kann, ist es deswegen erforderlich, eine solche Hashfunktion zu haben, die nicht alle Zeichen (das wäre O(N) ) einlesen muss, sondern die vorhergehende Hashfunktion mit einbezieht.&lt;br /&gt;
&lt;br /&gt;
Eine solche Hashfunktion heißt ''Running Hash'' und funktioniert analog zum ''Sliding Mean''.&lt;br /&gt;
&lt;br /&gt;
Die Running Hash Funktion berechnet in O(1) den hash von &amp;lt;tt&amp;gt;text[k+1:k+1+N]&amp;lt;/tt&amp;gt; ausgehend vom hash für &amp;lt;tt&amp;gt;text[k:k+N]&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Idee: Interpretiere den Text als Ziffern in einer base d Darstellung:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h_k = \text{text}[k]\cdot d^{N-1} + \text{text}[k]\cdot d^{N-2} + \cdots + \text{text}[k+N-1]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für die Basis 10 (Dezimalsystem) ergibt sich also&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h_k = \text{text}[k]\cdot {10}^{N-1} + \text{text}[k]\cdot {10}^{N-2} + \cdots + \text{text}[k+N-1]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Daraus folgt&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h_{k+1} = 10\cdot h_k - \text{text}[k]\cdot {10}^{N} + \text{text}[k+N]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Komplexität dieses Updates ist O(1), falls man &amp;lt;math&amp;gt;{10}^{N}&amp;lt;/math&amp;gt; vorberechnet hat.&lt;br /&gt;
&lt;br /&gt;
In der Realität wählt man dann d=32 und benutzt noch an einigen Stellen modulo Operationen, um die Zahlen nicht zu groß werden zu lassen.&lt;br /&gt;
&lt;br /&gt;
==== Implementation ====&lt;br /&gt;
  def searchRabinKarp(text, s):&lt;br /&gt;
      ht, hs, dN = 0, 0, 1&lt;br /&gt;
      M, N = len(text), len(s)&lt;br /&gt;
      d, q = 32, 33554393  # q ist eine große Primzahl, aber so, dass d*q &amp;lt; 2**32 (um Überlauf zu vermeiden)&lt;br /&gt;
      &lt;br /&gt;
      #Initialisierung      &lt;br /&gt;
      for k in range(N):&lt;br /&gt;
          ht = (ht*d + ord(text[k])) % q&lt;br /&gt;
          #ord() gibt die ASCIInummer des übergebenen Zeichens zurück&lt;br /&gt;
          ds = (hs*d + ord( s[k] )) % q&lt;br /&gt;
          dN = (dN*a) % q&lt;br /&gt;
      #Die Variablen sind jetzt wie folgt initialisiert:&lt;br /&gt;
      #ht = hash(text[0:N])&lt;br /&gt;
      #hs = hash(s)&lt;br /&gt;
      #dN = (d**N) % q&lt;br /&gt;
      &lt;br /&gt;
      #Hauptschleife&lt;br /&gt;
      k = 0 &lt;br /&gt;
      while k &amp;lt; M-N:&lt;br /&gt;
          if hs == ht and s==text[k:k+N]:&lt;br /&gt;
              return k # serch string an Position k gefunden&lt;br /&gt;
          if k+N &amp;lt; M:&lt;br /&gt;
              ht = (d*ht - dN * ord(text[k]) + dN*q + ord(text[k+N]) ) % q&lt;br /&gt;
          k +=1&lt;br /&gt;
      return -1  # search string nicht gefunden&lt;/div&gt;</summary>
		<author><name>Thorben</name></author>	</entry>

	<entry>
		<id>https://alda.iwr.uni-heidelberg.de/index.php?title=Hashing_und_assoziative_Arrays&amp;diff=1726</id>
		<title>Hashing und assoziative Arrays</title>
		<link rel="alternate" type="text/html" href="https://alda.iwr.uni-heidelberg.de/index.php?title=Hashing_und_assoziative_Arrays&amp;diff=1726"/>
				<updated>2008-06-10T21:40:38Z</updated>
		
		<summary type="html">&lt;p&gt;Thorben: /* Hashtabelle mit offener Adressierung (offenes Hashing) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Mitschrift gibts [http://hci.iwr.uni-heidelberg.de/alda/images/AlDa.pdf hier] als PDF und [http://hci.iwr.uni-heidelberg.de/alda/images/Alda_source.pdf hier] gibts die TeX-Sourcen, leider als PDF weil man wohl keine .TeXs hochladen darf. Originale gibts auf Anfrage bei kirchner at cl dot uni minus heidelberg dot de. Wird das Package &amp;quot;listings&amp;quot; verwendet, das gibts bei [http://tug.ctan.org/tex-archive/macros/latex/contrib/listings/ http://tug.ctan.org/tex-archive/macros/latex/contrib/listings/] &lt;br /&gt;
&lt;br /&gt;
Tipp- und sonstige Fehler dürfen gerne verbessert und erneut hochgeladen werden, oder gebt mir per Email Bescheid, dann pflege ich die   Korrektur ein :)&lt;br /&gt;
&lt;br /&gt;
Ich Finde dein Aufschrieb sollte ins Wiki übetragen werden, das bietet auch alles, was   &lt;br /&gt;
du mit Latex machen kannst. Die Bäume kannst du z.B. mit Latex zeichnen, einen pro Seite und diese dann in eine png Datei umwandeln. Wie sowas geht kann man z.B. in den Quellen von doxygen oder mediawiki selbst nachlesen. Oder man zoomt rein und macht einen Screenshot :-)&lt;br /&gt;
&lt;br /&gt;
== Hashtabelle mit linearer Verkettung ==&lt;br /&gt;
Pessimistischer Ansatz: Kollisionen treten häufig auf, deshalb wird unter jedem&lt;br /&gt;
Hashindex gleich eine Liste angelegt, in der Einträge aufgenommen werden können.&lt;br /&gt;
&lt;br /&gt;
===Implementation in Python===&lt;br /&gt;
''HashNode'' ist eine Hilfsdatenstruktur, die Schlüssel und Wert speichert&lt;br /&gt;
und mit Hilfe von ''next'' eine verkettete Liste realisiert&lt;br /&gt;
  class HashNode:&lt;br /&gt;
      def __init__(self,key,data,next):&lt;br /&gt;
          self.key = key&lt;br /&gt;
          self.data = data&lt;br /&gt;
          self.next = next # Verkettung!&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Die eigentliche Hashtabelle wird in der Klasse ''HashTable'' implementiert:&lt;br /&gt;
  class HashTable:&lt;br /&gt;
      def __init__(self):&lt;br /&gt;
         self.capacity = ... # Geeignete Werte siehe unten&lt;br /&gt;
         self.size = 0&lt;br /&gt;
         self.array = [None]*self.capacity&lt;br /&gt;
&lt;br /&gt;
In Python wird der Zugriffsoperator ''[ ]'' für eine Datenstruktur wie folgt (innerhalb einer Klasse) implementiert:&lt;br /&gt;
  def __setitem__(self, key, value)&lt;br /&gt;
&lt;br /&gt;
so dass im Programmtext dann folgende Syntax möglich ist: &amp;lt;tt&amp;gt;a[key] = value&amp;lt;/tt&amp;gt; (schreibender Zugriff auf &amp;lt;tt&amp;gt;a[key]&amp;lt;/tt&amp;gt;).&lt;br /&gt;
Analog wird der lesende Zugriff &amp;lt;tt&amp;gt;value = a[key]&amp;lt;/tt&amp;gt; wie folgt umgesetzt:&lt;br /&gt;
  def __getitem__(self, key, value)&lt;br /&gt;
&lt;br /&gt;
Implementierung der &amp;lt;tt&amp;gt;__setitem__&amp;lt;/tt&amp;gt;-Funktion in der &amp;lt;tt&amp;gt;HashTable&amp;lt;/tt&amp;gt;-Klasse:&lt;br /&gt;
  def __setitem__(self, key, value):&lt;br /&gt;
      index = hash(key) % self.capacity&lt;br /&gt;
      node = self.array[index]&lt;br /&gt;
      while node is not None:&lt;br /&gt;
          if node.key == key:&lt;br /&gt;
              # Element key ist schon in der Tabelle&lt;br /&gt;
              #Überschreibe die Daten mit dem neuen Wert&lt;br /&gt;
              node.data = value&lt;br /&gt;
              return&lt;br /&gt;
          # Kollision des Hashwerts, probiere nächsten Key aus&lt;br /&gt;
          node = node.next&lt;br /&gt;
      # Kein Element hatte den richtigen Schlüssel.&lt;br /&gt;
      # ==&amp;gt;Es gibt diesen Schlüssel noch nicht&lt;br /&gt;
      # Füge also ein neues Element in die Hashtabelle ein&lt;br /&gt;
       &lt;br /&gt;
      self.array[index] = HashNode(key, value, self.array[index])&lt;br /&gt;
      # Der alte Anfang der Liste wurde der Nachfolger des neu eingefügten&lt;br /&gt;
      # ersten Elements&lt;br /&gt;
       &lt;br /&gt;
      self.size += 1&lt;br /&gt;
&lt;br /&gt;
Und die Implementierung der &amp;lt;tt&amp;gt;__getitem__&amp;lt;/tt&amp;gt; Funktionen:&lt;br /&gt;
  def __getitem__(self, key):&lt;br /&gt;
      index = hash(key) % self.capacity&lt;br /&gt;
      node = self.array[index]&lt;br /&gt;
      while node is not None:&lt;br /&gt;
           if node.key == key: # Gefunden!&lt;br /&gt;
               return node.data&lt;br /&gt;
           node = node.next&lt;br /&gt;
      raise KeyError(key)&lt;br /&gt;
&lt;br /&gt;
==== Wahl der Kapazität ====&lt;br /&gt;
In der C++ Standardbibliothek (Klasse &amp;lt;tt&amp;gt;std::hash_map&amp;lt;/tt&amp;gt;) wird die Hashtabelle häufig mit Hilfe der linearen Verkettung&lt;br /&gt;
imlementiert. Dabei wird &amp;lt;tt&amp;gt;capacity&amp;lt;/tt&amp;gt; immer als ''Primzahl'' gewählt, wobei sich aufeinanderfolgende Kapazitäten immer ungefähr verdoppeln:&lt;br /&gt;
  53, 97, 193, 398, 769, ...&lt;br /&gt;
&lt;br /&gt;
Das hat zur Folge, dass &amp;lt;tt&amp;gt;hash(key) % self.capacity&amp;lt;/tt&amp;gt; ''alle'' Bits von h benutzt (Eigenschaft aus der Zahlentheorie). Die Kapizität wird vergrößert, wenn &amp;lt;tt&amp;gt;size == capacity&amp;lt;/tt&amp;gt; erreicht wird. Analog zum dynamischen Array werden die Daten dann aus dem alten Array (&amp;lt;tt&amp;gt;self.array&amp;lt;/tt&amp;gt;) in ein entsprechend vergrößertes neues Array kopiert.&lt;br /&gt;
&lt;br /&gt;
== Hashtabelle mit offener Adressierung (offenes Hashing) ==&lt;br /&gt;
[http://de.wikipedia.org/wiki/Hashtabelle#Hashing_mit_offener_Adressierung Wikipedia (de)]&lt;br /&gt;
[http://en.wikipedia.org/wiki/Open_addressing Wikipedia (en)]&lt;br /&gt;
&lt;br /&gt;
Optimistischer Ansatz: Kollisionen werden nicht so häufig auftreten.&lt;br /&gt;
&lt;br /&gt;
=== Idee ===&lt;br /&gt;
Wenn &amp;lt;tt&amp;gt;array[index]&amp;lt;/tt&amp;gt; durch Kollision bereits vergeben ist, probiere einen&lt;br /&gt;
anderen Index aus.&lt;br /&gt;
&lt;br /&gt;
* Das Array enthält pro Element höchstens ein (key,value)-Paar&lt;br /&gt;
* Das Array muss stets mindestens ''einen'' freien Platz haben (sonst gäbe es beim Ausprobieren anderer Indizes eine Endlosschleife). Es gilt immer &amp;lt;tt&amp;gt;self.size &amp;lt; self.capacity&amp;lt;/tt&amp;gt;. Dies war bei der vorigen Hash-Implementation mit linearer Verkettung nicht notwendig (aber im Sinne schneller zugriffszeiten trotzdem wünschenswert).&lt;br /&gt;
&lt;br /&gt;
=== Vorgehen bei Kollisionen ===&lt;br /&gt;
&lt;br /&gt;
==== Sequentielles Sondieren====&lt;br /&gt;
Probiere den nächsten Index: &amp;lt;tt&amp;gt;index = (index+1) % capacity&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Vorteil: einfach&lt;br /&gt;
* Nachteil: Clusterbildung&lt;br /&gt;
&lt;br /&gt;
Clusterbildung heißt, dass sich größere zusammenhängende Bereiche bilden die belegt sind, unterbrochen von Bereichen die komplett frei sind. Beim Versuche des Einfügens eines Elements an einen Platz, der schon belegt ist, muss jetzt das ganze Cluster sequentiell durchlaufen werden, bis ein freier Platz gefunden wird. Damit entspricht die Komplexität der Suche der mittleren Länge der belegten Bereiche, was sich entsprechend in einer langsamen Suche widerspiegelt.&lt;br /&gt;
&lt;br /&gt;
==== Doppeltes Hashing ====&lt;br /&gt;
Bestimme einen neuen Index (bei Kollisionen) durch eine ''2. Hashfunktion''.&lt;br /&gt;
&lt;br /&gt;
Das doppelte Hashing wird typischerweise in der Praxis angewendet und liegt auch der Python Implementierung des Datentyps ''Dictionary'' (Syntax &amp;lt;tt&amp;gt;{'a':1, 'b':2, 'c':3}&amp;lt;/tt&amp;gt; zugrunde.&lt;br /&gt;
&lt;br /&gt;
Eine effiziente Implementierung dieses Datentyps ist für die Performance der Skriptsprache Python extrem wichtig, da z.B. beim Aufruf einer Funktion der auszuführunde Code in einem Dictionary unter dem Schlüssel ''Funktionsname'' nachgeschlagen wird oder die Werte lokaler Variablen innerhalb einer Funktion ebenfalls in einem Dictionary zu finden sind.&lt;br /&gt;
&lt;br /&gt;
Für die Implementierung in Python werden wieder die obigen Klassen &amp;lt;tt&amp;gt;HashNode&amp;lt;/tt&amp;gt; (das Attribut &amp;lt;tt&amp;gt;next&amp;lt;/tt&amp;gt; kann allerdings jetzt entfernt werden) und &amp;lt;tt&amp;gt;HashTable&amp;lt;/tt&amp;gt; benötigt, es folgen die angepassten Implementationen von &amp;lt;tt&amp;gt;__setitem&amp;lt;/tt&amp;gt; und &amp;lt;tt&amp;gt;__getitem__&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
  def __setitem__(self, key, value):&lt;br /&gt;
      h = hash(key)&lt;br /&gt;
      index = h % self.capacity&lt;br /&gt;
      while True:&lt;br /&gt;
          if self.array[index] is None or self.array[index].key is None:&lt;br /&gt;
               # das Feld ist frei (1. Abfrage)&lt;br /&gt;
               # oder das Feld ist als frei markiert (2. Abfrage)&lt;br /&gt;
               self.array[index] = HashNode(key, value)&lt;br /&gt;
               self.size +=1&lt;br /&gt;
               return&lt;br /&gt;
          if self.array[index].key == key:&lt;br /&gt;
               # Es gibt diesen Schlüssel schon,&lt;br /&gt;
               # überschreibe die Daten&lt;br /&gt;
               self.array[index].data = value&lt;br /&gt;
               return&lt;br /&gt;
          # Letzter Fall: Kollision =&amp;gt; neuer Index durch 2. Hashfunktion&lt;br /&gt;
          index = (5*index+1+h) % self.capacity&lt;br /&gt;
          h = h &amp;gt;&amp;gt; 5&lt;br /&gt;
&lt;br /&gt;
Die vorgestellte Implementierung orientiert sich an Pythons interner Dictionary Implementierung, der zugehörige Quelltext (mit ausführlichem Kommentar) findet sich unter [http://svn.python.org/view/*checkout*/python/trunk/Objects/dictobject.c dictobject.c Python Implementation (SVN)]&lt;br /&gt;
&lt;br /&gt;
===== Komplexität des offenen Hashings =====&lt;br /&gt;
&lt;br /&gt;
* Annahme: uniformes Hashing, das heißt alle Indizes haben gleiche Wahrscheinlichkeit&lt;br /&gt;
* Füllstand &amp;lt;math&amp;gt;\alpha = \frac{\text{size}}{\text{capacity}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* '''Erfolglose Suche''' (d.h. es wird entweder ein neues Element eingefügt oder ein &amp;lt;tt&amp;gt;KeyError&amp;lt;/tt&amp;gt; geworfen): Untere Schranke für die Komplexität ist &amp;lt;math&amp;gt;\Omega\left(\frac{1}{1-\alpha}\right)&amp;lt;/math&amp;gt; Schritte (= Anzahl der notwendigen index-Berechnungen).&lt;br /&gt;
* '''Erfolgreiche Suche''' &amp;lt;math&amp;gt;\Omega\left(\frac{1}{\alpha}\ln\left(\frac{1}{1-\alpha}\right)\right)&amp;lt;/math&amp;gt; Schritte.&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;5&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
! &amp;lt;math&amp;gt;\alpha&amp;lt;/math&amp;gt;&lt;br /&gt;
! 0.5&lt;br /&gt;
! 0.9&lt;br /&gt;
|- &lt;br /&gt;
| erfolglos&lt;br /&gt;
| 2.0&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| erfolgreich&lt;br /&gt;
| 1.4&lt;br /&gt;
| 2.6&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===== Wahl der Kapazität =====&lt;br /&gt;
In Python wird &amp;lt;tt&amp;gt;capacity&amp;lt;/tt&amp;gt; Aufgrund der obigen Beobachtung so gewählt, dass &amp;lt;math&amp;gt;\alpha \leq 2/3&amp;lt;/math&amp;gt;. Falls &amp;lt;math&amp;gt;\alpha&amp;lt;/math&amp;gt; größer werden sollte, verdopple die Kapazität und kopiere das alte array in das neue Array (analog zum dynamischen Array)&lt;br /&gt;
&lt;br /&gt;
In Python werden die Kapazitätsgrößen als Zweierpotenzen gewählt, also 4,8,16,32,...,&lt;br /&gt;
so dass &amp;lt;tt&amp;gt;h % self.capacity&amp;lt;/tt&amp;gt; nur die unteren Bits von &amp;lt;tt&amp;gt;h&amp;lt;/tt&amp;gt; benutzt.&lt;br /&gt;
&lt;br /&gt;
== Anwendung von Hashing ==&lt;br /&gt;
&lt;br /&gt;
* Hashtabelle, assoziatives Aray&lt;br /&gt;
* Sortieren in linearer Zeit (Übungsaufgabe 6.2)&lt;br /&gt;
* Suchen von Strings in Texten: Rabin-Karp-Algorithmus&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
=== Rabin Karp Algorithmus ===&lt;br /&gt;
In Textverarbeitungsanwendungen ist eine häufig benutzte Funktion die ''Search &amp;amp; Replace'' Funktionalität. Die Suche sollte in O(len(text)) möglich sein, aber ein naiver Algorithmus braucht O(len(text)*len(searchstring))&lt;br /&gt;
&lt;br /&gt;
==== Naive Implementierung der Suche ====&lt;br /&gt;
  def search(text, s):&lt;br /&gt;
      M, N = len(text), len(s)&lt;br /&gt;
      for k in range(M-N):&lt;br /&gt;
          if s==text[k:k+N]:   # O(N), da N Zeichen verglichen werden müssen&lt;br /&gt;
              return k&lt;br /&gt;
      return -1 #nicht gefunden&lt;br /&gt;
&lt;br /&gt;
==== Idee des Rabin Karp Algorithmus ====&lt;br /&gt;
Statt Vergleichen &amp;lt;tt&amp;gt;s==text[k:k+N]&amp;lt;/tt&amp;gt;, die O(N) benötigen da N Vergleiche der Buchstaben durchgeführt werden müssen, Vergleiche die Hashs von Suchstring und dem zu untersuchenden Textabschnitt: &amp;lt;tt&amp;gt;hash(s) == hash(text[k:k+N])&amp;lt;/tt&amp;gt;. Dabei muss natürlich &amp;lt;tt&amp;gt;hash(s)&amp;lt;/tt&amp;gt; nur einmal berechnet werden, wohingegen &amp;lt;tt&amp;gt;hash(text[k:k+N])&amp;lt;/tt&amp;gt; immer wieder neu berechnet werden muss. Damit der Vergleich O(1) sein kann, ist es deswegen erforderlich, eine solche Hashfunktion zu haben, die nicht alle Zeichen (das wäre O(N) ) einlesen muss, sondern die vorhergehende Hashfunktion mit einbezieht.&lt;br /&gt;
&lt;br /&gt;
Eine solche Hashfunktion heißt ''Running Hash'' und funktioniert analog zum ''Sliding Mean''.&lt;br /&gt;
&lt;br /&gt;
Die Running Hash Funktion berechnet in O(1) den hash von &amp;lt;tt&amp;gt;text[k+1:k+1+N]&amp;lt;/tt&amp;gt; ausgehend vom hash für &amp;lt;tt&amp;gt;text[k:k+N]&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Idee: Interpretiere den Text als Ziffern in einer base d Darstellung:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h_k = \text{text}[k]\cdot d^{N-1} + \text{text}[k]\cdot d^{N-2} + \cdots + \text{text}[k+N-1]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für die Basis 10 (Dezimalsystem) ergibt sich also&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h_k = \text{text}[k]\cdot {10}^{N-1} + \text{text}[k]\cdot {10}^{N-2} + \cdots + \text{text}[k+N-1]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Daraus folgt&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h_{k+1} = 10\cdot h_k - \text{text}[k]\cdot {10}^{N} + \text{text}[k+N]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Komplexität dieses Updates ist O(1), falls man &amp;lt;math&amp;gt;{10}^{N}&amp;lt;/math&amp;gt; vorberechnet hat.&lt;br /&gt;
&lt;br /&gt;
In der Realität wählt man dann d=32 und benutzt noch an einigen Stellen modulo Operationen, um die Zahlen nicht zu groß werden zu lassen.&lt;br /&gt;
&lt;br /&gt;
==== Implementation ====&lt;br /&gt;
  def searchRabinKarp(text, s):&lt;br /&gt;
      ht, hs, dN = 0, 0, 1&lt;br /&gt;
      M, N = len(text), len(s)&lt;br /&gt;
      d, q = 32, 33554393  # q ist eine große Primzahl, aber so, dass d*q &amp;lt; 2**32 (um Überlauf zu vermeiden)&lt;br /&gt;
      &lt;br /&gt;
      #Initialisierung      &lt;br /&gt;
      for k in range(N):&lt;br /&gt;
          ht = (ht*d + ord(text[k])) % q&lt;br /&gt;
          #ord() gibt die ASCIInummer des übergebenen Zeichens zurück&lt;br /&gt;
          ds = (hs*d + ord( s[k] )) % q&lt;br /&gt;
          dN = (dN*a) % q&lt;br /&gt;
      #Die Variablen sind jetzt wie folgt initialisiert:&lt;br /&gt;
      #ht = hash(text[0:N])&lt;br /&gt;
      #hs = hash(s)&lt;br /&gt;
      #dN = (d**N) % q&lt;br /&gt;
      &lt;br /&gt;
      #Hauptschleife&lt;br /&gt;
      k = 0 &lt;br /&gt;
      while k &amp;lt; M-N:&lt;br /&gt;
          if hs == ht and s==text[k:k+N]:&lt;br /&gt;
              return k # serch string an Position k gefunden&lt;br /&gt;
          if k+N &amp;lt; M:&lt;br /&gt;
              ht = (d*ht - dN * ord(text[k]) + dN*q + ord(text[k+N]) ) % q&lt;br /&gt;
          k +=1&lt;br /&gt;
      return -1  # search string nicht gefunden&lt;/div&gt;</summary>
		<author><name>Thorben</name></author>	</entry>

	<entry>
		<id>https://alda.iwr.uni-heidelberg.de/index.php?title=Hashing_und_assoziative_Arrays&amp;diff=1724</id>
		<title>Hashing und assoziative Arrays</title>
		<link rel="alternate" type="text/html" href="https://alda.iwr.uni-heidelberg.de/index.php?title=Hashing_und_assoziative_Arrays&amp;diff=1724"/>
				<updated>2008-06-10T21:33:45Z</updated>
		
		<summary type="html">&lt;p&gt;Thorben: /* Implementation in Python */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Mitschrift gibts [http://hci.iwr.uni-heidelberg.de/alda/images/AlDa.pdf hier] als PDF und [http://hci.iwr.uni-heidelberg.de/alda/images/Alda_source.pdf hier] gibts die TeX-Sourcen, leider als PDF weil man wohl keine .TeXs hochladen darf. Originale gibts auf Anfrage bei kirchner at cl dot uni minus heidelberg dot de. Wird das Package &amp;quot;listings&amp;quot; verwendet, das gibts bei [http://tug.ctan.org/tex-archive/macros/latex/contrib/listings/ http://tug.ctan.org/tex-archive/macros/latex/contrib/listings/] &lt;br /&gt;
&lt;br /&gt;
Tipp- und sonstige Fehler dürfen gerne verbessert und erneut hochgeladen werden, oder gebt mir per Email Bescheid, dann pflege ich die   Korrektur ein :)&lt;br /&gt;
&lt;br /&gt;
Ich Finde dein Aufschrieb sollte ins Wiki übetragen werden, das bietet auch alles, was   &lt;br /&gt;
du mit Latex machen kannst. Die Bäume kannst du z.B. mit Latex zeichnen, einen pro Seite und diese dann in eine png Datei umwandeln. Wie sowas geht kann man z.B. in den Quellen von doxygen oder mediawiki selbst nachlesen. Oder man zoomt rein und macht einen Screenshot :-)&lt;br /&gt;
&lt;br /&gt;
== Hashtabelle mit linearer Verkettung ==&lt;br /&gt;
Pessimistischer Ansatz: Kollisionen treten häufig auf, deshalb wird unter jedem&lt;br /&gt;
Hashindex gleich eine Liste angelegt, in der Einträge aufgenommen werden können.&lt;br /&gt;
&lt;br /&gt;
===Implementation in Python===&lt;br /&gt;
''HashNode'' ist eine Hilfsdatenstruktur, die Schlüssel und Wert speichert&lt;br /&gt;
und mit Hilfe von ''next'' eine verkettete Liste realisiert&lt;br /&gt;
  class HashNode:&lt;br /&gt;
      def __init__(self,key,data,next):&lt;br /&gt;
          self.key = key&lt;br /&gt;
          self.data = data&lt;br /&gt;
          self.next = next # Verkettung!&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Die eigentliche Hashtabelle wird in der Klasse ''HashTable'' implementiert:&lt;br /&gt;
  class HashTable:&lt;br /&gt;
      def __init__(self):&lt;br /&gt;
         self.capacity = ... # Geeignete Werte siehe unten&lt;br /&gt;
         self.size = 0&lt;br /&gt;
         self.array = [None]*self.capacity&lt;br /&gt;
&lt;br /&gt;
In Python wird der Zugriffsoperator ''[ ]'' für eine Datenstruktur wie folgt (innerhalb einer Klasse) implementiert:&lt;br /&gt;
  def __setitem__(self, key, value)&lt;br /&gt;
&lt;br /&gt;
so dass im Programmtext dann folgende Syntax möglich ist: &amp;lt;tt&amp;gt;a[key] = value&amp;lt;/tt&amp;gt; (schreibender Zugriff auf &amp;lt;tt&amp;gt;a[key]&amp;lt;/tt&amp;gt;).&lt;br /&gt;
Analog wird der lesende Zugriff &amp;lt;tt&amp;gt;value = a[key]&amp;lt;/tt&amp;gt; wie folgt umgesetzt:&lt;br /&gt;
  def __getitem__(self, key, value)&lt;br /&gt;
&lt;br /&gt;
Implementierung der &amp;lt;tt&amp;gt;__setitem__&amp;lt;/tt&amp;gt;-Funktion in der &amp;lt;tt&amp;gt;HashTable&amp;lt;/tt&amp;gt;-Klasse:&lt;br /&gt;
  def __setitem__(self, key, value):&lt;br /&gt;
      index = hash(key) % self.capacity&lt;br /&gt;
      node = self.array[index]&lt;br /&gt;
      while node is not None:&lt;br /&gt;
          if node.key == key:&lt;br /&gt;
              # Element key ist schon in der Tabelle&lt;br /&gt;
              #Überschreibe die Daten mit dem neuen Wert&lt;br /&gt;
              node.data = value&lt;br /&gt;
              return&lt;br /&gt;
          # Kollision des Hashwerts, probiere nächsten Key aus&lt;br /&gt;
          node = node.next&lt;br /&gt;
      # Kein Element hatte den richtigen Schlüssel.&lt;br /&gt;
      # ==&amp;gt;Es gibt diesen Schlüssel noch nicht&lt;br /&gt;
      # Füge also ein neues Element in die Hashtabelle ein&lt;br /&gt;
       &lt;br /&gt;
      self.array[index] = HashNode(key, value, self.array[index])&lt;br /&gt;
      # Der alte Anfang der Liste wurde der Nachfolger des neu eingefügten&lt;br /&gt;
      # ersten Elements&lt;br /&gt;
       &lt;br /&gt;
      self.size += 1&lt;br /&gt;
&lt;br /&gt;
Und die Implementierung der &amp;lt;tt&amp;gt;__getitem__&amp;lt;/tt&amp;gt; Funktionen:&lt;br /&gt;
  def __getitem__(self, key):&lt;br /&gt;
      index = hash(key) % self.capacity&lt;br /&gt;
      node = self.array[index]&lt;br /&gt;
      while node is not None:&lt;br /&gt;
           if node.key == key: # Gefunden!&lt;br /&gt;
               return node.data&lt;br /&gt;
           node = node.next&lt;br /&gt;
      raise KeyError(key)&lt;br /&gt;
&lt;br /&gt;
==== Wahl der Kapazität ====&lt;br /&gt;
In der C++ Standardbibliothek (Klasse &amp;lt;tt&amp;gt;std::hash_map&amp;lt;/tt&amp;gt;) wird die Hashtabelle häufig mit Hilfe der linearen Verkettung&lt;br /&gt;
imlementiert. Dabei wird &amp;lt;tt&amp;gt;capacity&amp;lt;/tt&amp;gt; immer als ''Primzahl'' gewählt, wobei sich aufeinanderfolgende Kapazitäten immer ungefähr verdoppeln:&lt;br /&gt;
  53, 97, 193, 398, 769, ...&lt;br /&gt;
&lt;br /&gt;
Das hat zur Folge, dass &amp;lt;tt&amp;gt;hash(key) % self.capacity&amp;lt;/tt&amp;gt; ''alle'' Bits von h benutzt (Eigenschaft aus der Zahlentheorie). Die Kapizität wird vergrößert, wenn &amp;lt;tt&amp;gt;size == capacity&amp;lt;/tt&amp;gt; erreicht wird. Analog zum dynamischen Array werden die Daten dann aus dem alten Array (&amp;lt;tt&amp;gt;self.array&amp;lt;/tt&amp;gt;) in ein entsprechend vergrößertes neues Array kopiert.&lt;br /&gt;
&lt;br /&gt;
== Hashtabelle mit offener Adressierung (offenes Hashing) ==&lt;br /&gt;
Optimistischer Ansatz: Kollisionen werden nicht so häufig auftreten.&lt;br /&gt;
&lt;br /&gt;
=== Idee ===&lt;br /&gt;
Wenn &amp;lt;tt&amp;gt;array[index]&amp;lt;/tt&amp;gt; durch Kollision bereits vergeben ist, probiere einen&lt;br /&gt;
anderen Index aus.&lt;br /&gt;
&lt;br /&gt;
* Das Array enthält pro Element höchstens ein (key,value)-Paar&lt;br /&gt;
* Das Array muss stets mindestens ''einen'' freien Platz haben (sonst gäbe es beim Ausprobieren anderer Indizes eine Endlosschleife). Es gilt immer &amp;lt;tt&amp;gt;self.size &amp;lt; self.capacity&amp;lt;/tt&amp;gt;. Dies war bei der vorigen Hash-Implementation mit linearer Verkettung nicht notwendig (aber im Sinne schneller zugriffszeiten trotzdem wünschenswert).&lt;br /&gt;
&lt;br /&gt;
=== Vorgehen bei Kollisionen ===&lt;br /&gt;
&lt;br /&gt;
==== Sequentielles Sondieren====&lt;br /&gt;
Probiere den nächsten Index: &amp;lt;tt&amp;gt;index = (index+1) % capacity&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Vorteil: einfach&lt;br /&gt;
* Nachteil: Clusterbildung&lt;br /&gt;
&lt;br /&gt;
Clusterbildung heißt, dass sich größere zusammenhängende Bereiche bilden die belegt sind, unterbrochen von Bereichen die komplett frei sind. Beim Versuche des Einfügens eines Elements an einen Platz, der schon belegt ist, muss jetzt das ganze Cluster sequentiell durchlaufen werden, bis ein freier Platz gefunden wird. Damit entspricht die Komplexität der Suche der mittleren Länge der belegten Bereiche, was sich entsprechend in einer langsamen Suche widerspiegelt.&lt;br /&gt;
&lt;br /&gt;
==== Doppeltes Hashing ====&lt;br /&gt;
Bestimme einen neuen Index (bei Kollisionen) durch eine ''2. Hashfunktion''.&lt;br /&gt;
&lt;br /&gt;
Das doppelte Hashing wird typischerweise in der Praxis angewendet und liegt auch der Python Implementierung des Datentyps ''Dictionary'' (Syntax &amp;lt;tt&amp;gt;{'a':1, 'b':2, 'c':3}&amp;lt;/tt&amp;gt; zugrunde.&lt;br /&gt;
&lt;br /&gt;
Eine effiziente Implementierung dieses Datentyps ist für die Performance der Skriptsprache Python extrem wichtig, da z.B. beim Aufruf einer Funktion der auszuführunde Code in einem Dictionary unter dem Schlüssel ''Funktionsname'' nachgeschlagen wird oder die Werte lokaler Variablen innerhalb einer Funktion ebenfalls in einem Dictionary zu finden sind.&lt;br /&gt;
&lt;br /&gt;
Für die Implementierung in Python werden wieder die obigen Klassen &amp;lt;tt&amp;gt;HashNode&amp;lt;/tt&amp;gt; (das Attribut &amp;lt;tt&amp;gt;next&amp;lt;/tt&amp;gt; kann allerdings jetzt entfernt werden) und &amp;lt;tt&amp;gt;HashTable&amp;lt;/tt&amp;gt; benötigt, es folgen die angepassten Implementationen von &amp;lt;tt&amp;gt;__setitem&amp;lt;/tt&amp;gt; und &amp;lt;tt&amp;gt;__getitem__&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
  def __setitem__(self, key, value):&lt;br /&gt;
      h = hash(key)&lt;br /&gt;
      index = h % self.capacity&lt;br /&gt;
      while True:&lt;br /&gt;
          if self.array[index] is None or self.array[index].key is None:&lt;br /&gt;
               # das Feld ist frei (1. Abfrage)&lt;br /&gt;
               # oder das Feld ist als frei markiert (2. Abfrage)&lt;br /&gt;
               self.array[index] = HashNode(key, value)&lt;br /&gt;
               self.size +=1&lt;br /&gt;
               return&lt;br /&gt;
          if self.array[index].key == key:&lt;br /&gt;
               # Es gibt diesen Schlüssel schon,&lt;br /&gt;
               # überschreibe die Daten&lt;br /&gt;
               self.array[index].data = value&lt;br /&gt;
               return&lt;br /&gt;
          # Letzter Fall: Kollision =&amp;gt; neuer Index durch 2. Hashfunktion&lt;br /&gt;
          index = (5*index+1+h) % self.capacity&lt;br /&gt;
          h = h &amp;gt;&amp;gt; 5&lt;br /&gt;
&lt;br /&gt;
Die vorgestellte Implementierung orientiert sich an Pythons interner Dictionary Implementierung, der zugehörige Quelltext (mit ausführlichem Kommentar) findet sich unter [http://svn.python.org/view/*checkout*/python/trunk/Objects/dictobject.c dictobject.c Python Implementation (SVN)]&lt;br /&gt;
&lt;br /&gt;
===== Komplexität des offenen Hashings =====&lt;br /&gt;
&lt;br /&gt;
* Annahme: uniformes Hashing, das heißt alle Indizes haben gleiche Wahrscheinlichkeit&lt;br /&gt;
* Füllstand &amp;lt;math&amp;gt;\alpha = \frac{\text{size}}{\text{capacity}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* '''Erfolglose Suche''' (d.h. es wird entweder ein neues Element eingefügt oder ein &amp;lt;tt&amp;gt;KeyError&amp;lt;/tt&amp;gt; geworfen): Untere Schranke für die Komplexität ist &amp;lt;math&amp;gt;\Omega\left(\frac{1}{1-\alpha}\right)&amp;lt;/math&amp;gt; Schritte (= Anzahl der notwendigen index-Berechnungen).&lt;br /&gt;
* '''Erfolgreiche Suche''' &amp;lt;math&amp;gt;\Omega\left(\frac{1}{\alpha}\ln\left(\frac{1}{1-\alpha}\right)\right)&amp;lt;/math&amp;gt; Schritte.&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;5&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
! &amp;lt;math&amp;gt;\alpha&amp;lt;/math&amp;gt;&lt;br /&gt;
! 0.5&lt;br /&gt;
! 0.9&lt;br /&gt;
|- &lt;br /&gt;
| erfolglos&lt;br /&gt;
| 2.0&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| erfolgreich&lt;br /&gt;
| 1.4&lt;br /&gt;
| 2.6&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===== Wahl der Kapazität =====&lt;br /&gt;
In Python wird &amp;lt;tt&amp;gt;capacity&amp;lt;/tt&amp;gt; Aufgrund der obigen Beobachtung so gewählt, dass &amp;lt;math&amp;gt;\alpha \leq 2/3&amp;lt;/math&amp;gt;. Falls &amp;lt;math&amp;gt;\alpha&amp;lt;/math&amp;gt; größer werden sollte, verdopple die Kapazität und kopiere das alte array in das neue Array (analog zum dynamischen Array)&lt;br /&gt;
&lt;br /&gt;
In Python werden die Kapazitätsgrößen als Zweierpotenzen gewählt, also 4,8,16,32,...,&lt;br /&gt;
so dass &amp;lt;tt&amp;gt;h % self.capacity&amp;lt;/tt&amp;gt; nur die unteren Bits von &amp;lt;tt&amp;gt;h&amp;lt;/tt&amp;gt; benutzt.&lt;br /&gt;
&lt;br /&gt;
== Anwendung von Hashing ==&lt;br /&gt;
&lt;br /&gt;
* Hashtabelle, assoziatives Aray&lt;br /&gt;
* Sortieren in linearer Zeit (Übungsaufgabe 6.2)&lt;br /&gt;
* Suchen von Strings in Texten: Rabin-Karp-Algorithmus&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
=== Rabin Karp Algorithmus ===&lt;br /&gt;
In Textverarbeitungsanwendungen ist eine häufig benutzte Funktion die ''Search &amp;amp; Replace'' Funktionalität. Die Suche sollte in O(len(text)) möglich sein, aber ein naiver Algorithmus braucht O(len(text)*len(searchstring))&lt;br /&gt;
&lt;br /&gt;
==== Naive Implementierung der Suche ====&lt;br /&gt;
  def search(text, s):&lt;br /&gt;
      M, N = len(text), len(s)&lt;br /&gt;
      for k in range(M-N):&lt;br /&gt;
          if s==text[k:k+N]:   # O(N), da N Zeichen verglichen werden müssen&lt;br /&gt;
              return k&lt;br /&gt;
      return -1 #nicht gefunden&lt;br /&gt;
&lt;br /&gt;
==== Idee des Rabin Karp Algorithmus ====&lt;br /&gt;
Statt Vergleichen &amp;lt;tt&amp;gt;s==text[k:k+N]&amp;lt;/tt&amp;gt;, die O(N) benötigen da N Vergleiche der Buchstaben durchgeführt werden müssen, Vergleiche die Hashs von Suchstring und dem zu untersuchenden Textabschnitt: &amp;lt;tt&amp;gt;hash(s) == hash(text[k:k+N])&amp;lt;/tt&amp;gt;. Dabei muss natürlich &amp;lt;tt&amp;gt;hash(s)&amp;lt;/tt&amp;gt; nur einmal berechnet werden, wohingegen &amp;lt;tt&amp;gt;hash(text[k:k+N])&amp;lt;/tt&amp;gt; immer wieder neu berechnet werden muss. Damit der Vergleich O(1) sein kann, ist es deswegen erforderlich, eine solche Hashfunktion zu haben, die nicht alle Zeichen (das wäre O(N) ) einlesen muss, sondern die vorhergehende Hashfunktion mit einbezieht.&lt;br /&gt;
&lt;br /&gt;
Eine solche Hashfunktion heißt ''Running Hash'' und funktioniert analog zum ''Sliding Mean''.&lt;br /&gt;
&lt;br /&gt;
Die Running Hash Funktion berechnet in O(1) den hash von &amp;lt;tt&amp;gt;text[k+1:k+1+N]&amp;lt;/tt&amp;gt; ausgehend vom hash für &amp;lt;tt&amp;gt;text[k:k+N]&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Idee: Interpretiere den Text als Ziffern in einer base d Darstellung:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h_k = \text{text}[k]\cdot d^{N-1} + \text{text}[k]\cdot d^{N-2} + \cdots + \text{text}[k+N-1]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für die Basis 10 (Dezimalsystem) ergibt sich also&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h_k = \text{text}[k]\cdot {10}^{N-1} + \text{text}[k]\cdot {10}^{N-2} + \cdots + \text{text}[k+N-1]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Daraus folgt&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h_{k+1} = 10\cdot h_k - \text{text}[k]\cdot {10}^{N} + \text{text}[k+N]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Komplexität dieses Updates ist O(1), falls man &amp;lt;math&amp;gt;{10}^{N}&amp;lt;/math&amp;gt; vorberechnet hat.&lt;br /&gt;
&lt;br /&gt;
In der Realität wählt man dann d=32 und benutzt noch an einigen Stellen modulo Operationen, um die Zahlen nicht zu groß werden zu lassen.&lt;br /&gt;
&lt;br /&gt;
==== Implementation ====&lt;br /&gt;
  def searchRabinKarp(text, s):&lt;br /&gt;
      ht, hs, dN = 0, 0, 1&lt;br /&gt;
      M, N = len(text), len(s)&lt;br /&gt;
      d, q = 32, 33554393  # q ist eine große Primzahl, aber so, dass d*q &amp;lt; 2**32 (um Überlauf zu vermeiden)&lt;br /&gt;
      &lt;br /&gt;
      #Initialisierung      &lt;br /&gt;
      for k in range(N):&lt;br /&gt;
          ht = (ht*d + ord(text[k])) % q&lt;br /&gt;
          #ord() gibt die ASCIInummer des übergebenen Zeichens zurück&lt;br /&gt;
          ds = (hs*d + ord( s[k] )) % q&lt;br /&gt;
          dN = (dN*a) % q&lt;br /&gt;
      #Die Variablen sind jetzt wie folgt initialisiert:&lt;br /&gt;
      #ht = hash(text[0:N])&lt;br /&gt;
      #hs = hash(s)&lt;br /&gt;
      #dN = (d**N) % q&lt;br /&gt;
      &lt;br /&gt;
      #Hauptschleife&lt;br /&gt;
      k = 0 &lt;br /&gt;
      while k &amp;lt; M-N:&lt;br /&gt;
          if hs == ht and s==text[k:k+N]:&lt;br /&gt;
              return k # serch string an Position k gefunden&lt;br /&gt;
          if k+N &amp;lt; M:&lt;br /&gt;
              ht = (d*ht - dN * ord(text[k]) + dN*q + ord(text[k+N]) ) % q&lt;br /&gt;
          k +=1&lt;br /&gt;
      return -1  # search string nicht gefunden&lt;/div&gt;</summary>
		<author><name>Thorben</name></author>	</entry>

	<entry>
		<id>https://alda.iwr.uni-heidelberg.de/index.php?title=Talk:Hashing_und_assoziative_Arrays&amp;diff=1608</id>
		<title>Talk:Hashing und assoziative Arrays</title>
		<link rel="alternate" type="text/html" href="https://alda.iwr.uni-heidelberg.de/index.php?title=Talk:Hashing_und_assoziative_Arrays&amp;diff=1608"/>
				<updated>2008-06-04T17:29:33Z</updated>
		
		<summary type="html">&lt;p&gt;Thorben: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Warum als PDF? Das ist doch völlig am Sinn des Wikis vorbei...&lt;br /&gt;
&lt;br /&gt;
Finde ich auch, wenn du es schon als tex gemacht hast ist es doch super einfach&lt;br /&gt;
es in die Wiki zu übertragen, die unterstützt ja über &amp;lt; math &amp;gt; und &amp;lt; /math &amp;gt; auch&lt;br /&gt;
viele Latexbefehle...&lt;/div&gt;</summary>
		<author><name>Thorben</name></author>	</entry>

	<entry>
		<id>https://alda.iwr.uni-heidelberg.de/index.php?title=Iteration_versus_Rekursion&amp;diff=1606</id>
		<title>Iteration versus Rekursion</title>
		<link rel="alternate" type="text/html" href="https://alda.iwr.uni-heidelberg.de/index.php?title=Iteration_versus_Rekursion&amp;diff=1606"/>
				<updated>2008-06-04T17:28:27Z</updated>
		
		<summary type="html">&lt;p&gt;Thorben: Removing all content from page&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Thorben</name></author>	</entry>

	<entry>
		<id>https://alda.iwr.uni-heidelberg.de/index.php?title=Hashing_und_assoziative_Arrays&amp;diff=1605</id>
		<title>Hashing und assoziative Arrays</title>
		<link rel="alternate" type="text/html" href="https://alda.iwr.uni-heidelberg.de/index.php?title=Hashing_und_assoziative_Arrays&amp;diff=1605"/>
				<updated>2008-06-04T17:27:55Z</updated>
		
		<summary type="html">&lt;p&gt;Thorben: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Mitschrift gibts [http://hci.iwr.uni-heidelberg.de/alda/images/AlDa.pdf hier] als PDF und [http://hci.iwr.uni-heidelberg.de/alda/images/Alda_source.pdf hier] gibts die TeX-Sourcen, leider als PDF weil man wohl keine .TeXs hochladen darf. Originale gibts auf Anfrage bei kirchner at cl dot uni minus heidelberg dot de. Wird das Package &amp;quot;listings&amp;quot; verwendet, das gibts bei [http://tug.ctan.org/tex-archive/macros/latex/contrib/listings/ http://tug.ctan.org/tex-archive/macros/latex/contrib/listings/] &lt;br /&gt;
&lt;br /&gt;
Tipp- und sonstige Fehler dürfen gerne verbessert und erneut hochgeladen werden, oder gebt mir per Email Bescheid, dann pflege ich die   Korrektur ein :)&lt;br /&gt;
&lt;br /&gt;
== Hashtabelle mit linearer Verkettung ==&lt;br /&gt;
Pessimistischer Ansatz: Kollisionen treten häufig auf, deshalb wird unter jedem&lt;br /&gt;
Hashindex gleich eine Liste angelegt, in der Einträge aufgenommen werden können.&lt;br /&gt;
&lt;br /&gt;
===Implementation in Python===&lt;br /&gt;
''HashNode'' ist eine Hilfsdatenstruktur, die Schlüssel und Wert speichert&lt;br /&gt;
und mit hilfe von ''next'' eine verkettete Liste darstellt&lt;br /&gt;
  class HashNode:&lt;br /&gt;
      def __init__(self,key,data,next):&lt;br /&gt;
          self.key = key&lt;br /&gt;
          self.data = data&lt;br /&gt;
          self.next = next #Verkettung!&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Die eigentliche Hashtabelle wir in der Klasse ''HashTable'' implementier:&lt;br /&gt;
  class HashTable:&lt;br /&gt;
      def __init__(self):&lt;br /&gt;
         self.capacity = ... #Geigneter Wert&lt;br /&gt;
         self.size = 0&lt;br /&gt;
         self.array = [None]*self.capacity&lt;br /&gt;
&lt;br /&gt;
In Python wird der Zugriffsoperator ''[ ]'' für eine Datenstruktur wie folgt (innerhalb einer Klasse) implementiert:&lt;br /&gt;
  def __setitem__(self, key, value)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
So dass im Programmtext dann folgender Syntax möglich ist: &amp;lt;tt&amp;gt;a[key] = value&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Genauso wir die Zuweisung &amp;lt;tt&amp;gt;value=a[key]&amp;lt;/tt&amp;gt; wie folgt umgesetzt&lt;br /&gt;
  def __getitem__(self, key, value)&lt;br /&gt;
&lt;br /&gt;
Implementierung der &amp;lt;tt&amp;gt;__setitem__&amp;lt;/tt&amp;gt; Funktionen in der &amp;lt;tt&amp;gt;HashTable&amp;lt;/tt&amp;gt; Klasse:&lt;br /&gt;
  def __setitme__(self, key, value):&lt;br /&gt;
      index = hash(key) % self.capacity&lt;br /&gt;
      node = self.array[index]&lt;br /&gt;
      while node is not None:&lt;br /&gt;
          if node.key == key:&lt;br /&gt;
              #Element key ist schon in der Tabelle&lt;br /&gt;
              #Überschreibe die Daten mit dem neuen Wert&lt;br /&gt;
              node.data = value&lt;br /&gt;
              return&lt;br /&gt;
          #Kollision des Hashwerts, probiere nächsten Key aus&lt;br /&gt;
          node = node.next&lt;br /&gt;
       #Kein Element hatte den richtigen Schlüssel.&lt;br /&gt;
       #==&amp;gt;Es gibt diesen Schlüssel noch nicht&lt;br /&gt;
       #Füge also ein neues Element in die Hashtabelle ein&lt;br /&gt;
       &lt;br /&gt;
       self.array[index] = HashNode(key, value, self.array[index])&lt;br /&gt;
       #Der alte Anfang der List wurde der Nachfolger vom neue eingefügten&lt;br /&gt;
       #ersten Element&lt;br /&gt;
       &lt;br /&gt;
       size+=1&lt;br /&gt;
&lt;br /&gt;
Und die Implementierung der &amp;lt;tt&amp;gt;__getitem__&amp;lt;/tt&amp;gt; Funktionen:&lt;br /&gt;
  def __getItem__(self, key):&lt;br /&gt;
      index = hash(key) % self.capacity&lt;br /&gt;
      node = self.array[index]&lt;br /&gt;
      while node is not None:&lt;br /&gt;
           if node.key == key #Gefunden!&lt;br /&gt;
               return Node.data&lt;br /&gt;
           node = node.next&lt;br /&gt;
      raise KeyError(key)&lt;br /&gt;
&lt;br /&gt;
==== Wahl der Kapazität ====&lt;br /&gt;
In der C++ Standardbibliothek wird typischerweise ein Hash mit Hilfe der linearen Kette&lt;br /&gt;
imlementiert. Dabei wird &amp;lt;tt&amp;gt;capcity&amp;lt;/tt&amp;gt; immer als ''Primzahl'' gewählt, wobei sich aufeinanderfolgende Kapazitäten immer ungefähr verdoppeln:&lt;br /&gt;
  53, 97, 193, 398, 769, ...&lt;br /&gt;
&lt;br /&gt;
Das hat zur Folge, dass &amp;lt;tt&amp;gt;h % self.capacity&amp;lt;/tt&amp;gt; ''alle'' Bits von h benutzt (Eigenschaft aus der Zahlentheorie)&lt;br /&gt;
&lt;br /&gt;
== Hashtabelle mit offener Adressierung (offenes Hashing) ==&lt;br /&gt;
Optimistischer Ansatz: Kollisionen werden nicht so häufig auftreten.&lt;br /&gt;
&lt;br /&gt;
=== Idee ===&lt;br /&gt;
Wenn &amp;lt;tt&amp;gt;array[index]&amp;lt;/tt&amp;gt; durch Kollision bereits vergeben ist, probiere einen&lt;br /&gt;
anderen Index aus.&lt;br /&gt;
&lt;br /&gt;
* Das Array enthält pro Element höchstens ein (key,value)-Paar&lt;br /&gt;
* Das Array muss stets mindestens ''einen'' freien Platz haben (sonst gäbe es eine   Endlosschleife). Es gilt immer &amp;lt;tt&amp;gt;self.size &amp;lt; self.capacity&amp;lt;/tt&amp;gt;. Dies galt für die vorige Hash Implementation nicht.&lt;br /&gt;
&lt;br /&gt;
=== Vorgehen bei Kollisionen ===&lt;br /&gt;
&lt;br /&gt;
==== Sequentielles Suchen ====&lt;br /&gt;
Probiere den nächsten Index: &amp;lt;tt&amp;gt;index = index+1 % capacity&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Vorteil: einfach&lt;br /&gt;
* Nachteil: Clusterbildung&lt;br /&gt;
&lt;br /&gt;
Clusterbildung heißt, dass sich größere zusammenhängende Bereiche bilden die belegt sind, unterbrochen von Bereichen die komplett frei sind. Beim Versuche des Einfügens eines Elements an einen Platz, der schon belegt ist, muss jetzt das ganze Cluster sequentiell durchlaufen werden, bis ein freier Platz gefunden wird. Damit entspricht die Komplexität der Suche der mittleren Länge der belegten Bereiche, was sich entsprechend in einer langsamen Suche widerspiegelt.&lt;br /&gt;
&lt;br /&gt;
==== Doppeltes Hashing ====&lt;br /&gt;
Bestimme einen neuen Index (bei Kollisionen) durch eine ''2. Hashfunktion''.&lt;br /&gt;
&lt;br /&gt;
Das doppelte Hashing wird typischerweise in der Praxis angewendet und liegt auch der Python Implementierung des Datentyps ''Dictionary'' (Syntax &amp;lt;tt&amp;gt;{'a':1, 'b':2, 'c':3}&amp;lt;/tt&amp;gt; zugrunde.&lt;br /&gt;
&lt;br /&gt;
Eine effiziente Implementierung dieses Datentyps ist für die Performance der Skriptsprache Python extrem wichtig, da z.B. beim Aufruf einer Funktion der auszuführunde Code in einem Dictionary unter dem Schlüssel ''Funktionsname'' nachgeschlagen wird oder die Werte lokaler Variablen innerhalb einer Funktion ebenfalls in einem Dictionary zu finden sind.&lt;br /&gt;
&lt;br /&gt;
Für die Implementierung in Python werden wieder die obigen Klassen &amp;lt;tt&amp;gt;HashNode&amp;lt;/tt&amp;gt; und &amp;lt;tt&amp;gt;HashTable&amp;lt;/tt&amp;gt; benötigt, es folgen die angepassten Implementationen von &amp;lt;tt&amp;gt;__setitem&amp;lt;/tt&amp;gt; und &amp;lt;tt&amp;gt;__getitem__&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
  def __setitem__(self, key, value):&lt;br /&gt;
      h = hash(key)&lt;br /&gt;
      index = h % self.capacity&lt;br /&gt;
      while True:&lt;br /&gt;
          if self.array[index] is None or self.array[index].key is None&lt;br /&gt;
               #das Feld ist frei (1. Abfrage)&lt;br /&gt;
               #oder das feld ist als frei markiert (2. Abfrage)&lt;br /&gt;
               self.array[index] = HashNode(key, value)&lt;br /&gt;
               self.size +=1&lt;br /&gt;
               return&lt;br /&gt;
          if self.array[index].key == key:&lt;br /&gt;
               #Es gibt diesen Schlüssel schon,&lt;br /&gt;
               #überschreibe die Daten&lt;br /&gt;
               self.array[index].data = value&lt;br /&gt;
          #Letzter Fall: Kollision&lt;br /&gt;
          index = (5*index+1+h) % self.capacity&lt;br /&gt;
          h = h &amp;gt;&amp;gt; 5&lt;br /&gt;
&lt;br /&gt;
Die vorgestellte Implementierung orientiert sich an Pythons interner Dictionary Implementierung, der zugehörige Quelltext mit ausführlichem Kommentar) findet sich unter [http://svn.python.org/view/*checkout*/python/trunk/Objects/dictobject.c dictobject.c Python Implementation (SVN)]&lt;br /&gt;
&lt;br /&gt;
===== Komplexität des offenen Hashings =====&lt;br /&gt;
&lt;br /&gt;
* Annahme: uniformes Hashing, das heißt alle Indizes haben gleiche Wahrscheinlichkeit&lt;br /&gt;
* Füllstand &amp;lt;math&amp;gt;\alpha = \frac{\text{size}}{\text{capacity}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* '''Erfolglose Suche''' (d.h. es wird entweder ein neues Element eingefügt oder ein &amp;lt;tt&amp;gt;keyError&amp;lt;/tt&amp;gt; geworfen): Untere Schranke für die Komplexität ist &amp;lt;math&amp;gt;\Omega\left(\frac{1}{1-\alpha}\right)&amp;lt;/math&amp;gt; Schritte bzw. Anzahl von neuen index Berechnungen.&lt;br /&gt;
* '''Erfolgreiche Suche''' &amp;lt;math&amp;gt;\Omega\left(\frac{1}{\alpha}\ln\left(\frac{1}{1-\alpha}\right)\right)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;5&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
! &amp;lt;math&amp;gt;\alpha&amp;lt;/math&amp;gt;&lt;br /&gt;
! 0.5&lt;br /&gt;
! 0.9&lt;br /&gt;
|- &lt;br /&gt;
| erfolglos&lt;br /&gt;
| 2.0&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| erfolgreich&lt;br /&gt;
| 1.4&lt;br /&gt;
| 2.6&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===== Wahl der Kapazität =====&lt;br /&gt;
In Python wird &amp;lt;tt&amp;gt;capacity&amp;lt;/tt&amp;gt; Aufgrund der obigen Beobachtung so gewählt, dass &amp;lt;math&amp;gt;\alpha \leq 2/3&amp;lt;/math&amp;gt;. Falls &amp;lt;math&amp;gt;\alpha&amp;lt;/math&amp;gt; größer werden sollte, verdopple die Kapazität und kopiere das alte array in das neue Array (analog zum dynamischen Array)&lt;br /&gt;
&lt;br /&gt;
In Python werden die Kapazitätsgrößen als Zweierpotenzen gewählt, also 4,8,16,32,...,&lt;br /&gt;
so dass &amp;lt;tt&amp;gt;h % self.capacity&amp;lt;/tt&amp;gt; nur die unteren Bits von &amp;lt;tt&amp;gt;h&amp;lt;/tt&amp;gt; benutzt.&lt;br /&gt;
&lt;br /&gt;
== Anwendung von Hashing ==&lt;br /&gt;
&lt;br /&gt;
* Hashtabelle, assoziatives Aray&lt;br /&gt;
* Sortieren in linearer Zeit (Übungsaufgabe 6.2)&lt;br /&gt;
* Suchen von Strings in Texten&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
=== Rabin Karp Algorithmus ===&lt;br /&gt;
In Textverarbeitungsanwendungen ist eine häufig benutzte Funktion die ''Search &amp;amp; Replace'' Funktionalität. Die Suche sollte in O(len(text)) möglich sein, aber ein naiver Algorithmus braucht O(len(text)*len(searchstring))&lt;br /&gt;
&lt;br /&gt;
==== Naive Implementierung der Suche ====&lt;br /&gt;
  def search(text, s):&lt;br /&gt;
      M, N = len(text), len(s)&lt;br /&gt;
      for k in range(M-N):&lt;br /&gt;
          if s==text[k:k+N]&lt;br /&gt;
              return k&lt;br /&gt;
      return -1 #nicht gefunden&lt;br /&gt;
&lt;br /&gt;
==== Idee des Rabin Karp Algorithmus ====&lt;br /&gt;
Statt Vergleichen &amp;lt;tt&amp;gt;s==text[k:k+N], die O(N) benötigen da N Vergleiche der Buchstaben durchgeführt werden müssen, Vergleiche die Hashs von Suchstring und dem zu untersuchenden Textabschnitt: &amp;lt;tt&amp;gt;hash(s) == hash(text[k:k+N])&amp;lt;/tt&amp;gt;. Dabei muss natürlich &amp;lt;tt&amp;gt;hash(s)&amp;lt;/tt&amp;gt; nur einmal berechnet werden, wohingegen &amp;lt;tt&amp;gt;hash(text[k:k+N])&amp;lt;/tt&amp;gt; immer wieder neu berechnet werden muss. Damit der Vergleich O(1) sein kann, ist es deswegen erforderlich, eine solche Hashfunktion zu haben, die nicht alle Zeichen (das wäre O(N) ) einlesen muss, sondern die vorhergehende Hashfunktion mit einbezieht.&lt;br /&gt;
&lt;br /&gt;
Eine solche Hashfunktion heißt ''Running Hash'' und funktioniert analog zum ''Sliding Mean''.&lt;br /&gt;
&lt;br /&gt;
Die Running Hash Funktion berechnet in O(1) den hash von &amp;lt;tt&amp;gt;text[k+1:k+1+N]&amp;lt;/tt&amp;gt; ausgehend vom hash für &amp;lt;tt&amp;gt;text[k:k+N]&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Idee: Interpretiere den Text als Ziffern in einer base d Darstellung:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h_k = \text{text}[k]\cdot d^{N-1} + \text{text}[k]\cdot d^{N-2} + \cdots + \text{text}[k+N-1]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für die Basis 10 (Dezimalsystem) ergibt sich also&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h_k = \text{text}[k]\cdot {10}^{N-1} + \text{text}[k]\cdot {10}^{N-2} + \cdots + \text{text}[k+N-1]&amp;lt;/math&amp;gt;&lt;br /&gt;
Daraus folgt&lt;br /&gt;
&amp;lt;math&amp;gt;h_{k+1} = 10\cdot h_k - \text{text}[k]\cdot {10}^{N} + \text{text}[k+N]&amp;lt;/math&amp;gt;&lt;br /&gt;
Und die Komplexität ist O(1).&lt;br /&gt;
&lt;br /&gt;
In der Realität wählt man dann d=32 und benutzt noch an einigen Stellen modulo Operationen, um die Zahlen nicht zu groß werden zu lassen.&lt;br /&gt;
&lt;br /&gt;
==== Implementation ====&lt;br /&gt;
  def searchRabinKarp(text, s):&lt;br /&gt;
      ht, hs, dN = 0, 0, 1&lt;br /&gt;
      M, N = len(text), len(s)&lt;br /&gt;
      d, q = 32, &amp;lt;sehr große Primzahl&amp;gt;&lt;br /&gt;
      &lt;br /&gt;
      #Initialisierung      &lt;br /&gt;
      for k in range(N):&lt;br /&gt;
          ht = ht*d + ord(text[k]) % q&lt;br /&gt;
          #ord() gibt die ASCIInummer des übergebenen Zeichens zurück&lt;br /&gt;
          ds = hs*d + ord( s[k] )&lt;br /&gt;
          dN = (dN*a) % q&lt;br /&gt;
      #Die Variable sind jetzt wie folgt initialisiert:&lt;br /&gt;
      #ht = hash(text[0:N])&lt;br /&gt;
      #hs = hash(s)&lt;br /&gt;
      #dN = (d**N) % q&lt;br /&gt;
      &lt;br /&gt;
      #Hauptschleife&lt;br /&gt;
      k = 0 &lt;br /&gt;
      while k &amp;lt; M-N:&lt;br /&gt;
          if hs == ht and s==text[k:k+N]:&lt;br /&gt;
              return k&lt;br /&gt;
          ht = (d*ht - dN * ord(text[k]) + dN*q + ord(text[k+M]) ) % q&lt;br /&gt;
          k +=1&lt;br /&gt;
          return -1&lt;/div&gt;</summary>
		<author><name>Thorben</name></author>	</entry>

	<entry>
		<id>https://alda.iwr.uni-heidelberg.de/index.php?title=Iteration_versus_Rekursion&amp;diff=1601</id>
		<title>Iteration versus Rekursion</title>
		<link rel="alternate" type="text/html" href="https://alda.iwr.uni-heidelberg.de/index.php?title=Iteration_versus_Rekursion&amp;diff=1601"/>
				<updated>2008-06-04T17:10:18Z</updated>
		
		<summary type="html">&lt;p&gt;Thorben: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Hashtabelle mit linearer Verkettung ==&lt;br /&gt;
Pessimistischer Ansatz: Kollisionen treten häufig auf, deshalb wird unter jedem&lt;br /&gt;
Hashindex gleich eine Liste angelegt, in der Einträge aufgenommen werden können.&lt;br /&gt;
&lt;br /&gt;
===Implementation in Python===&lt;br /&gt;
''HashNode'' ist eine Hilfsdatenstruktur, die Schlüssel und Wert speichert&lt;br /&gt;
und mit hilfe von ''next'' eine verkettete Liste darstellt&lt;br /&gt;
  class HashNode:&lt;br /&gt;
      def __init__(self,key,data,next):&lt;br /&gt;
          self.key = key&lt;br /&gt;
          self.data = data&lt;br /&gt;
          self.next = next #Verkettung!&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Die eigentliche Hashtabelle wir in der Klasse ''HashTable'' implementier:&lt;br /&gt;
  class HashTable:&lt;br /&gt;
      def __init__(self):&lt;br /&gt;
         self.capacity = ... #Geigneter Wert&lt;br /&gt;
         self.size = 0&lt;br /&gt;
         self.array = [None]*self.capacity&lt;br /&gt;
&lt;br /&gt;
In Python wird der Zugriffsoperator ''[ ]'' für eine Datenstruktur wie folgt (innerhalb einer Klasse) implementiert:&lt;br /&gt;
  def __setitem__(self, key, value)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
So dass im Programmtext dann folgender Syntax möglich ist: &amp;lt;tt&amp;gt;a[key] = value&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Genauso wir die Zuweisung &amp;lt;tt&amp;gt;value=a[key]&amp;lt;/tt&amp;gt; wie folgt umgesetzt&lt;br /&gt;
  def __getitem__(self, key, value)&lt;br /&gt;
&lt;br /&gt;
Implementierung der &amp;lt;tt&amp;gt;__setitem__&amp;lt;/tt&amp;gt; Funktionen in der &amp;lt;tt&amp;gt;HashTable&amp;lt;/tt&amp;gt; Klasse:&lt;br /&gt;
  def __setitme__(self, key, value):&lt;br /&gt;
      index = hash(key) % self.capacity&lt;br /&gt;
      node = self.array[index]&lt;br /&gt;
      while node is not None:&lt;br /&gt;
          if node.key == key:&lt;br /&gt;
              #Element key ist schon in der Tabelle&lt;br /&gt;
              #Überschreibe die Daten mit dem neuen Wert&lt;br /&gt;
              node.data = value&lt;br /&gt;
              return&lt;br /&gt;
          #Kollision des Hashwerts, probiere nächsten Key aus&lt;br /&gt;
          node = node.next&lt;br /&gt;
       #Kein Element hatte den richtigen Schlüssel.&lt;br /&gt;
       #==&amp;gt;Es gibt diesen Schlüssel noch nicht&lt;br /&gt;
       #Füge also ein neues Element in die Hashtabelle ein&lt;br /&gt;
       &lt;br /&gt;
       self.array[index] = HashNode(key, value, self.array[index])&lt;br /&gt;
       #Der alte Anfang der List wurde der Nachfolger vom neue eingefügten&lt;br /&gt;
       #ersten Element&lt;br /&gt;
       &lt;br /&gt;
       size+=1&lt;br /&gt;
&lt;br /&gt;
Und die Implementierung der &amp;lt;tt&amp;gt;__getitem__&amp;lt;/tt&amp;gt; Funktionen:&lt;br /&gt;
  def __getItem__(self, key):&lt;br /&gt;
      index = hash(key) % self.capacity&lt;br /&gt;
      node = self.array[index]&lt;br /&gt;
      while node is not None:&lt;br /&gt;
           if node.key == key #Gefunden!&lt;br /&gt;
               return Node.data&lt;br /&gt;
           node = node.next&lt;br /&gt;
      raise KeyError(key)&lt;br /&gt;
&lt;br /&gt;
==== Wahl der Kapazität ====&lt;br /&gt;
In der C++ Standardbibliothek wird typischerweise ein Hash mit Hilfe der linearen Kette&lt;br /&gt;
imlementiert. Dabei wird &amp;lt;tt&amp;gt;capcity&amp;lt;/tt&amp;gt; immer als ''Primzahl'' gewählt, wobei sich aufeinanderfolgende Kapazitäten immer ungefähr verdoppeln:&lt;br /&gt;
  53, 97, 193, 398, 769, ...&lt;br /&gt;
&lt;br /&gt;
Das hat zur Folge, dass &amp;lt;tt&amp;gt;h % self.capacity&amp;lt;/tt&amp;gt; ''alle'' Bits von h benutzt (Eigenschaft aus der Zahlentheorie)&lt;br /&gt;
&lt;br /&gt;
== Hashtabelle mit offener Adressierung (offenes Hashing) ==&lt;br /&gt;
Optimistischer Ansatz: Kollisionen werden nicht so häufig auftreten.&lt;br /&gt;
&lt;br /&gt;
=== Idee ===&lt;br /&gt;
Wenn &amp;lt;tt&amp;gt;array[index]&amp;lt;/tt&amp;gt; durch Kollision bereits vergeben ist, probiere einen&lt;br /&gt;
anderen Index aus.&lt;br /&gt;
&lt;br /&gt;
* Das Array enthält pro Element höchstens ein (key,value)-Paar&lt;br /&gt;
* Das Array muss stets mindestens ''einen'' freien Platz haben (sonst gäbe es eine   Endlosschleife). Es gilt immer &amp;lt;tt&amp;gt;self.size &amp;lt; self.capacity&amp;lt;/tt&amp;gt;. Dies galt für die vorige Hash Implementation nicht.&lt;br /&gt;
&lt;br /&gt;
=== Vorgehen bei Kollisionen ===&lt;br /&gt;
&lt;br /&gt;
==== Sequentielles Suchen ====&lt;br /&gt;
Probiere den nächsten Index: &amp;lt;tt&amp;gt;index = index+1 % capacity&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Vorteil: einfach&lt;br /&gt;
* Nachteil: Clusterbildung&lt;br /&gt;
&lt;br /&gt;
Clusterbildung heißt, dass sich größere zusammenhängende Bereiche bilden die belegt sind, unterbrochen von Bereichen die komplett frei sind. Beim Versuche des Einfügens eines Elements an einen Platz, der schon belegt ist, muss jetzt das ganze Cluster sequentiell durchlaufen werden, bis ein freier Platz gefunden wird. Damit entspricht die Komplexität der Suche der mittleren Länge der belegten Bereiche, was sich entsprechend in einer langsamen Suche widerspiegelt.&lt;br /&gt;
&lt;br /&gt;
==== Doppeltes Hashing ====&lt;br /&gt;
Bestimme einen neuen Index (bei Kollisionen) durch eine ''2. Hashfunktion''.&lt;br /&gt;
&lt;br /&gt;
Das doppelte Hashing wird typischerweise in der Praxis angewendet und liegt auch der Python Implementierung des Datentyps ''Dictionary'' (Syntax &amp;lt;tt&amp;gt;{'a':1, 'b':2, 'c':3}&amp;lt;/tt&amp;gt; zugrunde.&lt;br /&gt;
&lt;br /&gt;
Eine effiziente Implementierung dieses Datentyps ist für die Performance der Skriptsprache Python extrem wichtig, da z.B. beim Aufruf einer Funktion der auszuführunde Code in einem Dictionary unter dem Schlüssel ''Funktionsname'' nachgeschlagen wird oder die Werte lokaler Variablen innerhalb einer Funktion ebenfalls in einem Dictionary zu finden sind.&lt;br /&gt;
&lt;br /&gt;
Für die Implementierung in Python werden wieder die obigen Klassen &amp;lt;tt&amp;gt;HashNode&amp;lt;/tt&amp;gt; und &amp;lt;tt&amp;gt;HashTable&amp;lt;/tt&amp;gt; benötigt, es folgen die angepassten Implementationen von &amp;lt;tt&amp;gt;__setitem&amp;lt;/tt&amp;gt; und &amp;lt;tt&amp;gt;__getitem__&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
  def __setitem__(self, key, value):&lt;br /&gt;
      h = hash(key)&lt;br /&gt;
      index = h % self.capacity&lt;br /&gt;
      while True:&lt;br /&gt;
          if self.array[index] is None or self.array[index].key is None&lt;br /&gt;
               #das Feld ist frei (1. Abfrage)&lt;br /&gt;
               #oder das feld ist als frei markiert (2. Abfrage)&lt;br /&gt;
               self.array[index] = HashNode(key, value)&lt;br /&gt;
               self.size +=1&lt;br /&gt;
               return&lt;br /&gt;
          if self.array[index].key == key:&lt;br /&gt;
               #Es gibt diesen Schlüssel schon,&lt;br /&gt;
               #überschreibe die Daten&lt;br /&gt;
               self.array[index].data = value&lt;br /&gt;
          #Letzter Fall: Kollision&lt;br /&gt;
          index = (5*index+1+h) % self.capacity&lt;br /&gt;
          h = h &amp;gt;&amp;gt; 5&lt;br /&gt;
&lt;br /&gt;
Die vorgestellte Implementierung orientiert sich an Pythons interner Dictionary Implementierung, der zugehörige Quelltext mit ausführlichem Kommentar) findet sich unter [http://svn.python.org/view/*checkout*/python/trunk/Objects/dictobject.c dictobject.c Python Implementation (SVN)]&lt;br /&gt;
&lt;br /&gt;
===== Komplexität des offenen Hashings =====&lt;br /&gt;
&lt;br /&gt;
* Annahme: uniformes Hashing, das heißt alle Indizes haben gleiche Wahrscheinlichkeit&lt;br /&gt;
* Füllstand &amp;lt;math&amp;gt;\alpha = \frac{\text{size}}{\text{capacity}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* '''Erfolglose Suche''' (d.h. es wird entweder ein neues Element eingefügt oder ein &amp;lt;tt&amp;gt;keyError&amp;lt;/tt&amp;gt; geworfen): Untere Schranke für die Komplexität ist &amp;lt;math&amp;gt;\Omega\left(\frac{1}{1-\alpha}\right)&amp;lt;/math&amp;gt; Schritte bzw. Anzahl von neuen index Berechnungen.&lt;br /&gt;
* '''Erfolgreiche Suche''' &amp;lt;math&amp;gt;\Omega\left(\frac{1}{\alpha}\ln\left(\frac{1}{1-\alpha}\right)\right)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;5&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
! &amp;lt;math&amp;gt;\alpha&amp;lt;/math&amp;gt;&lt;br /&gt;
! 0.5&lt;br /&gt;
! 0.9&lt;br /&gt;
|- &lt;br /&gt;
| erfolglos&lt;br /&gt;
| 2.0&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| erfolgreich&lt;br /&gt;
| 1.4&lt;br /&gt;
| 2.6&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===== Wahl der Kapazität =====&lt;br /&gt;
In Python wird &amp;lt;tt&amp;gt;capacity&amp;lt;/tt&amp;gt; Aufgrund der obigen Beobachtung so gewählt, dass &amp;lt;math&amp;gt;\alpha \leq 2/3&amp;lt;/math&amp;gt;. Falls &amp;lt;math&amp;gt;\alpha&amp;lt;/math&amp;gt; größer werden sollte, verdopple die Kapazität und kopiere das alte array in das neue Array (analog zum dynamischen Array)&lt;br /&gt;
&lt;br /&gt;
In Python werden die Kapazitätsgrößen als Zweierpotenzen gewählt, also 4,8,16,32,...,&lt;br /&gt;
so dass &amp;lt;tt&amp;gt;h % self.capacity&amp;lt;/tt&amp;gt; nur die unteren Bits von &amp;lt;tt&amp;gt;h&amp;lt;/tt&amp;gt; benutzt.&lt;br /&gt;
&lt;br /&gt;
== Anwendung von Hashing ==&lt;br /&gt;
&lt;br /&gt;
* Hashtabelle, assoziatives Aray&lt;br /&gt;
* Sortieren in linearer Zeit (Übungsaufgabe 6.2)&lt;br /&gt;
* Suchen von Strings in Texten&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
=== Rabin Karp Algorithmus ===&lt;br /&gt;
In Textverarbeitungsanwendungen ist eine häufig benutzte Funktion die ''Search &amp;amp; Replace'' Funktionalität. Die Suche sollte in O(len(text)) möglich sein, aber ein naiver Algorithmus braucht O(len(text)*len(searchstring))&lt;br /&gt;
&lt;br /&gt;
==== Naive Implementierung der Suche ====&lt;br /&gt;
  def search(text, s):&lt;br /&gt;
      M, N = len(text), len(s)&lt;br /&gt;
      for k in range(M-N):&lt;br /&gt;
          if s==text[k:k+N]&lt;br /&gt;
              return k&lt;br /&gt;
      return -1 #nicht gefunden&lt;br /&gt;
&lt;br /&gt;
==== Idee des Rabin Karp Algorithmus ====&lt;br /&gt;
Statt Vergleichen &amp;lt;tt&amp;gt;s==text[k:k+N], die O(N) benötigen da N Vergleiche der Buchstaben durchgeführt werden müssen, Vergleiche die Hashs von Suchstring und dem zu untersuchenden Textabschnitt: &amp;lt;tt&amp;gt;hash(s) == hash(text[k:k+N])&amp;lt;/tt&amp;gt;. Dabei muss natürlich &amp;lt;tt&amp;gt;hash(s)&amp;lt;/tt&amp;gt; nur einmal berechnet werden, wohingegen &amp;lt;tt&amp;gt;hash(text[k:k+N])&amp;lt;/tt&amp;gt; immer wieder neu berechnet werden muss. Damit der Vergleich O(1) sein kann, ist es deswegen erforderlich, eine solche Hashfunktion zu haben, die nicht alle Zeichen (das wäre O(N) ) einlesen muss, sondern die vorhergehende Hashfunktion mit einbezieht.&lt;br /&gt;
&lt;br /&gt;
Eine solche Hashfunktion heißt ''Running Hash'' und funktioniert analog zum ''Sliding Mean''.&lt;br /&gt;
&lt;br /&gt;
Die Running Hash Funktion berechnet in O(1) den hash von &amp;lt;tt&amp;gt;text[k+1:k+1+N]&amp;lt;/tt&amp;gt; ausgehend vom hash für &amp;lt;tt&amp;gt;text[k:k+N]&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Idee: Interpretiere den Text als Ziffern in einer base d Darstellung:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h_k = \text{text}[k]\cdot d^{N-1} + \text{text}[k]\cdot d^{N-2} + \cdots + \text{text}[k+N-1]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für die Basis 10 (Dezimalsystem) ergibt sich also&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h_k = \text{text}[k]\cdot {10}^{N-1} + \text{text}[k]\cdot {10}^{N-2} + \cdots + \text{text}[k+N-1]&amp;lt;/math&amp;gt;&lt;br /&gt;
Daraus folgt&lt;br /&gt;
&amp;lt;math&amp;gt;h_{k+1} = 10\cdot h_k - \text{text}[k]\cdot {10}^{N} + \text{text}[k+N]&amp;lt;/math&amp;gt;&lt;br /&gt;
Und die Komplexität ist O(1).&lt;br /&gt;
&lt;br /&gt;
In der Realität wählt man dann d=32 und benutzt noch an einigen Stellen modulo Operationen, um die Zahlen nicht zu groß werden zu lassen.&lt;br /&gt;
&lt;br /&gt;
==== Implementation ====&lt;br /&gt;
  def searchRabinKarp(text, s):&lt;br /&gt;
      ht, hs, dN = 0, 0, 1&lt;br /&gt;
      M, N = len(text), len(s)&lt;br /&gt;
      d, q = 32, &amp;lt;sehr große Primzahl&amp;gt;&lt;br /&gt;
      &lt;br /&gt;
      #Initialisierung      &lt;br /&gt;
      for k in range(N):&lt;br /&gt;
          ht = ht*d + ord(text[k]) % q&lt;br /&gt;
          #ord() gibt die ASCIInummer des übergebenen Zeichens zurück&lt;br /&gt;
          ds = hs*d + ord( s[k] )&lt;br /&gt;
          dN = (dN*a) % q&lt;br /&gt;
      #Die Variable sind jetzt wie folgt initialisiert:&lt;br /&gt;
      #ht = hash(text[0:N])&lt;br /&gt;
      #hs = hash(s)&lt;br /&gt;
      #dN = (d**N) % q&lt;br /&gt;
      &lt;br /&gt;
      #Hauptschleife&lt;br /&gt;
      k = 0 &lt;br /&gt;
      while k &amp;lt; M-N:&lt;br /&gt;
          if hs == ht and s==text[k:k+N]:&lt;br /&gt;
              return k&lt;br /&gt;
          ht = (d*ht - dN * ord(text[k]) + dN*q + ord(text[k+M]) ) % q&lt;br /&gt;
          k +=1&lt;br /&gt;
          return -1&lt;/div&gt;</summary>
		<author><name>Thorben</name></author>	</entry>

	<entry>
		<id>https://alda.iwr.uni-heidelberg.de/index.php?title=Iteration_versus_Rekursion&amp;diff=1600</id>
		<title>Iteration versus Rekursion</title>
		<link rel="alternate" type="text/html" href="https://alda.iwr.uni-heidelberg.de/index.php?title=Iteration_versus_Rekursion&amp;diff=1600"/>
				<updated>2008-06-04T17:08:36Z</updated>
		
		<summary type="html">&lt;p&gt;Thorben: /* Implementation */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Hashtabelle mit linearer Verkettung ==&lt;br /&gt;
Pessimistischer Ansatz: Kollisionen treten häufig auf, deshalb wird unter jedem&lt;br /&gt;
Hashindex gleich eine Liste angelegt, in der Einträge aufgenommen werden können.&lt;br /&gt;
&lt;br /&gt;
===Implementation in Python===&lt;br /&gt;
''HashNode'' ist eine Hilfsdatenstruktur, die Schlüssel und Wert speichert&lt;br /&gt;
und mit hilfe von ''next'' eine verkettete Liste darstellt&lt;br /&gt;
  class HashNode:&lt;br /&gt;
      def __init__(self,key,data,next):&lt;br /&gt;
          self.key = key&lt;br /&gt;
          self.data = data&lt;br /&gt;
          self.next = next #Verkettung!&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Die eigentliche Hashtabelle wir in der Klasse ''HashTable'' implementier:&lt;br /&gt;
  class HashTable:&lt;br /&gt;
      def __init__(self):&lt;br /&gt;
         self.capacity = ... #Geigneter Wert&lt;br /&gt;
         self.size = 0&lt;br /&gt;
         self.array = [None]*self.capacity&lt;br /&gt;
&lt;br /&gt;
In Python wird der Zugriffsoperator ''[ ]'' für eine Datenstruktur wie folgt (innerhalb einer Klasse) implementiert:&lt;br /&gt;
  def __setitem__(self, key, value)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
So dass im Programmtext dann folgender Syntax möglich ist: &amp;lt;tt&amp;gt;a[key] = value&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Genauso wir die Zuweisung &amp;lt;tt&amp;gt;value=a[key]&amp;lt;/tt&amp;gt; wie folgt umgesetzt&lt;br /&gt;
  def __getitem__(self, key, value)&lt;br /&gt;
&lt;br /&gt;
Implementierung der &amp;lt;tt&amp;gt;__setitem__&amp;lt;/tt&amp;gt; Funktionen in der &amp;lt;tt&amp;gt;HashTable&amp;lt;/tt&amp;gt; Klasse:&lt;br /&gt;
  def __setitme__(self, key, value):&lt;br /&gt;
      index = hash(key) % self.capacity&lt;br /&gt;
      node = self.array[index]&lt;br /&gt;
      while node is not None:&lt;br /&gt;
          if node.key == key:&lt;br /&gt;
              #Element key ist schon in der Tabelle&lt;br /&gt;
              #Überschreibe die Daten mit dem neuen Wert&lt;br /&gt;
              node.data = value&lt;br /&gt;
              return&lt;br /&gt;
          #Kollision des Hashwerts, probiere nächsten Key aus&lt;br /&gt;
          node = node.next&lt;br /&gt;
       #Kein Element hatte den richtigen Schlüssel.&lt;br /&gt;
       #==&amp;gt;Es gibt diesen Schlüssel noch nicht&lt;br /&gt;
       #Füge also ein neues Element in die Hashtabelle ein&lt;br /&gt;
       &lt;br /&gt;
       self.array[index] = HashNode(key, value, self.array[index])&lt;br /&gt;
       #Der alte Anfang der List wurde der Nachfolger vom neue eingefügten&lt;br /&gt;
       #ersten Element&lt;br /&gt;
       &lt;br /&gt;
       size+=1&lt;br /&gt;
&lt;br /&gt;
Und die Implementierung der &amp;lt;tt&amp;gt;__getitem__&amp;lt;/tt&amp;gt; Funktionen:&lt;br /&gt;
  def __getItem__(self, key):&lt;br /&gt;
      index = hash(key) % self.capacity&lt;br /&gt;
      node = self.array[index]&lt;br /&gt;
      while node is not None:&lt;br /&gt;
           if node.key == key #Gefunden!&lt;br /&gt;
               return Node.data&lt;br /&gt;
           node = node.next&lt;br /&gt;
      raise KeyError(key)&lt;br /&gt;
&lt;br /&gt;
==== Wahl der Kapazität ====&lt;br /&gt;
In der C++ Standardbibliothek wird typischerweise ein Hash mit Hilfe der linearen Kette&lt;br /&gt;
imlementiert. Dabei wird &amp;lt;tt&amp;gt;capcity&amp;lt;/tt&amp;gt; immer als ''Primzahl'' gewählt, wobei sich aufeinanderfolgende Kapazitäten immer ungefähr verdoppeln:&lt;br /&gt;
  53, 97, 193, 398, 769, ...&lt;br /&gt;
&lt;br /&gt;
Das hat zur Folge, dass &amp;lt;tt&amp;gt;h % self.capacity&amp;lt;/tt&amp;gt; ''alle'' Bits von h benutzt (Eigenschaft aus der Zahlentheorie)&lt;br /&gt;
&lt;br /&gt;
== Hashtabelle mit offener Adressierung (offenes Hashing) ==&lt;br /&gt;
Optimistischer Ansatz: Kollisionen werden nicht so häufig auftreten.&lt;br /&gt;
&lt;br /&gt;
=== Idee ===&lt;br /&gt;
Wenn &amp;lt;tt&amp;gt;array[index]&amp;lt;/tt&amp;gt; durch Kollision bereits vergeben ist, probiere einen&lt;br /&gt;
anderen Index aus.&lt;br /&gt;
&lt;br /&gt;
* Das Array enthält pro Element höchstens ein (key,value)-Paar&lt;br /&gt;
* Das Array muss stets mindestens ''einen'' freien Platz haben (sonst gäbe es eine   Endlosschleife). Es gilt immer &amp;lt;tt&amp;gt;self.size &amp;lt; self.capacity&amp;lt;/tt&amp;gt;. Dies galt für die vorige Hash Implementation nicht.&lt;br /&gt;
&lt;br /&gt;
=== Vorgehen bei Kollisionen ===&lt;br /&gt;
&lt;br /&gt;
==== Sequentielles Suchen ====&lt;br /&gt;
Probiere den nächsten Index: &amp;lt;tt&amp;gt;index = index+1 % capacity&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Vorteil: einfach&lt;br /&gt;
* Nachteil: Clusterbildung&lt;br /&gt;
&lt;br /&gt;
Clusterbildung heißt, dass sich größere zusammenhängende Bereiche bilden die belegt sind, unterbrochen von Bereichen die komplett frei sind. Beim Versuche des Einfügens eines Elements an einen Platz, der schon belegt ist, muss jetzt das ganze Cluster sequentiell durchlaufen werden, bis ein freier Platz gefunden wird. Damit entspricht die Komplexität der Suche der mittleren Länge der belegten Bereiche, was sich entsprechend in einer langsamen Suche widerspiegelt.&lt;br /&gt;
&lt;br /&gt;
==== Doppeltes Hashing ====&lt;br /&gt;
Bestimme einen neuen Index (bei Kollisionen) durch eine ''2. Hashfunktion''.&lt;br /&gt;
&lt;br /&gt;
Das doppelte Hashing wird typischerweise in der Praxis angewendet und liegt auch der Python Implementierung des Datentyps ''Dictionary'' (Syntax &amp;lt;tt&amp;gt;{'a':1, 'b':2, 'c':3}&amp;lt;/tt&amp;gt; zugrunde.&lt;br /&gt;
&lt;br /&gt;
Eine effiziente Implementierung dieses Datentyps ist für die Performance der Skriptsprache Python extrem wichtig, da z.B. beim Aufruf einer Funktion der auszuführunde Code in einem Dictionary unter dem Schlüssel ''Funktionsname'' nachgeschlagen wird oder die Werte lokaler Variablen innerhalb einer Funktion ebenfalls in einem Dictionary zu finden sind.&lt;br /&gt;
&lt;br /&gt;
Für die Implementierung in Python werden wieder die obigen Klassen &amp;lt;tt&amp;gt;HashNode&amp;lt;/tt&amp;gt; und &amp;lt;tt&amp;gt;HashTable&amp;lt;/tt&amp;gt; benötigt, es folgen die angepassten Implementationen von &amp;lt;tt&amp;gt;__setitem&amp;lt;/tt&amp;gt; und &amp;lt;tt&amp;gt;__getitem__&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
  def __setitem__(self, key, value):&lt;br /&gt;
      h = hash(key)&lt;br /&gt;
      index = h % self.capacity&lt;br /&gt;
      while True:&lt;br /&gt;
          if self.array[index] is None or self.array[index].key is None&lt;br /&gt;
               #das Feld ist frei (1. Abfrage)&lt;br /&gt;
               #oder das feld ist als frei markiert (2. Abfrage)&lt;br /&gt;
               self.array[index] = HashNode(key, value)&lt;br /&gt;
               self.size +=1&lt;br /&gt;
               return&lt;br /&gt;
          if self.array[index].key == key:&lt;br /&gt;
               #Es gibt diesen Schlüssel schon,&lt;br /&gt;
               #überschreibe die Daten&lt;br /&gt;
               self.array[index].data = value&lt;br /&gt;
          #Letzter Fall: Kollision&lt;br /&gt;
          index = (5*index+1+h) % self.capacity&lt;br /&gt;
          h = h &amp;gt;&amp;gt; 5&lt;br /&gt;
&lt;br /&gt;
Die vorgestellte Implementierung orientiert sich an Pythons interner Dictionary Implementierung, der zugehörige Quelltext mit ausführlichem Kommentar) findet sich unter [http://svn.python.org/view/*checkout*/python/trunk/Objects/dictobject.c dictobject.c Python Implementation (SVN)]&lt;br /&gt;
&lt;br /&gt;
===== Komplexität des offenen Hashings =====&lt;br /&gt;
&lt;br /&gt;
* Annahme: uniformes Hashing, das heißt alle Indizes haben gleiche Wahrscheinlichkeit&lt;br /&gt;
* Füllstand &amp;lt;math&amp;gt;\alpha = \frac{\text{size}}{\text{capacity}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* '''Erfolglose Suche''' (d.h. es wird entweder ein neues Element eingefügt oder ein &amp;lt;tt&amp;gt;keyError&amp;lt;/tt&amp;gt; geworfen): Untere Schranke für die Komplexität ist &amp;lt;math&amp;gt;\Omega\left(\frac{1}{1-\alpha}\right)&amp;lt;/math&amp;gt; Schritte bzw. Anzahl von neuen index Berechnungen.&lt;br /&gt;
* '''Erfolgreiche Suche''' &amp;lt;math&amp;gt;\Omega\left(\frac{1}{\alpha}\ln\left(\frac{1}{1-\alpha}\right)\right)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;5&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
! &amp;lt;math&amp;gt;\alpha&amp;lt;/math&amp;gt;&lt;br /&gt;
! 0.5&lt;br /&gt;
! 0.9&lt;br /&gt;
|- &lt;br /&gt;
| erfolglos&lt;br /&gt;
| 2.0&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| erfolgreich&lt;br /&gt;
| 1.4&lt;br /&gt;
| 2.6&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===== Wahl der Kapazität =====&lt;br /&gt;
In Python wird &amp;lt;tt&amp;gt;capacity&amp;lt;/tt&amp;gt; Aufgrund der obigen Beobachtung so gewählt, dass &amp;lt;math&amp;gt;\alpha \leq 2/3&amp;lt;/math&amp;gt;. Falls &amp;lt;math&amp;gt;\alpha&amp;lt;/math&amp;gt; größer werden sollte, verdopple die Kapazität und kopiere das alte array in das neue Array (analog zum dynamischen Array)&lt;br /&gt;
&lt;br /&gt;
In Python werden die Kapazitätsgrößen als Zweierpotenzen gewählt, also 4,8,16,32,...,&lt;br /&gt;
so dass &amp;lt;tt&amp;gt;h % self.capacity&amp;lt;/tt&amp;gt; nur die unteren Bits von &amp;lt;tt&amp;gt;h&amp;lt;/tt&amp;gt; benutzt.&lt;br /&gt;
&lt;br /&gt;
== Anwendung von Hashing ==&lt;br /&gt;
&lt;br /&gt;
* Hashtabelle, assoziatives Aray&lt;br /&gt;
* Sortieren in linearer Zeit (Übungsaufgabe 6.2)&lt;br /&gt;
* Suchen von Strings in Texten&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
=== Rabin Karp Algorithmus ===&lt;br /&gt;
In Textverarbeitungsanwendungen ist eine häufig benutzte Funktion die ''Search &amp;amp; Replace'' Funktionalität. Die Suche sollte in O(len(text)) möglich sein, aber ein naiver Algorithmus braucht O(len(text)*len(searchstring))&lt;br /&gt;
&lt;br /&gt;
==== Naive Implementierung der Suche ====&lt;br /&gt;
  def search(text, s):&lt;br /&gt;
      M, N = len(text), len(s)&lt;br /&gt;
      for k in range(M-N):&lt;br /&gt;
          if s==text[k:k+N]&lt;br /&gt;
              return k&lt;br /&gt;
      return -1 #nicht gefunden&lt;br /&gt;
&lt;br /&gt;
==== Idee des Rabin Karp Algorithmus ====&lt;br /&gt;
Statt Vergleichen &amp;lt;tt&amp;gt;s==text[k:k+N], die O(N) benötigen da N Vergleiche der Buchstaben durchgeführt werden müssen, Vergleiche die Hashs von Suchstring und dem zu untersuchenden Textabschnitt: &amp;lt;tt&amp;gt;hash(s) == hash(text[k:k+N])&amp;lt;/tt&amp;gt;. Dabei muss natürlich &amp;lt;tt&amp;gt;hash(s)&amp;lt;/tt&amp;gt; nur einmal berechnet werden, wohingegen &amp;lt;tt&amp;gt;hash(text[k:k+N])&amp;lt;/tt&amp;gt; immer wieder neu berechnet werden muss. Damit der Vergleich O(1) sein kann, ist es deswegen erforderlich, eine solche Hashfunktion zu haben, die nicht alle Zeichen (das wäre O(N) ) einlesen muss, sondern die vorhergehende Hashfunktion mit einbezieht.&lt;br /&gt;
&lt;br /&gt;
Eine solche Hashfunktion heißt ''Running Hash'' und funktioniert analog zum ''Sliding Mean''.&lt;br /&gt;
&lt;br /&gt;
Die Running Hash Funktion berechnet in O(1) den hash von &amp;lt;tt&amp;gt;text[k+1:k+1+N]&amp;lt;/tt&amp;gt; ausgehend vom hash für &amp;lt;tt&amp;gt;text[k:k+N]&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Idee: Interpretiere den Text als Ziffern in einer base d Darstellung:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h_k = \text{text}[k]\cdot d^{N-1} + \text{text}[k]\cdot d^{N-2} + \cdots + \text{text}[k+N-1]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für die Basis 10 (Dezimalsystem) ergibt sich also&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h_k = \text{text}[k]\cdot {10}^{N-1} + \text{text}[k]\cdot {10}^{N-2} + \cdots + \text{text}[k+N-1]&amp;lt;/math&amp;gt;&lt;br /&gt;
Daraus folgt&lt;br /&gt;
&amp;lt;math&amp;gt;h_{k+1} = 10\cdot h_k - \text{text}[k]\cdot {10}^{N} + \text{text}[k+N]&amp;lt;/math&amp;gt;&lt;br /&gt;
Und die Komplexität ist O(1).&lt;br /&gt;
&lt;br /&gt;
In der Realität wählt man dann d=32 und benutzt noch an einigen Stellen modulo Operationen, um die Zahlen nicht zu groß werden zu lassen.&lt;br /&gt;
&lt;br /&gt;
==== Implementation ====&lt;br /&gt;
  def searchRabinKarp(text, s):&lt;br /&gt;
      ht, hs, dN = 0, 0, 1&lt;br /&gt;
      M, N = len(text), len(s)&lt;br /&gt;
      d, q = 32, &amp;lt;sehr große Primzahl&amp;gt;&lt;br /&gt;
      &lt;br /&gt;
      #Initialisierung      &lt;br /&gt;
      for k in range(N):&lt;br /&gt;
          ht = ht*d + ord(text[k]) % q&lt;br /&gt;
          #ord() gibt die ASCIInummer des übergebenen Zeichens zurück&lt;br /&gt;
          ds = hs*d + ord( s[k] )&lt;br /&gt;
          dN = (dN*a) % q&lt;br /&gt;
      #Die Variable sind jetzt wie folgt initialisiert:&lt;br /&gt;
      #ht = hash(text[0:N])&lt;br /&gt;
      #hs = hash(s)&lt;br /&gt;
      #dN = (d**N) % q&lt;br /&gt;
      &lt;br /&gt;
      k = 0 &lt;br /&gt;
      while k &amp;lt; M-N:&lt;br /&gt;
          if hs == ht and s==text[k:k+N]:&lt;br /&gt;
              return k&lt;br /&gt;
          ht = (d*ht - dN * ord(text[k]) + dN*q + ord(text[k+M]) ) % q&lt;br /&gt;
          k +=1&lt;br /&gt;
          return -1&lt;br /&gt;
      &lt;br /&gt;
      #Hauptschleife&lt;/div&gt;</summary>
		<author><name>Thorben</name></author>	</entry>

	<entry>
		<id>https://alda.iwr.uni-heidelberg.de/index.php?title=Iteration_versus_Rekursion&amp;diff=1599</id>
		<title>Iteration versus Rekursion</title>
		<link rel="alternate" type="text/html" href="https://alda.iwr.uni-heidelberg.de/index.php?title=Iteration_versus_Rekursion&amp;diff=1599"/>
				<updated>2008-06-04T17:07:26Z</updated>
		
		<summary type="html">&lt;p&gt;Thorben: /* Idee des Rabin Karp Algorithmus */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Hashtabelle mit linearer Verkettung ==&lt;br /&gt;
Pessimistischer Ansatz: Kollisionen treten häufig auf, deshalb wird unter jedem&lt;br /&gt;
Hashindex gleich eine Liste angelegt, in der Einträge aufgenommen werden können.&lt;br /&gt;
&lt;br /&gt;
===Implementation in Python===&lt;br /&gt;
''HashNode'' ist eine Hilfsdatenstruktur, die Schlüssel und Wert speichert&lt;br /&gt;
und mit hilfe von ''next'' eine verkettete Liste darstellt&lt;br /&gt;
  class HashNode:&lt;br /&gt;
      def __init__(self,key,data,next):&lt;br /&gt;
          self.key = key&lt;br /&gt;
          self.data = data&lt;br /&gt;
          self.next = next #Verkettung!&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Die eigentliche Hashtabelle wir in der Klasse ''HashTable'' implementier:&lt;br /&gt;
  class HashTable:&lt;br /&gt;
      def __init__(self):&lt;br /&gt;
         self.capacity = ... #Geigneter Wert&lt;br /&gt;
         self.size = 0&lt;br /&gt;
         self.array = [None]*self.capacity&lt;br /&gt;
&lt;br /&gt;
In Python wird der Zugriffsoperator ''[ ]'' für eine Datenstruktur wie folgt (innerhalb einer Klasse) implementiert:&lt;br /&gt;
  def __setitem__(self, key, value)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
So dass im Programmtext dann folgender Syntax möglich ist: &amp;lt;tt&amp;gt;a[key] = value&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Genauso wir die Zuweisung &amp;lt;tt&amp;gt;value=a[key]&amp;lt;/tt&amp;gt; wie folgt umgesetzt&lt;br /&gt;
  def __getitem__(self, key, value)&lt;br /&gt;
&lt;br /&gt;
Implementierung der &amp;lt;tt&amp;gt;__setitem__&amp;lt;/tt&amp;gt; Funktionen in der &amp;lt;tt&amp;gt;HashTable&amp;lt;/tt&amp;gt; Klasse:&lt;br /&gt;
  def __setitme__(self, key, value):&lt;br /&gt;
      index = hash(key) % self.capacity&lt;br /&gt;
      node = self.array[index]&lt;br /&gt;
      while node is not None:&lt;br /&gt;
          if node.key == key:&lt;br /&gt;
              #Element key ist schon in der Tabelle&lt;br /&gt;
              #Überschreibe die Daten mit dem neuen Wert&lt;br /&gt;
              node.data = value&lt;br /&gt;
              return&lt;br /&gt;
          #Kollision des Hashwerts, probiere nächsten Key aus&lt;br /&gt;
          node = node.next&lt;br /&gt;
       #Kein Element hatte den richtigen Schlüssel.&lt;br /&gt;
       #==&amp;gt;Es gibt diesen Schlüssel noch nicht&lt;br /&gt;
       #Füge also ein neues Element in die Hashtabelle ein&lt;br /&gt;
       &lt;br /&gt;
       self.array[index] = HashNode(key, value, self.array[index])&lt;br /&gt;
       #Der alte Anfang der List wurde der Nachfolger vom neue eingefügten&lt;br /&gt;
       #ersten Element&lt;br /&gt;
       &lt;br /&gt;
       size+=1&lt;br /&gt;
&lt;br /&gt;
Und die Implementierung der &amp;lt;tt&amp;gt;__getitem__&amp;lt;/tt&amp;gt; Funktionen:&lt;br /&gt;
  def __getItem__(self, key):&lt;br /&gt;
      index = hash(key) % self.capacity&lt;br /&gt;
      node = self.array[index]&lt;br /&gt;
      while node is not None:&lt;br /&gt;
           if node.key == key #Gefunden!&lt;br /&gt;
               return Node.data&lt;br /&gt;
           node = node.next&lt;br /&gt;
      raise KeyError(key)&lt;br /&gt;
&lt;br /&gt;
==== Wahl der Kapazität ====&lt;br /&gt;
In der C++ Standardbibliothek wird typischerweise ein Hash mit Hilfe der linearen Kette&lt;br /&gt;
imlementiert. Dabei wird &amp;lt;tt&amp;gt;capcity&amp;lt;/tt&amp;gt; immer als ''Primzahl'' gewählt, wobei sich aufeinanderfolgende Kapazitäten immer ungefähr verdoppeln:&lt;br /&gt;
  53, 97, 193, 398, 769, ...&lt;br /&gt;
&lt;br /&gt;
Das hat zur Folge, dass &amp;lt;tt&amp;gt;h % self.capacity&amp;lt;/tt&amp;gt; ''alle'' Bits von h benutzt (Eigenschaft aus der Zahlentheorie)&lt;br /&gt;
&lt;br /&gt;
== Hashtabelle mit offener Adressierung (offenes Hashing) ==&lt;br /&gt;
Optimistischer Ansatz: Kollisionen werden nicht so häufig auftreten.&lt;br /&gt;
&lt;br /&gt;
=== Idee ===&lt;br /&gt;
Wenn &amp;lt;tt&amp;gt;array[index]&amp;lt;/tt&amp;gt; durch Kollision bereits vergeben ist, probiere einen&lt;br /&gt;
anderen Index aus.&lt;br /&gt;
&lt;br /&gt;
* Das Array enthält pro Element höchstens ein (key,value)-Paar&lt;br /&gt;
* Das Array muss stets mindestens ''einen'' freien Platz haben (sonst gäbe es eine   Endlosschleife). Es gilt immer &amp;lt;tt&amp;gt;self.size &amp;lt; self.capacity&amp;lt;/tt&amp;gt;. Dies galt für die vorige Hash Implementation nicht.&lt;br /&gt;
&lt;br /&gt;
=== Vorgehen bei Kollisionen ===&lt;br /&gt;
&lt;br /&gt;
==== Sequentielles Suchen ====&lt;br /&gt;
Probiere den nächsten Index: &amp;lt;tt&amp;gt;index = index+1 % capacity&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Vorteil: einfach&lt;br /&gt;
* Nachteil: Clusterbildung&lt;br /&gt;
&lt;br /&gt;
Clusterbildung heißt, dass sich größere zusammenhängende Bereiche bilden die belegt sind, unterbrochen von Bereichen die komplett frei sind. Beim Versuche des Einfügens eines Elements an einen Platz, der schon belegt ist, muss jetzt das ganze Cluster sequentiell durchlaufen werden, bis ein freier Platz gefunden wird. Damit entspricht die Komplexität der Suche der mittleren Länge der belegten Bereiche, was sich entsprechend in einer langsamen Suche widerspiegelt.&lt;br /&gt;
&lt;br /&gt;
==== Doppeltes Hashing ====&lt;br /&gt;
Bestimme einen neuen Index (bei Kollisionen) durch eine ''2. Hashfunktion''.&lt;br /&gt;
&lt;br /&gt;
Das doppelte Hashing wird typischerweise in der Praxis angewendet und liegt auch der Python Implementierung des Datentyps ''Dictionary'' (Syntax &amp;lt;tt&amp;gt;{'a':1, 'b':2, 'c':3}&amp;lt;/tt&amp;gt; zugrunde.&lt;br /&gt;
&lt;br /&gt;
Eine effiziente Implementierung dieses Datentyps ist für die Performance der Skriptsprache Python extrem wichtig, da z.B. beim Aufruf einer Funktion der auszuführunde Code in einem Dictionary unter dem Schlüssel ''Funktionsname'' nachgeschlagen wird oder die Werte lokaler Variablen innerhalb einer Funktion ebenfalls in einem Dictionary zu finden sind.&lt;br /&gt;
&lt;br /&gt;
Für die Implementierung in Python werden wieder die obigen Klassen &amp;lt;tt&amp;gt;HashNode&amp;lt;/tt&amp;gt; und &amp;lt;tt&amp;gt;HashTable&amp;lt;/tt&amp;gt; benötigt, es folgen die angepassten Implementationen von &amp;lt;tt&amp;gt;__setitem&amp;lt;/tt&amp;gt; und &amp;lt;tt&amp;gt;__getitem__&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
  def __setitem__(self, key, value):&lt;br /&gt;
      h = hash(key)&lt;br /&gt;
      index = h % self.capacity&lt;br /&gt;
      while True:&lt;br /&gt;
          if self.array[index] is None or self.array[index].key is None&lt;br /&gt;
               #das Feld ist frei (1. Abfrage)&lt;br /&gt;
               #oder das feld ist als frei markiert (2. Abfrage)&lt;br /&gt;
               self.array[index] = HashNode(key, value)&lt;br /&gt;
               self.size +=1&lt;br /&gt;
               return&lt;br /&gt;
          if self.array[index].key == key:&lt;br /&gt;
               #Es gibt diesen Schlüssel schon,&lt;br /&gt;
               #überschreibe die Daten&lt;br /&gt;
               self.array[index].data = value&lt;br /&gt;
          #Letzter Fall: Kollision&lt;br /&gt;
          index = (5*index+1+h) % self.capacity&lt;br /&gt;
          h = h &amp;gt;&amp;gt; 5&lt;br /&gt;
&lt;br /&gt;
Die vorgestellte Implementierung orientiert sich an Pythons interner Dictionary Implementierung, der zugehörige Quelltext mit ausführlichem Kommentar) findet sich unter [http://svn.python.org/view/*checkout*/python/trunk/Objects/dictobject.c dictobject.c Python Implementation (SVN)]&lt;br /&gt;
&lt;br /&gt;
===== Komplexität des offenen Hashings =====&lt;br /&gt;
&lt;br /&gt;
* Annahme: uniformes Hashing, das heißt alle Indizes haben gleiche Wahrscheinlichkeit&lt;br /&gt;
* Füllstand &amp;lt;math&amp;gt;\alpha = \frac{\text{size}}{\text{capacity}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* '''Erfolglose Suche''' (d.h. es wird entweder ein neues Element eingefügt oder ein &amp;lt;tt&amp;gt;keyError&amp;lt;/tt&amp;gt; geworfen): Untere Schranke für die Komplexität ist &amp;lt;math&amp;gt;\Omega\left(\frac{1}{1-\alpha}\right)&amp;lt;/math&amp;gt; Schritte bzw. Anzahl von neuen index Berechnungen.&lt;br /&gt;
* '''Erfolgreiche Suche''' &amp;lt;math&amp;gt;\Omega\left(\frac{1}{\alpha}\ln\left(\frac{1}{1-\alpha}\right)\right)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;5&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
! &amp;lt;math&amp;gt;\alpha&amp;lt;/math&amp;gt;&lt;br /&gt;
! 0.5&lt;br /&gt;
! 0.9&lt;br /&gt;
|- &lt;br /&gt;
| erfolglos&lt;br /&gt;
| 2.0&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| erfolgreich&lt;br /&gt;
| 1.4&lt;br /&gt;
| 2.6&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===== Wahl der Kapazität =====&lt;br /&gt;
In Python wird &amp;lt;tt&amp;gt;capacity&amp;lt;/tt&amp;gt; Aufgrund der obigen Beobachtung so gewählt, dass &amp;lt;math&amp;gt;\alpha \leq 2/3&amp;lt;/math&amp;gt;. Falls &amp;lt;math&amp;gt;\alpha&amp;lt;/math&amp;gt; größer werden sollte, verdopple die Kapazität und kopiere das alte array in das neue Array (analog zum dynamischen Array)&lt;br /&gt;
&lt;br /&gt;
In Python werden die Kapazitätsgrößen als Zweierpotenzen gewählt, also 4,8,16,32,...,&lt;br /&gt;
so dass &amp;lt;tt&amp;gt;h % self.capacity&amp;lt;/tt&amp;gt; nur die unteren Bits von &amp;lt;tt&amp;gt;h&amp;lt;/tt&amp;gt; benutzt.&lt;br /&gt;
&lt;br /&gt;
== Anwendung von Hashing ==&lt;br /&gt;
&lt;br /&gt;
* Hashtabelle, assoziatives Aray&lt;br /&gt;
* Sortieren in linearer Zeit (Übungsaufgabe 6.2)&lt;br /&gt;
* Suchen von Strings in Texten&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
=== Rabin Karp Algorithmus ===&lt;br /&gt;
In Textverarbeitungsanwendungen ist eine häufig benutzte Funktion die ''Search &amp;amp; Replace'' Funktionalität. Die Suche sollte in O(len(text)) möglich sein, aber ein naiver Algorithmus braucht O(len(text)*len(searchstring))&lt;br /&gt;
&lt;br /&gt;
==== Naive Implementierung der Suche ====&lt;br /&gt;
  def search(text, s):&lt;br /&gt;
      M, N = len(text), len(s)&lt;br /&gt;
      for k in range(M-N):&lt;br /&gt;
          if s==text[k:k+N]&lt;br /&gt;
              return k&lt;br /&gt;
      return -1 #nicht gefunden&lt;br /&gt;
&lt;br /&gt;
==== Idee des Rabin Karp Algorithmus ====&lt;br /&gt;
Statt Vergleichen &amp;lt;tt&amp;gt;s==text[k:k+N], die O(N) benötigen da N Vergleiche der Buchstaben durchgeführt werden müssen, Vergleiche die Hashs von Suchstring und dem zu untersuchenden Textabschnitt: &amp;lt;tt&amp;gt;hash(s) == hash(text[k:k+N])&amp;lt;/tt&amp;gt;. Dabei muss natürlich &amp;lt;tt&amp;gt;hash(s)&amp;lt;/tt&amp;gt; nur einmal berechnet werden, wohingegen &amp;lt;tt&amp;gt;hash(text[k:k+N])&amp;lt;/tt&amp;gt; immer wieder neu berechnet werden muss. Damit der Vergleich O(1) sein kann, ist es deswegen erforderlich, eine solche Hashfunktion zu haben, die nicht alle Zeichen (das wäre O(N) ) einlesen muss, sondern die vorhergehende Hashfunktion mit einbezieht.&lt;br /&gt;
&lt;br /&gt;
Eine solche Hashfunktion heißt ''Running Hash'' und funktioniert analog zum ''Sliding Mean''.&lt;br /&gt;
&lt;br /&gt;
Die Running Hash Funktion berechnet in O(1) den hash von &amp;lt;tt&amp;gt;text[k+1:k+1+N]&amp;lt;/tt&amp;gt; ausgehend vom hash für &amp;lt;tt&amp;gt;text[k:k+N]&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Idee: Interpretiere den Text als Ziffern in einer base d Darstellung:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h_k = \text{text}[k]\cdot d^{N-1} + \text{text}[k]\cdot d^{N-2} + \cdots + \text{text}[k+N-1]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für die Basis 10 (Dezimalsystem) ergibt sich also&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h_k = \text{text}[k]\cdot {10}^{N-1} + \text{text}[k]\cdot {10}^{N-2} + \cdots + \text{text}[k+N-1]&amp;lt;/math&amp;gt;&lt;br /&gt;
Daraus folgt&lt;br /&gt;
&amp;lt;math&amp;gt;h_{k+1} = 10\cdot h_k - \text{text}[k]\cdot {10}^{N} + \text{text}[k+N]&amp;lt;/math&amp;gt;&lt;br /&gt;
Und die Komplexität ist O(1).&lt;br /&gt;
&lt;br /&gt;
In der Realität wählt man dann d=32 und benutzt noch an einigen Stellen modulo Operationen, um die Zahlen nicht zu groß werden zu lassen.&lt;br /&gt;
&lt;br /&gt;
==== Implementation ====&lt;br /&gt;
  def searchRabinKarp(text, s):&lt;br /&gt;
      ht, hs, dN = 0, 0, 1&lt;br /&gt;
      M, N = len(text), len(s)&lt;br /&gt;
      d, q = 32, &amp;lt;sehr große Primzahl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
      #Initialisierung      &lt;br /&gt;
      for k in range(N):&lt;br /&gt;
          ht = ht*d + ord(text[k]) % q&lt;br /&gt;
          #ord() gibt die ASCIInummer des übergebenen Zeichens zurück&lt;br /&gt;
          ds = hs*d + ord( s[k] )&lt;br /&gt;
          dN = (dN*a) % q&lt;br /&gt;
      #Die Variable sind jetzt wie folgt initialisiert:&lt;br /&gt;
      #ht = hash(text[0:N])&lt;br /&gt;
      #hs = hash(s)&lt;br /&gt;
      #dN = (d**N) % q&lt;br /&gt;
&lt;br /&gt;
  k = 0 &lt;br /&gt;
  while k &amp;lt; M-N:&lt;br /&gt;
     if hs == ht and s==text[k:k+N]:&lt;br /&gt;
         return k&lt;br /&gt;
     ht = (d*ht - dN * ord(text[k]) + dN*q + ord(text[k+M]) ) % q&lt;br /&gt;
     k +=1&lt;br /&gt;
  return -1&lt;br /&gt;
&lt;br /&gt;
      #Hauptschleife&lt;/div&gt;</summary>
		<author><name>Thorben</name></author>	</entry>

	<entry>
		<id>https://alda.iwr.uni-heidelberg.de/index.php?title=Iteration_versus_Rekursion&amp;diff=1598</id>
		<title>Iteration versus Rekursion</title>
		<link rel="alternate" type="text/html" href="https://alda.iwr.uni-heidelberg.de/index.php?title=Iteration_versus_Rekursion&amp;diff=1598"/>
				<updated>2008-06-04T17:07:06Z</updated>
		
		<summary type="html">&lt;p&gt;Thorben: /* Rabin Karp Algorithmus */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Hashtabelle mit linearer Verkettung ==&lt;br /&gt;
Pessimistischer Ansatz: Kollisionen treten häufig auf, deshalb wird unter jedem&lt;br /&gt;
Hashindex gleich eine Liste angelegt, in der Einträge aufgenommen werden können.&lt;br /&gt;
&lt;br /&gt;
===Implementation in Python===&lt;br /&gt;
''HashNode'' ist eine Hilfsdatenstruktur, die Schlüssel und Wert speichert&lt;br /&gt;
und mit hilfe von ''next'' eine verkettete Liste darstellt&lt;br /&gt;
  class HashNode:&lt;br /&gt;
      def __init__(self,key,data,next):&lt;br /&gt;
          self.key = key&lt;br /&gt;
          self.data = data&lt;br /&gt;
          self.next = next #Verkettung!&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Die eigentliche Hashtabelle wir in der Klasse ''HashTable'' implementier:&lt;br /&gt;
  class HashTable:&lt;br /&gt;
      def __init__(self):&lt;br /&gt;
         self.capacity = ... #Geigneter Wert&lt;br /&gt;
         self.size = 0&lt;br /&gt;
         self.array = [None]*self.capacity&lt;br /&gt;
&lt;br /&gt;
In Python wird der Zugriffsoperator ''[ ]'' für eine Datenstruktur wie folgt (innerhalb einer Klasse) implementiert:&lt;br /&gt;
  def __setitem__(self, key, value)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
So dass im Programmtext dann folgender Syntax möglich ist: &amp;lt;tt&amp;gt;a[key] = value&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Genauso wir die Zuweisung &amp;lt;tt&amp;gt;value=a[key]&amp;lt;/tt&amp;gt; wie folgt umgesetzt&lt;br /&gt;
  def __getitem__(self, key, value)&lt;br /&gt;
&lt;br /&gt;
Implementierung der &amp;lt;tt&amp;gt;__setitem__&amp;lt;/tt&amp;gt; Funktionen in der &amp;lt;tt&amp;gt;HashTable&amp;lt;/tt&amp;gt; Klasse:&lt;br /&gt;
  def __setitme__(self, key, value):&lt;br /&gt;
      index = hash(key) % self.capacity&lt;br /&gt;
      node = self.array[index]&lt;br /&gt;
      while node is not None:&lt;br /&gt;
          if node.key == key:&lt;br /&gt;
              #Element key ist schon in der Tabelle&lt;br /&gt;
              #Überschreibe die Daten mit dem neuen Wert&lt;br /&gt;
              node.data = value&lt;br /&gt;
              return&lt;br /&gt;
          #Kollision des Hashwerts, probiere nächsten Key aus&lt;br /&gt;
          node = node.next&lt;br /&gt;
       #Kein Element hatte den richtigen Schlüssel.&lt;br /&gt;
       #==&amp;gt;Es gibt diesen Schlüssel noch nicht&lt;br /&gt;
       #Füge also ein neues Element in die Hashtabelle ein&lt;br /&gt;
       &lt;br /&gt;
       self.array[index] = HashNode(key, value, self.array[index])&lt;br /&gt;
       #Der alte Anfang der List wurde der Nachfolger vom neue eingefügten&lt;br /&gt;
       #ersten Element&lt;br /&gt;
       &lt;br /&gt;
       size+=1&lt;br /&gt;
&lt;br /&gt;
Und die Implementierung der &amp;lt;tt&amp;gt;__getitem__&amp;lt;/tt&amp;gt; Funktionen:&lt;br /&gt;
  def __getItem__(self, key):&lt;br /&gt;
      index = hash(key) % self.capacity&lt;br /&gt;
      node = self.array[index]&lt;br /&gt;
      while node is not None:&lt;br /&gt;
           if node.key == key #Gefunden!&lt;br /&gt;
               return Node.data&lt;br /&gt;
           node = node.next&lt;br /&gt;
      raise KeyError(key)&lt;br /&gt;
&lt;br /&gt;
==== Wahl der Kapazität ====&lt;br /&gt;
In der C++ Standardbibliothek wird typischerweise ein Hash mit Hilfe der linearen Kette&lt;br /&gt;
imlementiert. Dabei wird &amp;lt;tt&amp;gt;capcity&amp;lt;/tt&amp;gt; immer als ''Primzahl'' gewählt, wobei sich aufeinanderfolgende Kapazitäten immer ungefähr verdoppeln:&lt;br /&gt;
  53, 97, 193, 398, 769, ...&lt;br /&gt;
&lt;br /&gt;
Das hat zur Folge, dass &amp;lt;tt&amp;gt;h % self.capacity&amp;lt;/tt&amp;gt; ''alle'' Bits von h benutzt (Eigenschaft aus der Zahlentheorie)&lt;br /&gt;
&lt;br /&gt;
== Hashtabelle mit offener Adressierung (offenes Hashing) ==&lt;br /&gt;
Optimistischer Ansatz: Kollisionen werden nicht so häufig auftreten.&lt;br /&gt;
&lt;br /&gt;
=== Idee ===&lt;br /&gt;
Wenn &amp;lt;tt&amp;gt;array[index]&amp;lt;/tt&amp;gt; durch Kollision bereits vergeben ist, probiere einen&lt;br /&gt;
anderen Index aus.&lt;br /&gt;
&lt;br /&gt;
* Das Array enthält pro Element höchstens ein (key,value)-Paar&lt;br /&gt;
* Das Array muss stets mindestens ''einen'' freien Platz haben (sonst gäbe es eine   Endlosschleife). Es gilt immer &amp;lt;tt&amp;gt;self.size &amp;lt; self.capacity&amp;lt;/tt&amp;gt;. Dies galt für die vorige Hash Implementation nicht.&lt;br /&gt;
&lt;br /&gt;
=== Vorgehen bei Kollisionen ===&lt;br /&gt;
&lt;br /&gt;
==== Sequentielles Suchen ====&lt;br /&gt;
Probiere den nächsten Index: &amp;lt;tt&amp;gt;index = index+1 % capacity&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Vorteil: einfach&lt;br /&gt;
* Nachteil: Clusterbildung&lt;br /&gt;
&lt;br /&gt;
Clusterbildung heißt, dass sich größere zusammenhängende Bereiche bilden die belegt sind, unterbrochen von Bereichen die komplett frei sind. Beim Versuche des Einfügens eines Elements an einen Platz, der schon belegt ist, muss jetzt das ganze Cluster sequentiell durchlaufen werden, bis ein freier Platz gefunden wird. Damit entspricht die Komplexität der Suche der mittleren Länge der belegten Bereiche, was sich entsprechend in einer langsamen Suche widerspiegelt.&lt;br /&gt;
&lt;br /&gt;
==== Doppeltes Hashing ====&lt;br /&gt;
Bestimme einen neuen Index (bei Kollisionen) durch eine ''2. Hashfunktion''.&lt;br /&gt;
&lt;br /&gt;
Das doppelte Hashing wird typischerweise in der Praxis angewendet und liegt auch der Python Implementierung des Datentyps ''Dictionary'' (Syntax &amp;lt;tt&amp;gt;{'a':1, 'b':2, 'c':3}&amp;lt;/tt&amp;gt; zugrunde.&lt;br /&gt;
&lt;br /&gt;
Eine effiziente Implementierung dieses Datentyps ist für die Performance der Skriptsprache Python extrem wichtig, da z.B. beim Aufruf einer Funktion der auszuführunde Code in einem Dictionary unter dem Schlüssel ''Funktionsname'' nachgeschlagen wird oder die Werte lokaler Variablen innerhalb einer Funktion ebenfalls in einem Dictionary zu finden sind.&lt;br /&gt;
&lt;br /&gt;
Für die Implementierung in Python werden wieder die obigen Klassen &amp;lt;tt&amp;gt;HashNode&amp;lt;/tt&amp;gt; und &amp;lt;tt&amp;gt;HashTable&amp;lt;/tt&amp;gt; benötigt, es folgen die angepassten Implementationen von &amp;lt;tt&amp;gt;__setitem&amp;lt;/tt&amp;gt; und &amp;lt;tt&amp;gt;__getitem__&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
  def __setitem__(self, key, value):&lt;br /&gt;
      h = hash(key)&lt;br /&gt;
      index = h % self.capacity&lt;br /&gt;
      while True:&lt;br /&gt;
          if self.array[index] is None or self.array[index].key is None&lt;br /&gt;
               #das Feld ist frei (1. Abfrage)&lt;br /&gt;
               #oder das feld ist als frei markiert (2. Abfrage)&lt;br /&gt;
               self.array[index] = HashNode(key, value)&lt;br /&gt;
               self.size +=1&lt;br /&gt;
               return&lt;br /&gt;
          if self.array[index].key == key:&lt;br /&gt;
               #Es gibt diesen Schlüssel schon,&lt;br /&gt;
               #überschreibe die Daten&lt;br /&gt;
               self.array[index].data = value&lt;br /&gt;
          #Letzter Fall: Kollision&lt;br /&gt;
          index = (5*index+1+h) % self.capacity&lt;br /&gt;
          h = h &amp;gt;&amp;gt; 5&lt;br /&gt;
&lt;br /&gt;
Die vorgestellte Implementierung orientiert sich an Pythons interner Dictionary Implementierung, der zugehörige Quelltext mit ausführlichem Kommentar) findet sich unter [http://svn.python.org/view/*checkout*/python/trunk/Objects/dictobject.c dictobject.c Python Implementation (SVN)]&lt;br /&gt;
&lt;br /&gt;
===== Komplexität des offenen Hashings =====&lt;br /&gt;
&lt;br /&gt;
* Annahme: uniformes Hashing, das heißt alle Indizes haben gleiche Wahrscheinlichkeit&lt;br /&gt;
* Füllstand &amp;lt;math&amp;gt;\alpha = \frac{\text{size}}{\text{capacity}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* '''Erfolglose Suche''' (d.h. es wird entweder ein neues Element eingefügt oder ein &amp;lt;tt&amp;gt;keyError&amp;lt;/tt&amp;gt; geworfen): Untere Schranke für die Komplexität ist &amp;lt;math&amp;gt;\Omega\left(\frac{1}{1-\alpha}\right)&amp;lt;/math&amp;gt; Schritte bzw. Anzahl von neuen index Berechnungen.&lt;br /&gt;
* '''Erfolgreiche Suche''' &amp;lt;math&amp;gt;\Omega\left(\frac{1}{\alpha}\ln\left(\frac{1}{1-\alpha}\right)\right)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;5&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
! &amp;lt;math&amp;gt;\alpha&amp;lt;/math&amp;gt;&lt;br /&gt;
! 0.5&lt;br /&gt;
! 0.9&lt;br /&gt;
|- &lt;br /&gt;
| erfolglos&lt;br /&gt;
| 2.0&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| erfolgreich&lt;br /&gt;
| 1.4&lt;br /&gt;
| 2.6&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===== Wahl der Kapazität =====&lt;br /&gt;
In Python wird &amp;lt;tt&amp;gt;capacity&amp;lt;/tt&amp;gt; Aufgrund der obigen Beobachtung so gewählt, dass &amp;lt;math&amp;gt;\alpha \leq 2/3&amp;lt;/math&amp;gt;. Falls &amp;lt;math&amp;gt;\alpha&amp;lt;/math&amp;gt; größer werden sollte, verdopple die Kapazität und kopiere das alte array in das neue Array (analog zum dynamischen Array)&lt;br /&gt;
&lt;br /&gt;
In Python werden die Kapazitätsgrößen als Zweierpotenzen gewählt, also 4,8,16,32,...,&lt;br /&gt;
so dass &amp;lt;tt&amp;gt;h % self.capacity&amp;lt;/tt&amp;gt; nur die unteren Bits von &amp;lt;tt&amp;gt;h&amp;lt;/tt&amp;gt; benutzt.&lt;br /&gt;
&lt;br /&gt;
== Anwendung von Hashing ==&lt;br /&gt;
&lt;br /&gt;
* Hashtabelle, assoziatives Aray&lt;br /&gt;
* Sortieren in linearer Zeit (Übungsaufgabe 6.2)&lt;br /&gt;
* Suchen von Strings in Texten&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
=== Rabin Karp Algorithmus ===&lt;br /&gt;
In Textverarbeitungsanwendungen ist eine häufig benutzte Funktion die ''Search &amp;amp; Replace'' Funktionalität. Die Suche sollte in O(len(text)) möglich sein, aber ein naiver Algorithmus braucht O(len(text)*len(searchstring))&lt;br /&gt;
&lt;br /&gt;
==== Naive Implementierung der Suche ====&lt;br /&gt;
  def search(text, s):&lt;br /&gt;
      M, N = len(text), len(s)&lt;br /&gt;
      for k in range(M-N):&lt;br /&gt;
          if s==text[k:k+N]&lt;br /&gt;
              return k&lt;br /&gt;
      return -1 #nicht gefunden&lt;br /&gt;
&lt;br /&gt;
==== Idee des Rabin Karp Algorithmus ====&lt;br /&gt;
Statt Vergleichen &amp;lt;tt&amp;gt;s==text[k:k+N], die O(N) benötigen da N Vergleiche der Buchstaben durchgeführt werden müssen, Vergleiche die Hashs von Suchstring und dem zu untersuchenden Textabschnitt: &amp;lt;tt&amp;gt;hash(s) == hash(text[k:k+N])&amp;lt;/tt&amp;gt;. Dabei muss natürlich &amp;lt;tt&amp;gt;hash(s)&amp;lt;/tt&amp;gt; nur einmal berechnet werden, wohingegen &amp;lt;tt&amp;gt;hash(text[k:k+N])&amp;lt;/tt&amp;gt; immer wieder neu berechnet werden muss. Damit der Vergleich O(1) sein kann, ist es deswegen erforderlich, eine solche Hashfunktion zu haben, die nicht alle Zeichen (das wäre O(N) ) einlesen muss, sondern die vorhergehende Hashfunktion mit einbezieht.&lt;br /&gt;
&lt;br /&gt;
Eine solche Hashfunktion heißt ''Running Hash'' und funktioniert analog zum ''Sliding Mean''.&lt;br /&gt;
&lt;br /&gt;
Die Running Hash Funktion berechnet in O(1) den hash von &amp;lt;tt&amp;gt;text[k+1:k+1+N]&amp;lt;/tt&amp;gt; ausgehend vom hash für &amp;lt;tt&amp;gt;text[k:k+N]&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Idee: Interpretiere den Text als Ziffern in einer base d Darstellung:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h_k = \text{text}[k]\cdot d^{N-1} + \text{text}[k]\cdot d^{N-2} + \cdots + \text{text}[k+N-1]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für die Basis 10 (Dezimalsystem) ergibt sich also&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h_k = \text{text}[k]\cdot {10}^{N-1} + \text{text}[k]\cdot {10}^{N-2} + \cdots + \text{text}[k+N-1]&amp;lt;/math&amp;gt;&lt;br /&gt;
Daraus folgt&lt;br /&gt;
&amp;lt;math&amp;gt;h_{k+1} = 10\cdot h_k - \text{text}[k]\cdot {10}^{N} + \text{text}[k+N]&amp;lt;/math&amp;gt;&lt;br /&gt;
Und die Komplexität ist O(1).&lt;br /&gt;
&lt;br /&gt;
In der Realität wählt man dann d=32 und benutzt noch an einigen Stellen modulo Operationen, um die Zahlen nicht zu groß werden zu lassen.&lt;br /&gt;
&lt;br /&gt;
==== Implementation ====+&lt;br /&gt;
  def searchRabinKarp(text, s):&lt;br /&gt;
      ht, hs, dN = 0, 0, 1&lt;br /&gt;
      M, N = len(text), len(s)&lt;br /&gt;
      d, q = 32, &amp;lt;sehr große Primzahl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
      #Initialisierung      &lt;br /&gt;
      for k in range(N):&lt;br /&gt;
          ht = ht*d + ord(text[k]) % q&lt;br /&gt;
          #ord() gibt die ASCIInummer des übergebenen Zeichens zurück&lt;br /&gt;
          ds = hs*d + ord( s[k] )&lt;br /&gt;
          dN = (dN*a) % q&lt;br /&gt;
      #Die Variable sind jetzt wie folgt initialisiert:&lt;br /&gt;
      #ht = hash(text[0:N])&lt;br /&gt;
      #hs = hash(s)&lt;br /&gt;
      #dN = (d**N) % q&lt;br /&gt;
&lt;br /&gt;
  k = 0 &lt;br /&gt;
  while k &amp;lt; M-N:&lt;br /&gt;
     if hs == ht and s==text[k:k+N]:&lt;br /&gt;
         return k&lt;br /&gt;
     ht = (d*ht - dN * ord(text[k]) + dN*q + ord(text[k+M]) ) % q&lt;br /&gt;
     k +=1&lt;br /&gt;
  return -1&lt;br /&gt;
&lt;br /&gt;
      #Hauptschleife&lt;/div&gt;</summary>
		<author><name>Thorben</name></author>	</entry>

	<entry>
		<id>https://alda.iwr.uni-heidelberg.de/index.php?title=Iteration_versus_Rekursion&amp;diff=1597</id>
		<title>Iteration versus Rekursion</title>
		<link rel="alternate" type="text/html" href="https://alda.iwr.uni-heidelberg.de/index.php?title=Iteration_versus_Rekursion&amp;diff=1597"/>
				<updated>2008-06-04T16:51:24Z</updated>
		
		<summary type="html">&lt;p&gt;Thorben: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Hashtabelle mit linearer Verkettung ==&lt;br /&gt;
Pessimistischer Ansatz: Kollisionen treten häufig auf, deshalb wird unter jedem&lt;br /&gt;
Hashindex gleich eine Liste angelegt, in der Einträge aufgenommen werden können.&lt;br /&gt;
&lt;br /&gt;
===Implementation in Python===&lt;br /&gt;
''HashNode'' ist eine Hilfsdatenstruktur, die Schlüssel und Wert speichert&lt;br /&gt;
und mit hilfe von ''next'' eine verkettete Liste darstellt&lt;br /&gt;
  class HashNode:&lt;br /&gt;
      def __init__(self,key,data,next):&lt;br /&gt;
          self.key = key&lt;br /&gt;
          self.data = data&lt;br /&gt;
          self.next = next #Verkettung!&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Die eigentliche Hashtabelle wir in der Klasse ''HashTable'' implementier:&lt;br /&gt;
  class HashTable:&lt;br /&gt;
      def __init__(self):&lt;br /&gt;
         self.capacity = ... #Geigneter Wert&lt;br /&gt;
         self.size = 0&lt;br /&gt;
         self.array = [None]*self.capacity&lt;br /&gt;
&lt;br /&gt;
In Python wird der Zugriffsoperator ''[ ]'' für eine Datenstruktur wie folgt (innerhalb einer Klasse) implementiert:&lt;br /&gt;
  def __setitem__(self, key, value)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
So dass im Programmtext dann folgender Syntax möglich ist: &amp;lt;tt&amp;gt;a[key] = value&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Genauso wir die Zuweisung &amp;lt;tt&amp;gt;value=a[key]&amp;lt;/tt&amp;gt; wie folgt umgesetzt&lt;br /&gt;
  def __getitem__(self, key, value)&lt;br /&gt;
&lt;br /&gt;
Implementierung der &amp;lt;tt&amp;gt;__setitem__&amp;lt;/tt&amp;gt; Funktionen in der &amp;lt;tt&amp;gt;HashTable&amp;lt;/tt&amp;gt; Klasse:&lt;br /&gt;
  def __setitme__(self, key, value):&lt;br /&gt;
      index = hash(key) % self.capacity&lt;br /&gt;
      node = self.array[index]&lt;br /&gt;
      while node is not None:&lt;br /&gt;
          if node.key == key:&lt;br /&gt;
              #Element key ist schon in der Tabelle&lt;br /&gt;
              #Überschreibe die Daten mit dem neuen Wert&lt;br /&gt;
              node.data = value&lt;br /&gt;
              return&lt;br /&gt;
          #Kollision des Hashwerts, probiere nächsten Key aus&lt;br /&gt;
          node = node.next&lt;br /&gt;
       #Kein Element hatte den richtigen Schlüssel.&lt;br /&gt;
       #==&amp;gt;Es gibt diesen Schlüssel noch nicht&lt;br /&gt;
       #Füge also ein neues Element in die Hashtabelle ein&lt;br /&gt;
       &lt;br /&gt;
       self.array[index] = HashNode(key, value, self.array[index])&lt;br /&gt;
       #Der alte Anfang der List wurde der Nachfolger vom neue eingefügten&lt;br /&gt;
       #ersten Element&lt;br /&gt;
       &lt;br /&gt;
       size+=1&lt;br /&gt;
&lt;br /&gt;
Und die Implementierung der &amp;lt;tt&amp;gt;__getitem__&amp;lt;/tt&amp;gt; Funktionen:&lt;br /&gt;
  def __getItem__(self, key):&lt;br /&gt;
      index = hash(key) % self.capacity&lt;br /&gt;
      node = self.array[index]&lt;br /&gt;
      while node is not None:&lt;br /&gt;
           if node.key == key #Gefunden!&lt;br /&gt;
               return Node.data&lt;br /&gt;
           node = node.next&lt;br /&gt;
      raise KeyError(key)&lt;br /&gt;
&lt;br /&gt;
==== Wahl der Kapazität ====&lt;br /&gt;
In der C++ Standardbibliothek wird typischerweise ein Hash mit Hilfe der linearen Kette&lt;br /&gt;
imlementiert. Dabei wird &amp;lt;tt&amp;gt;capcity&amp;lt;/tt&amp;gt; immer als ''Primzahl'' gewählt, wobei sich aufeinanderfolgende Kapazitäten immer ungefähr verdoppeln:&lt;br /&gt;
  53, 97, 193, 398, 769, ...&lt;br /&gt;
&lt;br /&gt;
Das hat zur Folge, dass &amp;lt;tt&amp;gt;h % self.capacity&amp;lt;/tt&amp;gt; ''alle'' Bits von h benutzt (Eigenschaft aus der Zahlentheorie)&lt;br /&gt;
&lt;br /&gt;
== Hashtabelle mit offener Adressierung (offenes Hashing) ==&lt;br /&gt;
Optimistischer Ansatz: Kollisionen werden nicht so häufig auftreten.&lt;br /&gt;
&lt;br /&gt;
=== Idee ===&lt;br /&gt;
Wenn &amp;lt;tt&amp;gt;array[index]&amp;lt;/tt&amp;gt; durch Kollision bereits vergeben ist, probiere einen&lt;br /&gt;
anderen Index aus.&lt;br /&gt;
&lt;br /&gt;
* Das Array enthält pro Element höchstens ein (key,value)-Paar&lt;br /&gt;
* Das Array muss stets mindestens ''einen'' freien Platz haben (sonst gäbe es eine   Endlosschleife). Es gilt immer &amp;lt;tt&amp;gt;self.size &amp;lt; self.capacity&amp;lt;/tt&amp;gt;. Dies galt für die vorige Hash Implementation nicht.&lt;br /&gt;
&lt;br /&gt;
=== Vorgehen bei Kollisionen ===&lt;br /&gt;
&lt;br /&gt;
==== Sequentielles Suchen ====&lt;br /&gt;
Probiere den nächsten Index: &amp;lt;tt&amp;gt;index = index+1 % capacity&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Vorteil: einfach&lt;br /&gt;
* Nachteil: Clusterbildung&lt;br /&gt;
&lt;br /&gt;
Clusterbildung heißt, dass sich größere zusammenhängende Bereiche bilden die belegt sind, unterbrochen von Bereichen die komplett frei sind. Beim Versuche des Einfügens eines Elements an einen Platz, der schon belegt ist, muss jetzt das ganze Cluster sequentiell durchlaufen werden, bis ein freier Platz gefunden wird. Damit entspricht die Komplexität der Suche der mittleren Länge der belegten Bereiche, was sich entsprechend in einer langsamen Suche widerspiegelt.&lt;br /&gt;
&lt;br /&gt;
==== Doppeltes Hashing ====&lt;br /&gt;
Bestimme einen neuen Index (bei Kollisionen) durch eine ''2. Hashfunktion''.&lt;br /&gt;
&lt;br /&gt;
Das doppelte Hashing wird typischerweise in der Praxis angewendet und liegt auch der Python Implementierung des Datentyps ''Dictionary'' (Syntax &amp;lt;tt&amp;gt;{'a':1, 'b':2, 'c':3}&amp;lt;/tt&amp;gt; zugrunde.&lt;br /&gt;
&lt;br /&gt;
Eine effiziente Implementierung dieses Datentyps ist für die Performance der Skriptsprache Python extrem wichtig, da z.B. beim Aufruf einer Funktion der auszuführunde Code in einem Dictionary unter dem Schlüssel ''Funktionsname'' nachgeschlagen wird oder die Werte lokaler Variablen innerhalb einer Funktion ebenfalls in einem Dictionary zu finden sind.&lt;br /&gt;
&lt;br /&gt;
Für die Implementierung in Python werden wieder die obigen Klassen &amp;lt;tt&amp;gt;HashNode&amp;lt;/tt&amp;gt; und &amp;lt;tt&amp;gt;HashTable&amp;lt;/tt&amp;gt; benötigt, es folgen die angepassten Implementationen von &amp;lt;tt&amp;gt;__setitem&amp;lt;/tt&amp;gt; und &amp;lt;tt&amp;gt;__getitem__&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
  def __setitem__(self, key, value):&lt;br /&gt;
      h = hash(key)&lt;br /&gt;
      index = h % self.capacity&lt;br /&gt;
      while True:&lt;br /&gt;
          if self.array[index] is None or self.array[index].key is None&lt;br /&gt;
               #das Feld ist frei (1. Abfrage)&lt;br /&gt;
               #oder das feld ist als frei markiert (2. Abfrage)&lt;br /&gt;
               self.array[index] = HashNode(key, value)&lt;br /&gt;
               self.size +=1&lt;br /&gt;
               return&lt;br /&gt;
          if self.array[index].key == key:&lt;br /&gt;
               #Es gibt diesen Schlüssel schon,&lt;br /&gt;
               #überschreibe die Daten&lt;br /&gt;
               self.array[index].data = value&lt;br /&gt;
          #Letzter Fall: Kollision&lt;br /&gt;
          index = (5*index+1+h) % self.capacity&lt;br /&gt;
          h = h &amp;gt;&amp;gt; 5&lt;br /&gt;
&lt;br /&gt;
Die vorgestellte Implementierung orientiert sich an Pythons interner Dictionary Implementierung, der zugehörige Quelltext mit ausführlichem Kommentar) findet sich unter [http://svn.python.org/view/*checkout*/python/trunk/Objects/dictobject.c dictobject.c Python Implementation (SVN)]&lt;br /&gt;
&lt;br /&gt;
===== Komplexität des offenen Hashings =====&lt;br /&gt;
&lt;br /&gt;
* Annahme: uniformes Hashing, das heißt alle Indizes haben gleiche Wahrscheinlichkeit&lt;br /&gt;
* Füllstand &amp;lt;math&amp;gt;\alpha = \frac{\text{size}}{\text{capacity}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* '''Erfolglose Suche''' (d.h. es wird entweder ein neues Element eingefügt oder ein &amp;lt;tt&amp;gt;keyError&amp;lt;/tt&amp;gt; geworfen): Untere Schranke für die Komplexität ist &amp;lt;math&amp;gt;\Omega\left(\frac{1}{1-\alpha}\right)&amp;lt;/math&amp;gt; Schritte bzw. Anzahl von neuen index Berechnungen.&lt;br /&gt;
* '''Erfolgreiche Suche''' &amp;lt;math&amp;gt;\Omega\left(\frac{1}{\alpha}\ln\left(\frac{1}{1-\alpha}\right)\right)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;5&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
! &amp;lt;math&amp;gt;\alpha&amp;lt;/math&amp;gt;&lt;br /&gt;
! 0.5&lt;br /&gt;
! 0.9&lt;br /&gt;
|- &lt;br /&gt;
| erfolglos&lt;br /&gt;
| 2.0&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| erfolgreich&lt;br /&gt;
| 1.4&lt;br /&gt;
| 2.6&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===== Wahl der Kapazität =====&lt;br /&gt;
In Python wird &amp;lt;tt&amp;gt;capacity&amp;lt;/tt&amp;gt; Aufgrund der obigen Beobachtung so gewählt, dass &amp;lt;math&amp;gt;\alpha \leq 2/3&amp;lt;/math&amp;gt;. Falls &amp;lt;math&amp;gt;\alpha&amp;lt;/math&amp;gt; größer werden sollte, verdopple die Kapazität und kopiere das alte array in das neue Array (analog zum dynamischen Array)&lt;br /&gt;
&lt;br /&gt;
In Python werden die Kapazitätsgrößen als Zweierpotenzen gewählt, also 4,8,16,32,...,&lt;br /&gt;
so dass &amp;lt;tt&amp;gt;h % self.capacity&amp;lt;/tt&amp;gt; nur die unteren Bits von &amp;lt;tt&amp;gt;h&amp;lt;/tt&amp;gt; benutzt.&lt;br /&gt;
&lt;br /&gt;
== Anwendung von Hashing ==&lt;br /&gt;
&lt;br /&gt;
* Hashtabelle, assoziatives Aray&lt;br /&gt;
* Sortieren in linearer Zeit (Übungsaufgabe 6.2)&lt;br /&gt;
* Suchen von Strings in Texten&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
=== Rabin Karp Algorithmus ===&lt;br /&gt;
In Textverarbeitungsanwendungen ist eine häufig benutzte Funktion die ''Search &amp;amp; Replace'' Funktionalität. Die Suche sollte in O(len(text)) möglich sein, aber ein naiver Algorithmus braucht O(len(text)*len(searchstring))&lt;br /&gt;
&lt;br /&gt;
==== Naive Implementierung der Suche ====&lt;br /&gt;
  def search(text, s):&lt;br /&gt;
      M, N = len(text), len(s)&lt;br /&gt;
      for k in range(M-N):&lt;br /&gt;
          if s==text[k:k+N]&lt;br /&gt;
              return k&lt;br /&gt;
      return -1 #nicht gefunden&lt;br /&gt;
&lt;br /&gt;
==== Idee des Rabin Karp Algorithmus ====&lt;br /&gt;
Statt Vergleichen &amp;lt;tt&amp;gt;s==text[k:k+N], die O(N) benötigen da N Vergleiche der Buchstaben durchgeführt werden müssen, Vergleiche die Hashs von Suchstring und dem zu untersuchenden Textabschnitt: &amp;lt;tt&amp;gt;hash(s) == hash(text[k:k+N])&amp;lt;/tt&amp;gt;. Dabei muss natürlich &amp;lt;tt&amp;gt;hash(s)&amp;lt;/tt&amp;gt; nur einmal berechnet werden, wohingegen &amp;lt;tt&amp;gt;hash(text[k:k+N])&amp;lt;/tt&amp;gt; immer wieder neu berechnet werden muss. Damit der Vergleich O(1) sein kann, ist es deswegen erforderlich, eine solche Hashfunktion zu haben, die nicht alle Zeichen (das wäre O(N) ) einlesen muss, sondern die vorhergehende Hashfunktion mit einbezieht.&lt;br /&gt;
&lt;br /&gt;
Eine solche Hashfunktion heißt ''Running Hash'' und funktioniert analog zum ''Sliding Mean''.&lt;br /&gt;
&lt;br /&gt;
Die Running Hash Funktion berechnet in O(1) den hash von &amp;lt;tt&amp;gt;text[k+1:k+1+N]&amp;lt;/tt&amp;gt; ausgehend vom hash für &amp;lt;tt&amp;gt;text[k:k+N]&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Idee: Interpretiere den Text als Ziffern in einer base d Darstellung:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h_k = \text{text}[k]\cdot d^{N-1} + \text{text}[k]\cdot d^{N-2} + \cdots + \text{text}[k+N-1]&amp;lt;/math&amp;gt;&lt;/div&gt;</summary>
		<author><name>Thorben</name></author>	</entry>

	<entry>
		<id>https://alda.iwr.uni-heidelberg.de/index.php?title=Iteration_versus_Rekursion&amp;diff=1596</id>
		<title>Iteration versus Rekursion</title>
		<link rel="alternate" type="text/html" href="https://alda.iwr.uni-heidelberg.de/index.php?title=Iteration_versus_Rekursion&amp;diff=1596"/>
				<updated>2008-06-04T16:39:23Z</updated>
		
		<summary type="html">&lt;p&gt;Thorben: /* Wahl der Kapazität */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Hashtabelle mit linearer Verkettung ==&lt;br /&gt;
Pessimistischer Ansatz: Kollisionen treten häufig auf, deshalb wird unter jedem&lt;br /&gt;
Hashindex gleich eine Liste angelegt, in der Einträge aufgenommen werden können.&lt;br /&gt;
&lt;br /&gt;
===Implementation in Python===&lt;br /&gt;
''HashNode'' ist eine Hilfsdatenstruktur, die Schlüssel und Wert speichert&lt;br /&gt;
und mit hilfe von ''next'' eine verkettete Liste darstellt&lt;br /&gt;
  class HashNode:&lt;br /&gt;
      def __init__(self,key,data,next):&lt;br /&gt;
          self.key = key&lt;br /&gt;
          self.data = data&lt;br /&gt;
          self.next = next #Verkettung!&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Die eigentliche Hashtabelle wir in der Klasse ''HashTable'' implementier:&lt;br /&gt;
  class HashTable:&lt;br /&gt;
      def __init__(self):&lt;br /&gt;
         self.capacity = ... #Geigneter Wert&lt;br /&gt;
         self.size = 0&lt;br /&gt;
         self.array = [None]*self.capacity&lt;br /&gt;
&lt;br /&gt;
In Python wird der Zugriffsoperator ''[ ]'' für eine Datenstruktur wie folgt (innerhalb einer Klasse) implementiert:&lt;br /&gt;
  def __setitem__(self, key, value)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
So dass im Programmtext dann folgender Syntax möglich ist: &amp;lt;tt&amp;gt;a[key] = value&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Genauso wir die Zuweisung &amp;lt;tt&amp;gt;value=a[key]&amp;lt;/tt&amp;gt; wie folgt umgesetzt&lt;br /&gt;
  def __getitem__(self, key, value)&lt;br /&gt;
&lt;br /&gt;
Implementierung der &amp;lt;tt&amp;gt;__setitem__&amp;lt;/tt&amp;gt; Funktionen in der &amp;lt;tt&amp;gt;HashTable&amp;lt;/tt&amp;gt; Klasse:&lt;br /&gt;
  def __setitme__(self, key, value):&lt;br /&gt;
      index = hash(key) % self.capacity&lt;br /&gt;
      node = self.array[index]&lt;br /&gt;
      while node is not None:&lt;br /&gt;
          if node.key == key:&lt;br /&gt;
              #Element key ist schon in der Tabelle&lt;br /&gt;
              #Überschreibe die Daten mit dem neuen Wert&lt;br /&gt;
              node.data = value&lt;br /&gt;
              return&lt;br /&gt;
          #Kollision des Hashwerts, probiere nächsten Key aus&lt;br /&gt;
          node = node.next&lt;br /&gt;
       #Kein Element hatte den richtigen Schlüssel.&lt;br /&gt;
       #==&amp;gt;Es gibt diesen Schlüssel noch nicht&lt;br /&gt;
       #Füge also ein neues Element in die Hashtabelle ein&lt;br /&gt;
       &lt;br /&gt;
       self.array[index] = HashNode(key, value, self.array[index])&lt;br /&gt;
       #Der alte Anfang der List wurde der Nachfolger vom neue eingefügten&lt;br /&gt;
       #ersten Element&lt;br /&gt;
       &lt;br /&gt;
       size+=1&lt;br /&gt;
&lt;br /&gt;
Und die Implementierung der &amp;lt;tt&amp;gt;__getitem__&amp;lt;/tt&amp;gt; Funktionen:&lt;br /&gt;
  def __getItem__(self, key):&lt;br /&gt;
      index = hash(key) % self.capacity&lt;br /&gt;
      node = self.array[index]&lt;br /&gt;
      while node is not None:&lt;br /&gt;
           if node.key == key #Gefunden!&lt;br /&gt;
               return Node.data&lt;br /&gt;
           node = node.next&lt;br /&gt;
      raise KeyError(key)&lt;br /&gt;
&lt;br /&gt;
==== Wahl der Kapazität ====&lt;br /&gt;
In der C++ Standardbibliothek wird typischerweise ein Hash mit Hilfe der linearen Kette&lt;br /&gt;
imlementiert. Dabei wird &amp;lt;tt&amp;gt;capcity&amp;lt;/tt&amp;gt; immer als ''Primzahl'' gewählt, wobei sich aufeinanderfolgende Kapazitäten immer ungefähr verdoppeln:&lt;br /&gt;
  53, 97, 193, 398, 769, ...&lt;br /&gt;
&lt;br /&gt;
Das hat zur Folge, dass &amp;lt;tt&amp;gt;h % self.capacity&amp;lt;/tt&amp;gt; ''alle'' Bits von h benutzt (Eigenschaft aus der Zahlentheorie)&lt;br /&gt;
&lt;br /&gt;
== Hashtabelle mit offener Adressierung (offenes Hashing) ==&lt;br /&gt;
Optimistischer Ansatz: Kollisionen werden nicht so häufig auftreten.&lt;br /&gt;
&lt;br /&gt;
=== Idee ===&lt;br /&gt;
Wenn &amp;lt;tt&amp;gt;array[index]&amp;lt;/tt&amp;gt; durch Kollision bereits vergeben ist, probiere einen&lt;br /&gt;
anderen Index aus.&lt;br /&gt;
&lt;br /&gt;
* Das Array enthält pro Element höchstens ein (key,value)-Paar&lt;br /&gt;
* Das Array muss stets mindestens ''einen'' freien Platz haben (sonst gäbe es eine   Endlosschleife). Es gilt immer &amp;lt;tt&amp;gt;self.size &amp;lt; self.capacity&amp;lt;/tt&amp;gt;. Dies galt für die vorige Hash Implementation nicht.&lt;br /&gt;
&lt;br /&gt;
=== Vorgehen bei Kollisionen ===&lt;br /&gt;
&lt;br /&gt;
==== Sequentielles Suchen ====&lt;br /&gt;
Probiere den nächsten Index: &amp;lt;tt&amp;gt;index = index+1 % capacity&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Vorteil: einfach&lt;br /&gt;
* Nachteil: Clusterbildung&lt;br /&gt;
&lt;br /&gt;
Clusterbildung heißt, dass sich größere zusammenhängende Bereiche bilden die belegt sind, unterbrochen von Bereichen die komplett frei sind. Beim Versuche des Einfügens eines Elements an einen Platz, der schon belegt ist, muss jetzt das ganze Cluster sequentiell durchlaufen werden, bis ein freier Platz gefunden wird. Damit entspricht die Komplexität der Suche der mittleren Länge der belegten Bereiche, was sich entsprechend in einer langsamen Suche widerspiegelt.&lt;br /&gt;
&lt;br /&gt;
==== Doppeltes Hashing ====&lt;br /&gt;
Bestimme einen neuen Index (bei Kollisionen) durch eine ''2. Hashfunktion''.&lt;br /&gt;
&lt;br /&gt;
Das doppelte Hashing wird typischerweise in der Praxis angewendet und liegt auch der Python Implementierung des Datentyps ''Dictionary'' (Syntax &amp;lt;tt&amp;gt;{'a':1, 'b':2, 'c':3}&amp;lt;/tt&amp;gt; zugrunde.&lt;br /&gt;
&lt;br /&gt;
Eine effiziente Implementierung dieses Datentyps ist für die Performance der Skriptsprache Python extrem wichtig, da z.B. beim Aufruf einer Funktion der auszuführunde Code in einem Dictionary unter dem Schlüssel ''Funktionsname'' nachgeschlagen wird oder die Werte lokaler Variablen innerhalb einer Funktion ebenfalls in einem Dictionary zu finden sind.&lt;br /&gt;
&lt;br /&gt;
Für die Implementierung in Python werden wieder die obigen Klassen &amp;lt;tt&amp;gt;HashNode&amp;lt;/tt&amp;gt; und &amp;lt;tt&amp;gt;HashTable&amp;lt;/tt&amp;gt; benötigt, es folgen die angepassten Implementationen von &amp;lt;tt&amp;gt;__setitem&amp;lt;/tt&amp;gt; und &amp;lt;tt&amp;gt;__getitem__&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
  def __setitem__(self, key, value):&lt;br /&gt;
      h = hash(key)&lt;br /&gt;
      index = h % self.capacity&lt;br /&gt;
      while True:&lt;br /&gt;
          if self.array[index] is None or self.array[index].key is None&lt;br /&gt;
               #das Feld ist frei (1. Abfrage)&lt;br /&gt;
               #oder das feld ist als frei markiert (2. Abfrage)&lt;br /&gt;
               self.array[index] = HashNode(key, value)&lt;br /&gt;
               self.size +=1&lt;br /&gt;
               return&lt;br /&gt;
          if self.array[index].key == key:&lt;br /&gt;
               #Es gibt diesen Schlüssel schon,&lt;br /&gt;
               #überschreibe die Daten&lt;br /&gt;
               self.array[index].data = value&lt;br /&gt;
          #Letzter Fall: Kollision&lt;br /&gt;
          index = (5*index+1+h) % self.capacity&lt;br /&gt;
          h = h &amp;gt;&amp;gt; 5&lt;br /&gt;
&lt;br /&gt;
Die vorgestellte Implementierung orientiert sich an Pythons interner Dictionary Implementierung, der zugehörige Quelltext mit ausführlichem Kommentar) findet sich unter [http://svn.python.org/view/*checkout*/python/trunk/Objects/dictobject.c dictobject.c Python Implementation (SVN)]&lt;br /&gt;
&lt;br /&gt;
===== Komplexität des offenen Hashings =====&lt;br /&gt;
&lt;br /&gt;
* Annahme: uniformes Hashing, das heißt alle Indizes haben gleiche Wahrscheinlichkeit&lt;br /&gt;
* Füllstand &amp;lt;math&amp;gt;\alpha = \frac{\text{size}}{\text{capacity}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* '''Erfolglose Suche''' (d.h. es wird entweder ein neues Element eingefügt oder ein &amp;lt;tt&amp;gt;keyError&amp;lt;/tt&amp;gt; geworfen): Untere Schranke für die Komplexität ist &amp;lt;math&amp;gt;\Omega\left(\frac{1}{1-\alpha}\right)&amp;lt;/math&amp;gt; Schritte bzw. Anzahl von neuen index Berechnungen.&lt;br /&gt;
* '''Erfolgreiche Suche''' &amp;lt;math&amp;gt;\Omega\left(\frac{1}{\alpha}\ln\left(\frac{1}{1-\alpha}\right)\right)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;5&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
! &amp;lt;math&amp;gt;\alpha&amp;lt;/math&amp;gt;&lt;br /&gt;
! 0.5&lt;br /&gt;
! 0.9&lt;br /&gt;
|- &lt;br /&gt;
| erfolglos&lt;br /&gt;
| 2.0&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| erfolgreich&lt;br /&gt;
| 1.4&lt;br /&gt;
| 2.6&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===== Wahl der Kapazität =====&lt;br /&gt;
In Python wird &amp;lt;tt&amp;gt;capacity&amp;lt;/tt&amp;gt; Aufgrund der obigen Beobachtung so gewählt, dass &amp;lt;math&amp;gt;\alpha \leq 2/3&amp;lt;/math&amp;gt;. Falls &amp;lt;math&amp;gt;\alpha&amp;lt;/math&amp;gt; größer werden sollte, verdopple die Kapazität und kopiere das alte array in das neue Array (analog zum dynamischen Array)&lt;br /&gt;
&lt;br /&gt;
In Python werden die Kapazitätsgrößen als Zweierpotenzen gewählt, also 4,8,16,32,...,&lt;br /&gt;
so dass &amp;lt;tt&amp;gt;h % self.capacity&amp;lt;/tt&amp;gt; nur die unteren Bits von &amp;lt;tt&amp;gt;h&amp;lt;/tt&amp;gt; benutzt.&lt;/div&gt;</summary>
		<author><name>Thorben</name></author>	</entry>

	<entry>
		<id>https://alda.iwr.uni-heidelberg.de/index.php?title=Iteration_versus_Rekursion&amp;diff=1595</id>
		<title>Iteration versus Rekursion</title>
		<link rel="alternate" type="text/html" href="https://alda.iwr.uni-heidelberg.de/index.php?title=Iteration_versus_Rekursion&amp;diff=1595"/>
				<updated>2008-06-04T16:38:54Z</updated>
		
		<summary type="html">&lt;p&gt;Thorben: /* Wahl der Kapazität */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Hashtabelle mit linearer Verkettung ==&lt;br /&gt;
Pessimistischer Ansatz: Kollisionen treten häufig auf, deshalb wird unter jedem&lt;br /&gt;
Hashindex gleich eine Liste angelegt, in der Einträge aufgenommen werden können.&lt;br /&gt;
&lt;br /&gt;
===Implementation in Python===&lt;br /&gt;
''HashNode'' ist eine Hilfsdatenstruktur, die Schlüssel und Wert speichert&lt;br /&gt;
und mit hilfe von ''next'' eine verkettete Liste darstellt&lt;br /&gt;
  class HashNode:&lt;br /&gt;
      def __init__(self,key,data,next):&lt;br /&gt;
          self.key = key&lt;br /&gt;
          self.data = data&lt;br /&gt;
          self.next = next #Verkettung!&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Die eigentliche Hashtabelle wir in der Klasse ''HashTable'' implementier:&lt;br /&gt;
  class HashTable:&lt;br /&gt;
      def __init__(self):&lt;br /&gt;
         self.capacity = ... #Geigneter Wert&lt;br /&gt;
         self.size = 0&lt;br /&gt;
         self.array = [None]*self.capacity&lt;br /&gt;
&lt;br /&gt;
In Python wird der Zugriffsoperator ''[ ]'' für eine Datenstruktur wie folgt (innerhalb einer Klasse) implementiert:&lt;br /&gt;
  def __setitem__(self, key, value)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
So dass im Programmtext dann folgender Syntax möglich ist: &amp;lt;tt&amp;gt;a[key] = value&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Genauso wir die Zuweisung &amp;lt;tt&amp;gt;value=a[key]&amp;lt;/tt&amp;gt; wie folgt umgesetzt&lt;br /&gt;
  def __getitem__(self, key, value)&lt;br /&gt;
&lt;br /&gt;
Implementierung der &amp;lt;tt&amp;gt;__setitem__&amp;lt;/tt&amp;gt; Funktionen in der &amp;lt;tt&amp;gt;HashTable&amp;lt;/tt&amp;gt; Klasse:&lt;br /&gt;
  def __setitme__(self, key, value):&lt;br /&gt;
      index = hash(key) % self.capacity&lt;br /&gt;
      node = self.array[index]&lt;br /&gt;
      while node is not None:&lt;br /&gt;
          if node.key == key:&lt;br /&gt;
              #Element key ist schon in der Tabelle&lt;br /&gt;
              #Überschreibe die Daten mit dem neuen Wert&lt;br /&gt;
              node.data = value&lt;br /&gt;
              return&lt;br /&gt;
          #Kollision des Hashwerts, probiere nächsten Key aus&lt;br /&gt;
          node = node.next&lt;br /&gt;
       #Kein Element hatte den richtigen Schlüssel.&lt;br /&gt;
       #==&amp;gt;Es gibt diesen Schlüssel noch nicht&lt;br /&gt;
       #Füge also ein neues Element in die Hashtabelle ein&lt;br /&gt;
       &lt;br /&gt;
       self.array[index] = HashNode(key, value, self.array[index])&lt;br /&gt;
       #Der alte Anfang der List wurde der Nachfolger vom neue eingefügten&lt;br /&gt;
       #ersten Element&lt;br /&gt;
       &lt;br /&gt;
       size+=1&lt;br /&gt;
&lt;br /&gt;
Und die Implementierung der &amp;lt;tt&amp;gt;__getitem__&amp;lt;/tt&amp;gt; Funktionen:&lt;br /&gt;
  def __getItem__(self, key):&lt;br /&gt;
      index = hash(key) % self.capacity&lt;br /&gt;
      node = self.array[index]&lt;br /&gt;
      while node is not None:&lt;br /&gt;
           if node.key == key #Gefunden!&lt;br /&gt;
               return Node.data&lt;br /&gt;
           node = node.next&lt;br /&gt;
      raise KeyError(key)&lt;br /&gt;
&lt;br /&gt;
==== Wahl der Kapazität ====&lt;br /&gt;
In der C++ Standardbibliothek wird typischerweise ein Hash mit Hilfe der linearen Kette&lt;br /&gt;
imlementiert. Dabei wird &amp;lt;tt&amp;gt;capcity&amp;lt;/tt&amp;gt; immer als ''Primzahl'' gewählt, wobei sich aufeinanderfolgende Kapazitäten immer ungefähr verdoppeln:&lt;br /&gt;
  53, 97, 193, 398, 769, ...&lt;br /&gt;
&lt;br /&gt;
Das hat zur Folge, dass &amp;lt;tt&amp;gt;h % self.capacity&amp;lt;/tt&amp;gt; ''alle'' Bits von h benutzt (Eigenschaft aus der Zahlentheorie)&lt;br /&gt;
&lt;br /&gt;
== Hashtabelle mit offener Adressierung (offenes Hashing) ==&lt;br /&gt;
Optimistischer Ansatz: Kollisionen werden nicht so häufig auftreten.&lt;br /&gt;
&lt;br /&gt;
=== Idee ===&lt;br /&gt;
Wenn &amp;lt;tt&amp;gt;array[index]&amp;lt;/tt&amp;gt; durch Kollision bereits vergeben ist, probiere einen&lt;br /&gt;
anderen Index aus.&lt;br /&gt;
&lt;br /&gt;
* Das Array enthält pro Element höchstens ein (key,value)-Paar&lt;br /&gt;
* Das Array muss stets mindestens ''einen'' freien Platz haben (sonst gäbe es eine   Endlosschleife). Es gilt immer &amp;lt;tt&amp;gt;self.size &amp;lt; self.capacity&amp;lt;/tt&amp;gt;. Dies galt für die vorige Hash Implementation nicht.&lt;br /&gt;
&lt;br /&gt;
=== Vorgehen bei Kollisionen ===&lt;br /&gt;
&lt;br /&gt;
==== Sequentielles Suchen ====&lt;br /&gt;
Probiere den nächsten Index: &amp;lt;tt&amp;gt;index = index+1 % capacity&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Vorteil: einfach&lt;br /&gt;
* Nachteil: Clusterbildung&lt;br /&gt;
&lt;br /&gt;
Clusterbildung heißt, dass sich größere zusammenhängende Bereiche bilden die belegt sind, unterbrochen von Bereichen die komplett frei sind. Beim Versuche des Einfügens eines Elements an einen Platz, der schon belegt ist, muss jetzt das ganze Cluster sequentiell durchlaufen werden, bis ein freier Platz gefunden wird. Damit entspricht die Komplexität der Suche der mittleren Länge der belegten Bereiche, was sich entsprechend in einer langsamen Suche widerspiegelt.&lt;br /&gt;
&lt;br /&gt;
==== Doppeltes Hashing ====&lt;br /&gt;
Bestimme einen neuen Index (bei Kollisionen) durch eine ''2. Hashfunktion''.&lt;br /&gt;
&lt;br /&gt;
Das doppelte Hashing wird typischerweise in der Praxis angewendet und liegt auch der Python Implementierung des Datentyps ''Dictionary'' (Syntax &amp;lt;tt&amp;gt;{'a':1, 'b':2, 'c':3}&amp;lt;/tt&amp;gt; zugrunde.&lt;br /&gt;
&lt;br /&gt;
Eine effiziente Implementierung dieses Datentyps ist für die Performance der Skriptsprache Python extrem wichtig, da z.B. beim Aufruf einer Funktion der auszuführunde Code in einem Dictionary unter dem Schlüssel ''Funktionsname'' nachgeschlagen wird oder die Werte lokaler Variablen innerhalb einer Funktion ebenfalls in einem Dictionary zu finden sind.&lt;br /&gt;
&lt;br /&gt;
Für die Implementierung in Python werden wieder die obigen Klassen &amp;lt;tt&amp;gt;HashNode&amp;lt;/tt&amp;gt; und &amp;lt;tt&amp;gt;HashTable&amp;lt;/tt&amp;gt; benötigt, es folgen die angepassten Implementationen von &amp;lt;tt&amp;gt;__setitem&amp;lt;/tt&amp;gt; und &amp;lt;tt&amp;gt;__getitem__&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
  def __setitem__(self, key, value):&lt;br /&gt;
      h = hash(key)&lt;br /&gt;
      index = h % self.capacity&lt;br /&gt;
      while True:&lt;br /&gt;
          if self.array[index] is None or self.array[index].key is None&lt;br /&gt;
               #das Feld ist frei (1. Abfrage)&lt;br /&gt;
               #oder das feld ist als frei markiert (2. Abfrage)&lt;br /&gt;
               self.array[index] = HashNode(key, value)&lt;br /&gt;
               self.size +=1&lt;br /&gt;
               return&lt;br /&gt;
          if self.array[index].key == key:&lt;br /&gt;
               #Es gibt diesen Schlüssel schon,&lt;br /&gt;
               #überschreibe die Daten&lt;br /&gt;
               self.array[index].data = value&lt;br /&gt;
          #Letzter Fall: Kollision&lt;br /&gt;
          index = (5*index+1+h) % self.capacity&lt;br /&gt;
          h = h &amp;gt;&amp;gt; 5&lt;br /&gt;
&lt;br /&gt;
Die vorgestellte Implementierung orientiert sich an Pythons interner Dictionary Implementierung, der zugehörige Quelltext mit ausführlichem Kommentar) findet sich unter [http://svn.python.org/view/*checkout*/python/trunk/Objects/dictobject.c dictobject.c Python Implementation (SVN)]&lt;br /&gt;
&lt;br /&gt;
===== Komplexität des offenen Hashings =====&lt;br /&gt;
&lt;br /&gt;
* Annahme: uniformes Hashing, das heißt alle Indizes haben gleiche Wahrscheinlichkeit&lt;br /&gt;
* Füllstand &amp;lt;math&amp;gt;\alpha = \frac{\text{size}}{\text{capacity}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* '''Erfolglose Suche''' (d.h. es wird entweder ein neues Element eingefügt oder ein &amp;lt;tt&amp;gt;keyError&amp;lt;/tt&amp;gt; geworfen): Untere Schranke für die Komplexität ist &amp;lt;math&amp;gt;\Omega\left(\frac{1}{1-\alpha}\right)&amp;lt;/math&amp;gt; Schritte bzw. Anzahl von neuen index Berechnungen.&lt;br /&gt;
* '''Erfolgreiche Suche''' &amp;lt;math&amp;gt;\Omega\left(\frac{1}{\alpha}\ln\left(\frac{1}{1-\alpha}\right)\right)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;5&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
! &amp;lt;math&amp;gt;\alpha&amp;lt;/math&amp;gt;&lt;br /&gt;
! 0.5&lt;br /&gt;
! 0.9&lt;br /&gt;
|- &lt;br /&gt;
| erfolglos&lt;br /&gt;
| 2.0&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| erfolgreich&lt;br /&gt;
| 1.4&lt;br /&gt;
| 2.6&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===== Wahl der Kapazität =====&lt;br /&gt;
In Python wird &amp;lt;tt&amp;gt;capacity&amp;lt;/tt&amp;gt; Aufgrund der obigen Beobachtung so gewählt, dass &amp;lt;math&amp;gt;\alpha \lq 2/3&amp;lt;/math&amp;gt;. Falls &amp;lt;math&amp;gt;\alpha&amp;lt;/math&amp;gt; größer werden sollte, verdopple die Kapazität und kopiere das alte array in das neue Array (analog zum dynamischen Array)&lt;br /&gt;
&lt;br /&gt;
In Python werden die Kapazitätsgrößen als Zweierpotenzen gewählt, also 4,8,16,32,...,&lt;br /&gt;
so dass &amp;lt;tt&amp;gt;h % self.capacity&amp;lt;/tt&amp;gt; nur die unteren Bits von &amp;lt;tt&amp;gt;h&amp;lt;/tt&amp;gt; benutzt.&lt;/div&gt;</summary>
		<author><name>Thorben</name></author>	</entry>

	<entry>
		<id>https://alda.iwr.uni-heidelberg.de/index.php?title=Iteration_versus_Rekursion&amp;diff=1594</id>
		<title>Iteration versus Rekursion</title>
		<link rel="alternate" type="text/html" href="https://alda.iwr.uni-heidelberg.de/index.php?title=Iteration_versus_Rekursion&amp;diff=1594"/>
				<updated>2008-06-04T16:38:11Z</updated>
		
		<summary type="html">&lt;p&gt;Thorben: /* Hashtabelle mit linearer Verkettung */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Hashtabelle mit linearer Verkettung ==&lt;br /&gt;
Pessimistischer Ansatz: Kollisionen treten häufig auf, deshalb wird unter jedem&lt;br /&gt;
Hashindex gleich eine Liste angelegt, in der Einträge aufgenommen werden können.&lt;br /&gt;
&lt;br /&gt;
===Implementation in Python===&lt;br /&gt;
''HashNode'' ist eine Hilfsdatenstruktur, die Schlüssel und Wert speichert&lt;br /&gt;
und mit hilfe von ''next'' eine verkettete Liste darstellt&lt;br /&gt;
  class HashNode:&lt;br /&gt;
      def __init__(self,key,data,next):&lt;br /&gt;
          self.key = key&lt;br /&gt;
          self.data = data&lt;br /&gt;
          self.next = next #Verkettung!&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Die eigentliche Hashtabelle wir in der Klasse ''HashTable'' implementier:&lt;br /&gt;
  class HashTable:&lt;br /&gt;
      def __init__(self):&lt;br /&gt;
         self.capacity = ... #Geigneter Wert&lt;br /&gt;
         self.size = 0&lt;br /&gt;
         self.array = [None]*self.capacity&lt;br /&gt;
&lt;br /&gt;
In Python wird der Zugriffsoperator ''[ ]'' für eine Datenstruktur wie folgt (innerhalb einer Klasse) implementiert:&lt;br /&gt;
  def __setitem__(self, key, value)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
So dass im Programmtext dann folgender Syntax möglich ist: &amp;lt;tt&amp;gt;a[key] = value&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Genauso wir die Zuweisung &amp;lt;tt&amp;gt;value=a[key]&amp;lt;/tt&amp;gt; wie folgt umgesetzt&lt;br /&gt;
  def __getitem__(self, key, value)&lt;br /&gt;
&lt;br /&gt;
Implementierung der &amp;lt;tt&amp;gt;__setitem__&amp;lt;/tt&amp;gt; Funktionen in der &amp;lt;tt&amp;gt;HashTable&amp;lt;/tt&amp;gt; Klasse:&lt;br /&gt;
  def __setitme__(self, key, value):&lt;br /&gt;
      index = hash(key) % self.capacity&lt;br /&gt;
      node = self.array[index]&lt;br /&gt;
      while node is not None:&lt;br /&gt;
          if node.key == key:&lt;br /&gt;
              #Element key ist schon in der Tabelle&lt;br /&gt;
              #Überschreibe die Daten mit dem neuen Wert&lt;br /&gt;
              node.data = value&lt;br /&gt;
              return&lt;br /&gt;
          #Kollision des Hashwerts, probiere nächsten Key aus&lt;br /&gt;
          node = node.next&lt;br /&gt;
       #Kein Element hatte den richtigen Schlüssel.&lt;br /&gt;
       #==&amp;gt;Es gibt diesen Schlüssel noch nicht&lt;br /&gt;
       #Füge also ein neues Element in die Hashtabelle ein&lt;br /&gt;
       &lt;br /&gt;
       self.array[index] = HashNode(key, value, self.array[index])&lt;br /&gt;
       #Der alte Anfang der List wurde der Nachfolger vom neue eingefügten&lt;br /&gt;
       #ersten Element&lt;br /&gt;
       &lt;br /&gt;
       size+=1&lt;br /&gt;
&lt;br /&gt;
Und die Implementierung der &amp;lt;tt&amp;gt;__getitem__&amp;lt;/tt&amp;gt; Funktionen:&lt;br /&gt;
  def __getItem__(self, key):&lt;br /&gt;
      index = hash(key) % self.capacity&lt;br /&gt;
      node = self.array[index]&lt;br /&gt;
      while node is not None:&lt;br /&gt;
           if node.key == key #Gefunden!&lt;br /&gt;
               return Node.data&lt;br /&gt;
           node = node.next&lt;br /&gt;
      raise KeyError(key)&lt;br /&gt;
&lt;br /&gt;
==== Wahl der Kapazität ====&lt;br /&gt;
In der C++ Standardbibliothek wird typischerweise ein Hash mit Hilfe der linearen Kette&lt;br /&gt;
imlementiert. Dabei wird &amp;lt;tt&amp;gt;capcity&amp;lt;/tt&amp;gt; immer als ''Primzahl'' gewählt, wobei sich aufeinanderfolgende Kapazitäten immer ungefähr verdoppeln:&lt;br /&gt;
  53, 97, 193, 398, 769, ...&lt;br /&gt;
&lt;br /&gt;
Das hat zur Folge, dass &amp;lt;tt&amp;gt;h % self.capacity&amp;lt;/tt&amp;gt; ''alle'' Bits von h benutzt (Eigenschaft aus der Zahlentheorie)&lt;br /&gt;
&lt;br /&gt;
== Hashtabelle mit offener Adressierung (offenes Hashing) ==&lt;br /&gt;
Optimistischer Ansatz: Kollisionen werden nicht so häufig auftreten.&lt;br /&gt;
&lt;br /&gt;
=== Idee ===&lt;br /&gt;
Wenn &amp;lt;tt&amp;gt;array[index]&amp;lt;/tt&amp;gt; durch Kollision bereits vergeben ist, probiere einen&lt;br /&gt;
anderen Index aus.&lt;br /&gt;
&lt;br /&gt;
* Das Array enthält pro Element höchstens ein (key,value)-Paar&lt;br /&gt;
* Das Array muss stets mindestens ''einen'' freien Platz haben (sonst gäbe es eine   Endlosschleife). Es gilt immer &amp;lt;tt&amp;gt;self.size &amp;lt; self.capacity&amp;lt;/tt&amp;gt;. Dies galt für die vorige Hash Implementation nicht.&lt;br /&gt;
&lt;br /&gt;
=== Vorgehen bei Kollisionen ===&lt;br /&gt;
&lt;br /&gt;
==== Sequentielles Suchen ====&lt;br /&gt;
Probiere den nächsten Index: &amp;lt;tt&amp;gt;index = index+1 % capacity&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Vorteil: einfach&lt;br /&gt;
* Nachteil: Clusterbildung&lt;br /&gt;
&lt;br /&gt;
Clusterbildung heißt, dass sich größere zusammenhängende Bereiche bilden die belegt sind, unterbrochen von Bereichen die komplett frei sind. Beim Versuche des Einfügens eines Elements an einen Platz, der schon belegt ist, muss jetzt das ganze Cluster sequentiell durchlaufen werden, bis ein freier Platz gefunden wird. Damit entspricht die Komplexität der Suche der mittleren Länge der belegten Bereiche, was sich entsprechend in einer langsamen Suche widerspiegelt.&lt;br /&gt;
&lt;br /&gt;
==== Doppeltes Hashing ====&lt;br /&gt;
Bestimme einen neuen Index (bei Kollisionen) durch eine ''2. Hashfunktion''.&lt;br /&gt;
&lt;br /&gt;
Das doppelte Hashing wird typischerweise in der Praxis angewendet und liegt auch der Python Implementierung des Datentyps ''Dictionary'' (Syntax &amp;lt;tt&amp;gt;{'a':1, 'b':2, 'c':3}&amp;lt;/tt&amp;gt; zugrunde.&lt;br /&gt;
&lt;br /&gt;
Eine effiziente Implementierung dieses Datentyps ist für die Performance der Skriptsprache Python extrem wichtig, da z.B. beim Aufruf einer Funktion der auszuführunde Code in einem Dictionary unter dem Schlüssel ''Funktionsname'' nachgeschlagen wird oder die Werte lokaler Variablen innerhalb einer Funktion ebenfalls in einem Dictionary zu finden sind.&lt;br /&gt;
&lt;br /&gt;
Für die Implementierung in Python werden wieder die obigen Klassen &amp;lt;tt&amp;gt;HashNode&amp;lt;/tt&amp;gt; und &amp;lt;tt&amp;gt;HashTable&amp;lt;/tt&amp;gt; benötigt, es folgen die angepassten Implementationen von &amp;lt;tt&amp;gt;__setitem&amp;lt;/tt&amp;gt; und &amp;lt;tt&amp;gt;__getitem__&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
  def __setitem__(self, key, value):&lt;br /&gt;
      h = hash(key)&lt;br /&gt;
      index = h % self.capacity&lt;br /&gt;
      while True:&lt;br /&gt;
          if self.array[index] is None or self.array[index].key is None&lt;br /&gt;
               #das Feld ist frei (1. Abfrage)&lt;br /&gt;
               #oder das feld ist als frei markiert (2. Abfrage)&lt;br /&gt;
               self.array[index] = HashNode(key, value)&lt;br /&gt;
               self.size +=1&lt;br /&gt;
               return&lt;br /&gt;
          if self.array[index].key == key:&lt;br /&gt;
               #Es gibt diesen Schlüssel schon,&lt;br /&gt;
               #überschreibe die Daten&lt;br /&gt;
               self.array[index].data = value&lt;br /&gt;
          #Letzter Fall: Kollision&lt;br /&gt;
          index = (5*index+1+h) % self.capacity&lt;br /&gt;
          h = h &amp;gt;&amp;gt; 5&lt;br /&gt;
&lt;br /&gt;
Die vorgestellte Implementierung orientiert sich an Pythons interner Dictionary Implementierung, der zugehörige Quelltext mit ausführlichem Kommentar) findet sich unter [http://svn.python.org/view/*checkout*/python/trunk/Objects/dictobject.c dictobject.c Python Implementation (SVN)]&lt;br /&gt;
&lt;br /&gt;
===== Komplexität des offenen Hashings =====&lt;br /&gt;
&lt;br /&gt;
* Annahme: uniformes Hashing, das heißt alle Indizes haben gleiche Wahrscheinlichkeit&lt;br /&gt;
* Füllstand &amp;lt;math&amp;gt;\alpha = \frac{\text{size}}{\text{capacity}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* '''Erfolglose Suche''' (d.h. es wird entweder ein neues Element eingefügt oder ein &amp;lt;tt&amp;gt;keyError&amp;lt;/tt&amp;gt; geworfen): Untere Schranke für die Komplexität ist &amp;lt;math&amp;gt;\Omega\left(\frac{1}{1-\alpha}\right)&amp;lt;/math&amp;gt; Schritte bzw. Anzahl von neuen index Berechnungen.&lt;br /&gt;
* '''Erfolgreiche Suche''' &amp;lt;math&amp;gt;\Omega\left(\frac{1}{\alpha}\ln\left(\frac{1}{1-\alpha}\right)\right)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;5&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
! &amp;lt;math&amp;gt;\alpha&amp;lt;/math&amp;gt;&lt;br /&gt;
! 0.5&lt;br /&gt;
! 0.9&lt;br /&gt;
|- &lt;br /&gt;
| erfolglos&lt;br /&gt;
| 2.0&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| erfolgreich&lt;br /&gt;
| 1.4&lt;br /&gt;
| 2.6&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===== Wahl der Kapazität =====&lt;br /&gt;
In Python wird &amp;lt;tt&amp;gt;capacity&amp;lt;/tt&amp;gt; Aufgrund der obigen Beobachtung so gewählt, dass &amp;lt;math&amp;gt;\alpha \lt 2/3&amp;lt;/math&amp;gt;. Falls &amp;lt;math&amp;gt;\alpha&amp;lt;/math&amp;gt; größer werden sollte, verdopple die Kapazität und kopiere das alte array in das neue Array (analog zum dynamischen Array)&lt;br /&gt;
&lt;br /&gt;
In Python werden die Kapazitätsgrößen als Zweierpotenzen gewählt, also 4,8,16,32,...,&lt;br /&gt;
so dass &amp;lt;tt&amp;gt;h % self.capacity&amp;lt;/tt&amp;gt; nur die unteren Bits von &amp;lt;tt&amp;gt;h&amp;lt;/tt&amp;gt; benutzt.&lt;/div&gt;</summary>
		<author><name>Thorben</name></author>	</entry>

	<entry>
		<id>https://alda.iwr.uni-heidelberg.de/index.php?title=Iteration_versus_Rekursion&amp;diff=1593</id>
		<title>Iteration versus Rekursion</title>
		<link rel="alternate" type="text/html" href="https://alda.iwr.uni-heidelberg.de/index.php?title=Iteration_versus_Rekursion&amp;diff=1593"/>
				<updated>2008-06-04T16:34:51Z</updated>
		
		<summary type="html">&lt;p&gt;Thorben: /* Doppeltes Hashing */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Hashtabelle mit linearer Verkettung ==&lt;br /&gt;
Pessimistischer Ansatz: Kollisionen treten häufig auf, deshalb wird unter jedem&lt;br /&gt;
Hashindex gleich eine Liste angelegt, in der Einträge aufgenommen werden können.&lt;br /&gt;
&lt;br /&gt;
===Implementation in Python===&lt;br /&gt;
''HashNode'' ist eine Hilfsdatenstruktur, die Schlüssel und Wert speichert&lt;br /&gt;
und mit hilfe von ''next'' eine verkettete Liste darstellt&lt;br /&gt;
  class HashNode:&lt;br /&gt;
      def __init__(self,key,data,next):&lt;br /&gt;
          self.key = key&lt;br /&gt;
          self.data = data&lt;br /&gt;
          self.next = next #Verkettung!&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Die eigentliche Hashtabelle wir in der Klasse ''HashTable'' implementier:&lt;br /&gt;
  class HashTable:&lt;br /&gt;
      def __init__(self):&lt;br /&gt;
         self.capacity = ... #Geigneter Wert&lt;br /&gt;
         self.size = 0&lt;br /&gt;
         self.array = [None]*self.capacity&lt;br /&gt;
&lt;br /&gt;
In Python wird der Zugriffsoperator ''[ ]'' für eine Datenstruktur wie folgt (innerhalb einer Klasse) implementiert:&lt;br /&gt;
  def __setitem__(self, key, value)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
So dass im Programmtext dann folgender Syntax möglich ist: &amp;lt;tt&amp;gt;a[key] = value&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Genauso wir die Zuweisung &amp;lt;tt&amp;gt;value=a[key]&amp;lt;/tt&amp;gt; wie folgt umgesetzt&lt;br /&gt;
  def __getitem__(self, key, value)&lt;br /&gt;
&lt;br /&gt;
Implementierung der &amp;lt;tt&amp;gt;__setitem__&amp;lt;/tt&amp;gt; Funktionen in der &amp;lt;tt&amp;gt;HashTable&amp;lt;/tt&amp;gt; Klasse:&lt;br /&gt;
  def __setitme__(self, key, value):&lt;br /&gt;
      index = hash(key) % self.capacity&lt;br /&gt;
      node = self.array[index]&lt;br /&gt;
      while node is not None:&lt;br /&gt;
          if node.key == key:&lt;br /&gt;
              #Element key ist schon in der Tabelle&lt;br /&gt;
              #Überschreibe die Daten mit dem neuen Wert&lt;br /&gt;
              node.data = value&lt;br /&gt;
              return&lt;br /&gt;
          #Kollision des Hashwerts, probiere nächsten Key aus&lt;br /&gt;
          node = node.next&lt;br /&gt;
       #Kein Element hatte den richtigen Schlüssel.&lt;br /&gt;
       #==&amp;gt;Es gibt diesen Schlüssel noch nicht&lt;br /&gt;
       #Füge also ein neues Element in die Hashtabelle ein&lt;br /&gt;
       &lt;br /&gt;
       self.array[index] = HashNode(key, value, self.array[index])&lt;br /&gt;
       #Der alte Anfang der List wurde der Nachfolger vom neue eingefügten&lt;br /&gt;
       #ersten Element&lt;br /&gt;
       &lt;br /&gt;
       size+=1&lt;br /&gt;
&lt;br /&gt;
Und die Implementierung der &amp;lt;tt&amp;gt;__getitem__&amp;lt;/tt&amp;gt; Funktionen:&lt;br /&gt;
  def __getItem__(self, key):&lt;br /&gt;
      index = hash(key) % self.capacity&lt;br /&gt;
      node = self.array[index]&lt;br /&gt;
      while node is not None:&lt;br /&gt;
           if node.key == key #Gefunden!&lt;br /&gt;
               return Node.data&lt;br /&gt;
           node = node.next&lt;br /&gt;
      raise KeyError(key)&lt;br /&gt;
&lt;br /&gt;
== Hashtabelle mit offener Adressierung (offenes Hashing) ==&lt;br /&gt;
Optimistischer Ansatz: Kollisionen werden nicht so häufig auftreten.&lt;br /&gt;
&lt;br /&gt;
=== Idee ===&lt;br /&gt;
Wenn &amp;lt;tt&amp;gt;array[index]&amp;lt;/tt&amp;gt; durch Kollision bereits vergeben ist, probiere einen&lt;br /&gt;
anderen Index aus.&lt;br /&gt;
&lt;br /&gt;
* Das Array enthält pro Element höchstens ein (key,value)-Paar&lt;br /&gt;
* Das Array muss stets mindestens ''einen'' freien Platz haben (sonst gäbe es eine   Endlosschleife). Es gilt immer &amp;lt;tt&amp;gt;self.size &amp;lt; self.capacity&amp;lt;/tt&amp;gt;. Dies galt für die vorige Hash Implementation nicht.&lt;br /&gt;
&lt;br /&gt;
=== Vorgehen bei Kollisionen ===&lt;br /&gt;
&lt;br /&gt;
==== Sequentielles Suchen ====&lt;br /&gt;
Probiere den nächsten Index: &amp;lt;tt&amp;gt;index = index+1 % capacity&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Vorteil: einfach&lt;br /&gt;
* Nachteil: Clusterbildung&lt;br /&gt;
&lt;br /&gt;
Clusterbildung heißt, dass sich größere zusammenhängende Bereiche bilden die belegt sind, unterbrochen von Bereichen die komplett frei sind. Beim Versuche des Einfügens eines Elements an einen Platz, der schon belegt ist, muss jetzt das ganze Cluster sequentiell durchlaufen werden, bis ein freier Platz gefunden wird. Damit entspricht die Komplexität der Suche der mittleren Länge der belegten Bereiche, was sich entsprechend in einer langsamen Suche widerspiegelt.&lt;br /&gt;
&lt;br /&gt;
==== Doppeltes Hashing ====&lt;br /&gt;
Bestimme einen neuen Index (bei Kollisionen) durch eine ''2. Hashfunktion''.&lt;br /&gt;
&lt;br /&gt;
Das doppelte Hashing wird typischerweise in der Praxis angewendet und liegt auch der Python Implementierung des Datentyps ''Dictionary'' (Syntax &amp;lt;tt&amp;gt;{'a':1, 'b':2, 'c':3}&amp;lt;/tt&amp;gt; zugrunde.&lt;br /&gt;
&lt;br /&gt;
Eine effiziente Implementierung dieses Datentyps ist für die Performance der Skriptsprache Python extrem wichtig, da z.B. beim Aufruf einer Funktion der auszuführunde Code in einem Dictionary unter dem Schlüssel ''Funktionsname'' nachgeschlagen wird oder die Werte lokaler Variablen innerhalb einer Funktion ebenfalls in einem Dictionary zu finden sind.&lt;br /&gt;
&lt;br /&gt;
Für die Implementierung in Python werden wieder die obigen Klassen &amp;lt;tt&amp;gt;HashNode&amp;lt;/tt&amp;gt; und &amp;lt;tt&amp;gt;HashTable&amp;lt;/tt&amp;gt; benötigt, es folgen die angepassten Implementationen von &amp;lt;tt&amp;gt;__setitem&amp;lt;/tt&amp;gt; und &amp;lt;tt&amp;gt;__getitem__&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
  def __setitem__(self, key, value):&lt;br /&gt;
      h = hash(key)&lt;br /&gt;
      index = h % self.capacity&lt;br /&gt;
      while True:&lt;br /&gt;
          if self.array[index] is None or self.array[index].key is None&lt;br /&gt;
               #das Feld ist frei (1. Abfrage)&lt;br /&gt;
               #oder das feld ist als frei markiert (2. Abfrage)&lt;br /&gt;
               self.array[index] = HashNode(key, value)&lt;br /&gt;
               self.size +=1&lt;br /&gt;
               return&lt;br /&gt;
          if self.array[index].key == key:&lt;br /&gt;
               #Es gibt diesen Schlüssel schon,&lt;br /&gt;
               #überschreibe die Daten&lt;br /&gt;
               self.array[index].data = value&lt;br /&gt;
          #Letzter Fall: Kollision&lt;br /&gt;
          index = (5*index+1+h) % self.capacity&lt;br /&gt;
          h = h &amp;gt;&amp;gt; 5&lt;br /&gt;
&lt;br /&gt;
Die vorgestellte Implementierung orientiert sich an Pythons interner Dictionary Implementierung, der zugehörige Quelltext mit ausführlichem Kommentar) findet sich unter [http://svn.python.org/view/*checkout*/python/trunk/Objects/dictobject.c dictobject.c Python Implementation (SVN)]&lt;br /&gt;
&lt;br /&gt;
===== Komplexität des offenen Hashings =====&lt;br /&gt;
&lt;br /&gt;
* Annahme: uniformes Hashing, das heißt alle Indizes haben gleiche Wahrscheinlichkeit&lt;br /&gt;
* Füllstand &amp;lt;math&amp;gt;\alpha = \frac{\text{size}}{\text{capacity}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* '''Erfolglose Suche''' (d.h. es wird entweder ein neues Element eingefügt oder ein &amp;lt;tt&amp;gt;keyError&amp;lt;/tt&amp;gt; geworfen): Untere Schranke für die Komplexität ist &amp;lt;math&amp;gt;\Omega\left(\frac{1}{1-\alpha}\right)&amp;lt;/math&amp;gt; Schritte bzw. Anzahl von neuen index Berechnungen.&lt;br /&gt;
* '''Erfolgreiche Suche''' &amp;lt;math&amp;gt;\Omega\left(\frac{1}{\alpha}\ln\left(\frac{1}{1-\alpha}\right)\right)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;5&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
! &amp;lt;math&amp;gt;\alpha&amp;lt;/math&amp;gt;&lt;br /&gt;
! 0.5&lt;br /&gt;
! 0.9&lt;br /&gt;
|- &lt;br /&gt;
| erfolglos&lt;br /&gt;
| 2.0&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| erfolgreich&lt;br /&gt;
| 1.4&lt;br /&gt;
| 2.6&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===== Wahl der Kapazität =====&lt;br /&gt;
In Python wird &amp;lt;tt&amp;gt;capacity&amp;lt;/tt&amp;gt; Aufgrund der obigen Beobachtung so gewählt, dass &amp;lt;math&amp;gt;\alpha \lt 2/3&amp;lt;/math&amp;gt;. Falls &amp;lt;math&amp;gt;\alpha&amp;lt;/math&amp;gt; größer werden sollte, verdopple die Kapazität und kopiere das alte array in das neue Array (analog zum dynamischen Array)&lt;br /&gt;
&lt;br /&gt;
In Python werden die Kapazitätsgrößen als Zweierpotenzen gewählt, also 4,8,16,32,...,&lt;br /&gt;
so dass &amp;lt;tt&amp;gt;h % self.capacity&amp;lt;/tt&amp;gt; nur die unteren Bits von &amp;lt;tt&amp;gt;h&amp;lt;/tt&amp;gt; benutzt.&lt;/div&gt;</summary>
		<author><name>Thorben</name></author>	</entry>

	<entry>
		<id>https://alda.iwr.uni-heidelberg.de/index.php?title=Iteration_versus_Rekursion&amp;diff=1592</id>
		<title>Iteration versus Rekursion</title>
		<link rel="alternate" type="text/html" href="https://alda.iwr.uni-heidelberg.de/index.php?title=Iteration_versus_Rekursion&amp;diff=1592"/>
				<updated>2008-06-04T16:31:01Z</updated>
		
		<summary type="html">&lt;p&gt;Thorben: /* Komplexität des offenen Hashings */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Hashtabelle mit linearer Verkettung ==&lt;br /&gt;
Pessimistischer Ansatz: Kollisionen treten häufig auf, deshalb wird unter jedem&lt;br /&gt;
Hashindex gleich eine Liste angelegt, in der Einträge aufgenommen werden können.&lt;br /&gt;
&lt;br /&gt;
===Implementation in Python===&lt;br /&gt;
''HashNode'' ist eine Hilfsdatenstruktur, die Schlüssel und Wert speichert&lt;br /&gt;
und mit hilfe von ''next'' eine verkettete Liste darstellt&lt;br /&gt;
  class HashNode:&lt;br /&gt;
      def __init__(self,key,data,next):&lt;br /&gt;
          self.key = key&lt;br /&gt;
          self.data = data&lt;br /&gt;
          self.next = next #Verkettung!&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Die eigentliche Hashtabelle wir in der Klasse ''HashTable'' implementier:&lt;br /&gt;
  class HashTable:&lt;br /&gt;
      def __init__(self):&lt;br /&gt;
         self.capacity = ... #Geigneter Wert&lt;br /&gt;
         self.size = 0&lt;br /&gt;
         self.array = [None]*self.capacity&lt;br /&gt;
&lt;br /&gt;
In Python wird der Zugriffsoperator ''[ ]'' für eine Datenstruktur wie folgt (innerhalb einer Klasse) implementiert:&lt;br /&gt;
  def __setitem__(self, key, value)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
So dass im Programmtext dann folgender Syntax möglich ist: &amp;lt;tt&amp;gt;a[key] = value&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Genauso wir die Zuweisung &amp;lt;tt&amp;gt;value=a[key]&amp;lt;/tt&amp;gt; wie folgt umgesetzt&lt;br /&gt;
  def __getitem__(self, key, value)&lt;br /&gt;
&lt;br /&gt;
Implementierung der &amp;lt;tt&amp;gt;__setitem__&amp;lt;/tt&amp;gt; Funktionen in der &amp;lt;tt&amp;gt;HashTable&amp;lt;/tt&amp;gt; Klasse:&lt;br /&gt;
  def __setitme__(self, key, value):&lt;br /&gt;
      index = hash(key) % self.capacity&lt;br /&gt;
      node = self.array[index]&lt;br /&gt;
      while node is not None:&lt;br /&gt;
          if node.key == key:&lt;br /&gt;
              #Element key ist schon in der Tabelle&lt;br /&gt;
              #Überschreibe die Daten mit dem neuen Wert&lt;br /&gt;
              node.data = value&lt;br /&gt;
              return&lt;br /&gt;
          #Kollision des Hashwerts, probiere nächsten Key aus&lt;br /&gt;
          node = node.next&lt;br /&gt;
       #Kein Element hatte den richtigen Schlüssel.&lt;br /&gt;
       #==&amp;gt;Es gibt diesen Schlüssel noch nicht&lt;br /&gt;
       #Füge also ein neues Element in die Hashtabelle ein&lt;br /&gt;
       &lt;br /&gt;
       self.array[index] = HashNode(key, value, self.array[index])&lt;br /&gt;
       #Der alte Anfang der List wurde der Nachfolger vom neue eingefügten&lt;br /&gt;
       #ersten Element&lt;br /&gt;
       &lt;br /&gt;
       size+=1&lt;br /&gt;
&lt;br /&gt;
Und die Implementierung der &amp;lt;tt&amp;gt;__getitem__&amp;lt;/tt&amp;gt; Funktionen:&lt;br /&gt;
  def __getItem__(self, key):&lt;br /&gt;
      index = hash(key) % self.capacity&lt;br /&gt;
      node = self.array[index]&lt;br /&gt;
      while node is not None:&lt;br /&gt;
           if node.key == key #Gefunden!&lt;br /&gt;
               return Node.data&lt;br /&gt;
           node = node.next&lt;br /&gt;
      raise KeyError(key)&lt;br /&gt;
&lt;br /&gt;
== Hashtabelle mit offener Adressierung (offenes Hashing) ==&lt;br /&gt;
Optimistischer Ansatz: Kollisionen werden nicht so häufig auftreten.&lt;br /&gt;
&lt;br /&gt;
=== Idee ===&lt;br /&gt;
Wenn &amp;lt;tt&amp;gt;array[index]&amp;lt;/tt&amp;gt; durch Kollision bereits vergeben ist, probiere einen&lt;br /&gt;
anderen Index aus.&lt;br /&gt;
&lt;br /&gt;
* Das Array enthält pro Element höchstens ein (key,value)-Paar&lt;br /&gt;
* Das Array muss stets mindestens ''einen'' freien Platz haben (sonst gäbe es eine   Endlosschleife). Es gilt immer &amp;lt;tt&amp;gt;self.size &amp;lt; self.capacity&amp;lt;/tt&amp;gt;. Dies galt für die vorige Hash Implementation nicht.&lt;br /&gt;
&lt;br /&gt;
=== Vorgehen bei Kollisionen ===&lt;br /&gt;
&lt;br /&gt;
==== Sequentielles Suchen ====&lt;br /&gt;
Probiere den nächsten Index: &amp;lt;tt&amp;gt;index = index+1 % capacity&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Vorteil: einfach&lt;br /&gt;
* Nachteil: Clusterbildung&lt;br /&gt;
&lt;br /&gt;
Clusterbildung heißt, dass sich größere zusammenhängende Bereiche bilden die belegt sind, unterbrochen von Bereichen die komplett frei sind. Beim Versuche des Einfügens eines Elements an einen Platz, der schon belegt ist, muss jetzt das ganze Cluster sequentiell durchlaufen werden, bis ein freier Platz gefunden wird. Damit entspricht die Komplexität der Suche der mittleren Länge der belegten Bereiche, was sich entsprechend in einer langsamen Suche widerspiegelt.&lt;br /&gt;
&lt;br /&gt;
==== Doppeltes Hashing ====&lt;br /&gt;
Bestimme einen neuen Index (bei Kollisionen) durch eine ''2. Hashfunktion''.&lt;br /&gt;
&lt;br /&gt;
Das doppelte Hashing wird typischerweise in der Praxis angewendet und liegt auch der Python Implementierung des Datentyps ''Dictionary'' (Syntax &amp;lt;tt&amp;gt;{'a':1, 'b':2, 'c':3}&amp;lt;/tt&amp;gt; zugrunde.&lt;br /&gt;
&lt;br /&gt;
Eine effiziente Implementierung dieses Datentyps ist für die Performance der Skriptsprache Python extrem wichtig, da z.B. beim Aufruf einer Funktion der auszuführunde Code in einem Dictionary unter dem Schlüssel ''Funktionsname'' nachgeschlagen wird oder die Werte lokaler Variablen innerhalb einer Funktion ebenfalls in einem Dictionary zu finden sind.&lt;br /&gt;
&lt;br /&gt;
Für die Implementierung in Python werden wieder die obigen Klassen &amp;lt;tt&amp;gt;HashNode&amp;lt;/tt&amp;gt; und &amp;lt;tt&amp;gt;HashTable&amp;lt;/tt&amp;gt; benötigt, es folgen die angepassten Implementationen von &amp;lt;tt&amp;gt;__setitem&amp;lt;/tt&amp;gt; und &amp;lt;tt&amp;gt;__getitem__&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
  def __setitem__(self, key, value):&lt;br /&gt;
      h = hash(key)&lt;br /&gt;
      index = h % self.capacity&lt;br /&gt;
      while True:&lt;br /&gt;
          if self.array[index] is None or self.array[index].key is None&lt;br /&gt;
               #das Feld ist frei (1. Abfrage)&lt;br /&gt;
               #oder das feld ist als frei markiert (2. Abfrage)&lt;br /&gt;
               self.array[index] = HashNode(key, value)&lt;br /&gt;
               self.size +=1&lt;br /&gt;
               return&lt;br /&gt;
          if self.array[index].key == key:&lt;br /&gt;
               #Es gibt diesen Schlüssel schon,&lt;br /&gt;
               #überschreibe die Daten&lt;br /&gt;
               self.array[index].data = value&lt;br /&gt;
          #Letzter Fall: Kollision&lt;br /&gt;
          index = (5*index+1+h) % self.capacity&lt;br /&gt;
          h = h &amp;gt;&amp;gt; 5&lt;br /&gt;
&lt;br /&gt;
Die vorgestellte Implementierung orientiert sich an Pythons interner Dictionary Implementierung, der zugehörige Quelltext mit ausführlichem Kommentar) findet sich unter [http://svn.python.org/view/*checkout*/python/trunk/Objects/dictobject.c dictobject.c Python Implementation (SVN)]&lt;br /&gt;
&lt;br /&gt;
===== Komplexität des offenen Hashings =====&lt;br /&gt;
&lt;br /&gt;
* Annahme: uniformes Hashing, das heißt alle Indizes haben gleiche Wahrscheinlichkeit&lt;br /&gt;
* Füllstand &amp;lt;math&amp;gt;\alpha = \frac{\text{size}}{\text{capacity}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* '''Erfolglose Suche''' (d.h. es wird entweder ein neues Element eingefügt oder ein &amp;lt;tt&amp;gt;keyError&amp;lt;/tt&amp;gt; geworfen): Untere Schranke für die Komplexität ist &amp;lt;math&amp;gt;\Omega\left(\frac{1}{1-\alpha}\right)&amp;lt;/math&amp;gt; Schritte bzw. Anzahl von neuen index Berechnungen.&lt;br /&gt;
* '''Erfolgreiche Suche''' &amp;lt;math&amp;gt;\Omega\left(\frac{1}{\alpha}\ln\left(\frac{1}{1-\alpha}\right)\right)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;5&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
! &amp;lt;math&amp;gt;\alpha&amp;lt;/math&amp;gt;&lt;br /&gt;
! 0.5&lt;br /&gt;
! 0.9&lt;br /&gt;
|- &lt;br /&gt;
| erfolglos&lt;br /&gt;
| 2.0&lt;br /&gt;
| 10&lt;br /&gt;
|-&lt;br /&gt;
| erfolgreich&lt;br /&gt;
| 1.4&lt;br /&gt;
| 2.6&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Thorben</name></author>	</entry>

	<entry>
		<id>https://alda.iwr.uni-heidelberg.de/index.php?title=Iteration_versus_Rekursion&amp;diff=1591</id>
		<title>Iteration versus Rekursion</title>
		<link rel="alternate" type="text/html" href="https://alda.iwr.uni-heidelberg.de/index.php?title=Iteration_versus_Rekursion&amp;diff=1591"/>
				<updated>2008-06-04T16:27:24Z</updated>
		
		<summary type="html">&lt;p&gt;Thorben: /* Doppeltes Hashing */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Hashtabelle mit linearer Verkettung ==&lt;br /&gt;
Pessimistischer Ansatz: Kollisionen treten häufig auf, deshalb wird unter jedem&lt;br /&gt;
Hashindex gleich eine Liste angelegt, in der Einträge aufgenommen werden können.&lt;br /&gt;
&lt;br /&gt;
===Implementation in Python===&lt;br /&gt;
''HashNode'' ist eine Hilfsdatenstruktur, die Schlüssel und Wert speichert&lt;br /&gt;
und mit hilfe von ''next'' eine verkettete Liste darstellt&lt;br /&gt;
  class HashNode:&lt;br /&gt;
      def __init__(self,key,data,next):&lt;br /&gt;
          self.key = key&lt;br /&gt;
          self.data = data&lt;br /&gt;
          self.next = next #Verkettung!&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Die eigentliche Hashtabelle wir in der Klasse ''HashTable'' implementier:&lt;br /&gt;
  class HashTable:&lt;br /&gt;
      def __init__(self):&lt;br /&gt;
         self.capacity = ... #Geigneter Wert&lt;br /&gt;
         self.size = 0&lt;br /&gt;
         self.array = [None]*self.capacity&lt;br /&gt;
&lt;br /&gt;
In Python wird der Zugriffsoperator ''[ ]'' für eine Datenstruktur wie folgt (innerhalb einer Klasse) implementiert:&lt;br /&gt;
  def __setitem__(self, key, value)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
So dass im Programmtext dann folgender Syntax möglich ist: &amp;lt;tt&amp;gt;a[key] = value&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Genauso wir die Zuweisung &amp;lt;tt&amp;gt;value=a[key]&amp;lt;/tt&amp;gt; wie folgt umgesetzt&lt;br /&gt;
  def __getitem__(self, key, value)&lt;br /&gt;
&lt;br /&gt;
Implementierung der &amp;lt;tt&amp;gt;__setitem__&amp;lt;/tt&amp;gt; Funktionen in der &amp;lt;tt&amp;gt;HashTable&amp;lt;/tt&amp;gt; Klasse:&lt;br /&gt;
  def __setitme__(self, key, value):&lt;br /&gt;
      index = hash(key) % self.capacity&lt;br /&gt;
      node = self.array[index]&lt;br /&gt;
      while node is not None:&lt;br /&gt;
          if node.key == key:&lt;br /&gt;
              #Element key ist schon in der Tabelle&lt;br /&gt;
              #Überschreibe die Daten mit dem neuen Wert&lt;br /&gt;
              node.data = value&lt;br /&gt;
              return&lt;br /&gt;
          #Kollision des Hashwerts, probiere nächsten Key aus&lt;br /&gt;
          node = node.next&lt;br /&gt;
       #Kein Element hatte den richtigen Schlüssel.&lt;br /&gt;
       #==&amp;gt;Es gibt diesen Schlüssel noch nicht&lt;br /&gt;
       #Füge also ein neues Element in die Hashtabelle ein&lt;br /&gt;
       &lt;br /&gt;
       self.array[index] = HashNode(key, value, self.array[index])&lt;br /&gt;
       #Der alte Anfang der List wurde der Nachfolger vom neue eingefügten&lt;br /&gt;
       #ersten Element&lt;br /&gt;
       &lt;br /&gt;
       size+=1&lt;br /&gt;
&lt;br /&gt;
Und die Implementierung der &amp;lt;tt&amp;gt;__getitem__&amp;lt;/tt&amp;gt; Funktionen:&lt;br /&gt;
  def __getItem__(self, key):&lt;br /&gt;
      index = hash(key) % self.capacity&lt;br /&gt;
      node = self.array[index]&lt;br /&gt;
      while node is not None:&lt;br /&gt;
           if node.key == key #Gefunden!&lt;br /&gt;
               return Node.data&lt;br /&gt;
           node = node.next&lt;br /&gt;
      raise KeyError(key)&lt;br /&gt;
&lt;br /&gt;
== Hashtabelle mit offener Adressierung (offenes Hashing) ==&lt;br /&gt;
Optimistischer Ansatz: Kollisionen werden nicht so häufig auftreten.&lt;br /&gt;
&lt;br /&gt;
=== Idee ===&lt;br /&gt;
Wenn &amp;lt;tt&amp;gt;array[index]&amp;lt;/tt&amp;gt; durch Kollision bereits vergeben ist, probiere einen&lt;br /&gt;
anderen Index aus.&lt;br /&gt;
&lt;br /&gt;
* Das Array enthält pro Element höchstens ein (key,value)-Paar&lt;br /&gt;
* Das Array muss stets mindestens ''einen'' freien Platz haben (sonst gäbe es eine   Endlosschleife). Es gilt immer &amp;lt;tt&amp;gt;self.size &amp;lt; self.capacity&amp;lt;/tt&amp;gt;. Dies galt für die vorige Hash Implementation nicht.&lt;br /&gt;
&lt;br /&gt;
=== Vorgehen bei Kollisionen ===&lt;br /&gt;
&lt;br /&gt;
==== Sequentielles Suchen ====&lt;br /&gt;
Probiere den nächsten Index: &amp;lt;tt&amp;gt;index = index+1 % capacity&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Vorteil: einfach&lt;br /&gt;
* Nachteil: Clusterbildung&lt;br /&gt;
&lt;br /&gt;
Clusterbildung heißt, dass sich größere zusammenhängende Bereiche bilden die belegt sind, unterbrochen von Bereichen die komplett frei sind. Beim Versuche des Einfügens eines Elements an einen Platz, der schon belegt ist, muss jetzt das ganze Cluster sequentiell durchlaufen werden, bis ein freier Platz gefunden wird. Damit entspricht die Komplexität der Suche der mittleren Länge der belegten Bereiche, was sich entsprechend in einer langsamen Suche widerspiegelt.&lt;br /&gt;
&lt;br /&gt;
==== Doppeltes Hashing ====&lt;br /&gt;
Bestimme einen neuen Index (bei Kollisionen) durch eine ''2. Hashfunktion''.&lt;br /&gt;
&lt;br /&gt;
Das doppelte Hashing wird typischerweise in der Praxis angewendet und liegt auch der Python Implementierung des Datentyps ''Dictionary'' (Syntax &amp;lt;tt&amp;gt;{'a':1, 'b':2, 'c':3}&amp;lt;/tt&amp;gt; zugrunde.&lt;br /&gt;
&lt;br /&gt;
Eine effiziente Implementierung dieses Datentyps ist für die Performance der Skriptsprache Python extrem wichtig, da z.B. beim Aufruf einer Funktion der auszuführunde Code in einem Dictionary unter dem Schlüssel ''Funktionsname'' nachgeschlagen wird oder die Werte lokaler Variablen innerhalb einer Funktion ebenfalls in einem Dictionary zu finden sind.&lt;br /&gt;
&lt;br /&gt;
Für die Implementierung in Python werden wieder die obigen Klassen &amp;lt;tt&amp;gt;HashNode&amp;lt;/tt&amp;gt; und &amp;lt;tt&amp;gt;HashTable&amp;lt;/tt&amp;gt; benötigt, es folgen die angepassten Implementationen von &amp;lt;tt&amp;gt;__setitem&amp;lt;/tt&amp;gt; und &amp;lt;tt&amp;gt;__getitem__&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
  def __setitem__(self, key, value):&lt;br /&gt;
      h = hash(key)&lt;br /&gt;
      index = h % self.capacity&lt;br /&gt;
      while True:&lt;br /&gt;
          if self.array[index] is None or self.array[index].key is None&lt;br /&gt;
               #das Feld ist frei (1. Abfrage)&lt;br /&gt;
               #oder das feld ist als frei markiert (2. Abfrage)&lt;br /&gt;
               self.array[index] = HashNode(key, value)&lt;br /&gt;
               self.size +=1&lt;br /&gt;
               return&lt;br /&gt;
          if self.array[index].key == key:&lt;br /&gt;
               #Es gibt diesen Schlüssel schon,&lt;br /&gt;
               #überschreibe die Daten&lt;br /&gt;
               self.array[index].data = value&lt;br /&gt;
          #Letzter Fall: Kollision&lt;br /&gt;
          index = (5*index+1+h) % self.capacity&lt;br /&gt;
          h = h &amp;gt;&amp;gt; 5&lt;br /&gt;
&lt;br /&gt;
Die vorgestellte Implementierung orientiert sich an Pythons interner Dictionary Implementierung, der zugehörige Quelltext mit ausführlichem Kommentar) findet sich unter [http://svn.python.org/view/*checkout*/python/trunk/Objects/dictobject.c dictobject.c Python Implementation (SVN)]&lt;br /&gt;
&lt;br /&gt;
===== Komplexität des offenen Hashings =====&lt;br /&gt;
&lt;br /&gt;
* Annahme: uniformes Hashing, das heißt alle Indizes haben gleiche Wahrscheinlichkeit&lt;br /&gt;
* Füllstand &amp;lt;math&amp;gt;\alpha = \frac{\text{size}}{\text{capacity}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* '''Erfolglose Suche''' (d.h. es wird entweder ein neues Element eingefügt oder ein &amp;lt;tt&amp;gt;keyError&amp;lt;/tt&amp;gt; geworfen): Untere Schranke für die Komplexität ist &amp;lt;math&amp;gt;\Omega\left(\frac{1}{1-\alpha}\right)&amp;lt;/math&amp;gt; Schritte bzw. Anzahl von neuen index Berechnungen.&lt;br /&gt;
* '''Erfolgreiche Suche''' &amp;lt;math&amp;gt;\Omega\left(\frac{1}{\alpha}\ln\left(\frac{1}{1-\alpha}\right)\right)&amp;lt;/math&amp;gt;&lt;/div&gt;</summary>
		<author><name>Thorben</name></author>	</entry>

	<entry>
		<id>https://alda.iwr.uni-heidelberg.de/index.php?title=Iteration_versus_Rekursion&amp;diff=1589</id>
		<title>Iteration versus Rekursion</title>
		<link rel="alternate" type="text/html" href="https://alda.iwr.uni-heidelberg.de/index.php?title=Iteration_versus_Rekursion&amp;diff=1589"/>
				<updated>2008-06-04T16:21:05Z</updated>
		
		<summary type="html">&lt;p&gt;Thorben: /* Doppeltes Hashing */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Hashtabelle mit linearer Verkettung ==&lt;br /&gt;
Pessimistischer Ansatz: Kollisionen treten häufig auf, deshalb wird unter jedem&lt;br /&gt;
Hashindex gleich eine Liste angelegt, in der Einträge aufgenommen werden können.&lt;br /&gt;
&lt;br /&gt;
===Implementation in Python===&lt;br /&gt;
''HashNode'' ist eine Hilfsdatenstruktur, die Schlüssel und Wert speichert&lt;br /&gt;
und mit hilfe von ''next'' eine verkettete Liste darstellt&lt;br /&gt;
  class HashNode:&lt;br /&gt;
      def __init__(self,key,data,next):&lt;br /&gt;
          self.key = key&lt;br /&gt;
          self.data = data&lt;br /&gt;
          self.next = next #Verkettung!&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Die eigentliche Hashtabelle wir in der Klasse ''HashTable'' implementier:&lt;br /&gt;
  class HashTable:&lt;br /&gt;
      def __init__(self):&lt;br /&gt;
         self.capacity = ... #Geigneter Wert&lt;br /&gt;
         self.size = 0&lt;br /&gt;
         self.array = [None]*self.capacity&lt;br /&gt;
&lt;br /&gt;
In Python wird der Zugriffsoperator ''[ ]'' für eine Datenstruktur wie folgt (innerhalb einer Klasse) implementiert:&lt;br /&gt;
  def __setitem__(self, key, value)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
So dass im Programmtext dann folgender Syntax möglich ist: &amp;lt;tt&amp;gt;a[key] = value&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Genauso wir die Zuweisung &amp;lt;tt&amp;gt;value=a[key]&amp;lt;/tt&amp;gt; wie folgt umgesetzt&lt;br /&gt;
  def __getitem__(self, key, value)&lt;br /&gt;
&lt;br /&gt;
Implementierung der &amp;lt;tt&amp;gt;__setitem__&amp;lt;/tt&amp;gt; Funktionen in der &amp;lt;tt&amp;gt;HashTable&amp;lt;/tt&amp;gt; Klasse:&lt;br /&gt;
  def __setitme__(self, key, value):&lt;br /&gt;
      index = hash(key) % self.capacity&lt;br /&gt;
      node = self.array[index]&lt;br /&gt;
      while node is not None:&lt;br /&gt;
          if node.key == key:&lt;br /&gt;
              #Element key ist schon in der Tabelle&lt;br /&gt;
              #Überschreibe die Daten mit dem neuen Wert&lt;br /&gt;
              node.data = value&lt;br /&gt;
              return&lt;br /&gt;
          #Kollision des Hashwerts, probiere nächsten Key aus&lt;br /&gt;
          node = node.next&lt;br /&gt;
       #Kein Element hatte den richtigen Schlüssel.&lt;br /&gt;
       #==&amp;gt;Es gibt diesen Schlüssel noch nicht&lt;br /&gt;
       #Füge also ein neues Element in die Hashtabelle ein&lt;br /&gt;
       &lt;br /&gt;
       self.array[index] = HashNode(key, value, self.array[index])&lt;br /&gt;
       #Der alte Anfang der List wurde der Nachfolger vom neue eingefügten&lt;br /&gt;
       #ersten Element&lt;br /&gt;
       &lt;br /&gt;
       size+=1&lt;br /&gt;
&lt;br /&gt;
Und die Implementierung der &amp;lt;tt&amp;gt;__getitem__&amp;lt;/tt&amp;gt; Funktionen:&lt;br /&gt;
  def __getItem__(self, key):&lt;br /&gt;
      index = hash(key) % self.capacity&lt;br /&gt;
      node = self.array[index]&lt;br /&gt;
      while node is not None:&lt;br /&gt;
           if node.key == key #Gefunden!&lt;br /&gt;
               return Node.data&lt;br /&gt;
           node = node.next&lt;br /&gt;
      raise KeyError(key)&lt;br /&gt;
&lt;br /&gt;
== Hashtabelle mit offener Adressierung (offenes Hashing) ==&lt;br /&gt;
Optimistischer Ansatz: Kollisionen werden nicht so häufig auftreten.&lt;br /&gt;
&lt;br /&gt;
=== Idee ===&lt;br /&gt;
Wenn &amp;lt;tt&amp;gt;array[index]&amp;lt;/tt&amp;gt; durch Kollision bereits vergeben ist, probiere einen&lt;br /&gt;
anderen Index aus.&lt;br /&gt;
&lt;br /&gt;
* Das Array enthält pro Element höchstens ein (key,value)-Paar&lt;br /&gt;
* Das Array muss stets mindestens ''einen'' freien Platz haben (sonst gäbe es eine   Endlosschleife). Es gilt immer &amp;lt;tt&amp;gt;self.size &amp;lt; self.capacity&amp;lt;/tt&amp;gt;. Dies galt für die vorige Hash Implementation nicht.&lt;br /&gt;
&lt;br /&gt;
=== Vorgehen bei Kollisionen ===&lt;br /&gt;
&lt;br /&gt;
==== Sequentielles Suchen ====&lt;br /&gt;
Probiere den nächsten Index: &amp;lt;tt&amp;gt;index = index+1 % capacity&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Vorteil: einfach&lt;br /&gt;
* Nachteil: Clusterbildung&lt;br /&gt;
&lt;br /&gt;
Clusterbildung heißt, dass sich größere zusammenhängende Bereiche bilden die belegt sind, unterbrochen von Bereichen die komplett frei sind. Beim Versuche des Einfügens eines Elements an einen Platz, der schon belegt ist, muss jetzt das ganze Cluster sequentiell durchlaufen werden, bis ein freier Platz gefunden wird. Damit entspricht die Komplexität der Suche der mittleren Länge der belegten Bereiche, was sich entsprechend in einer langsamen Suche widerspiegelt.&lt;br /&gt;
&lt;br /&gt;
==== Doppeltes Hashing ====&lt;br /&gt;
Bestimme einen neuen Index (bei Kollisionen) durch eine ''2. Hashfunktion''.&lt;br /&gt;
&lt;br /&gt;
Das doppelte Hashing wird typischerweise in der Praxis angewendet und liegt auch der Python Implementierung des Datentyps ''Dictionary'' (Syntax &amp;lt;tt&amp;gt;{'a':1, 'b':2, 'c':3}&amp;lt;/tt&amp;gt; zugrunde.&lt;br /&gt;
&lt;br /&gt;
Eine effiziente Implementierung dieses Datentyps ist für die Performance der Skriptsprache Python extrem wichtig, da z.B. beim Aufruf einer Funktion der auszuführunde Code in einem Dictionary unter dem Schlüssel ''Funktionsname'' nachgeschlagen wird oder die Werte lokaler Variablen innerhalb einer Funktion ebenfalls in einem Dictionary zu finden sind.&lt;br /&gt;
&lt;br /&gt;
Für die Implementierung in Python werden wieder die obigen Klassen &amp;lt;tt&amp;gt;HashNode&amp;lt;/tt&amp;gt; und &amp;lt;tt&amp;gt;HashTable&amp;lt;/tt&amp;gt; benötigt, es folgen die angepassten Implementationen von &amp;lt;tt&amp;gt;__setitem&amp;lt;/tt&amp;gt; und &amp;lt;tt&amp;gt;__getitem__&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
  def __setitem__(self, key, value):&lt;br /&gt;
      h = hash(key)&lt;br /&gt;
      index = h % self.capacity&lt;br /&gt;
      while True:&lt;br /&gt;
          if self.array[index] is None or self.array[index].key is None&lt;br /&gt;
               #das Feld ist frei (1. Abfrage)&lt;br /&gt;
               #oder das feld ist als frei markiert (2. Abfrage)&lt;br /&gt;
               self.array[index] = HashNode(key, value)&lt;br /&gt;
               self.size +=1&lt;br /&gt;
               return&lt;br /&gt;
          if self.array[index].key == key:&lt;br /&gt;
               #Es gibt diesen Schlüssel schon,&lt;br /&gt;
               #überschreibe die Daten&lt;br /&gt;
               self.array[index].data = value&lt;br /&gt;
          #Letzter Fall: Kollision&lt;br /&gt;
          index = (5*index+1+h) % self.capacity&lt;br /&gt;
          h = h &amp;gt;&amp;gt; 5&lt;br /&gt;
&lt;br /&gt;
Die vorgestellte Implementierung orientiert sich an Pythons interner Dictionary Implementierung, der zugehörige Quelltext mit ausführlichem Kommentar) findet sich unter [http://svn.python.org/view/*checkout*/python/trunk/Objects/dictobject.c dictobject.c Python Implementation (SVN)]&lt;/div&gt;</summary>
		<author><name>Thorben</name></author>	</entry>

	<entry>
		<id>https://alda.iwr.uni-heidelberg.de/index.php?title=Iteration_versus_Rekursion&amp;diff=1588</id>
		<title>Iteration versus Rekursion</title>
		<link rel="alternate" type="text/html" href="https://alda.iwr.uni-heidelberg.de/index.php?title=Iteration_versus_Rekursion&amp;diff=1588"/>
				<updated>2008-06-04T16:15:32Z</updated>
		
		<summary type="html">&lt;p&gt;Thorben: /* Hashtabelle mit offener Adressierung (offenes Hashing) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Hashtabelle mit linearer Verkettung ==&lt;br /&gt;
Pessimistischer Ansatz: Kollisionen treten häufig auf, deshalb wird unter jedem&lt;br /&gt;
Hashindex gleich eine Liste angelegt, in der Einträge aufgenommen werden können.&lt;br /&gt;
&lt;br /&gt;
===Implementation in Python===&lt;br /&gt;
''HashNode'' ist eine Hilfsdatenstruktur, die Schlüssel und Wert speichert&lt;br /&gt;
und mit hilfe von ''next'' eine verkettete Liste darstellt&lt;br /&gt;
  class HashNode:&lt;br /&gt;
      def __init__(self,key,data,next):&lt;br /&gt;
          self.key = key&lt;br /&gt;
          self.data = data&lt;br /&gt;
          self.next = next #Verkettung!&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Die eigentliche Hashtabelle wir in der Klasse ''HashTable'' implementier:&lt;br /&gt;
  class HashTable:&lt;br /&gt;
      def __init__(self):&lt;br /&gt;
         self.capacity = ... #Geigneter Wert&lt;br /&gt;
         self.size = 0&lt;br /&gt;
         self.array = [None]*self.capacity&lt;br /&gt;
&lt;br /&gt;
In Python wird der Zugriffsoperator ''[ ]'' für eine Datenstruktur wie folgt (innerhalb einer Klasse) implementiert:&lt;br /&gt;
  def __setitem__(self, key, value)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
So dass im Programmtext dann folgender Syntax möglich ist: &amp;lt;tt&amp;gt;a[key] = value&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Genauso wir die Zuweisung &amp;lt;tt&amp;gt;value=a[key]&amp;lt;/tt&amp;gt; wie folgt umgesetzt&lt;br /&gt;
  def __getitem__(self, key, value)&lt;br /&gt;
&lt;br /&gt;
Implementierung der &amp;lt;tt&amp;gt;__setitem__&amp;lt;/tt&amp;gt; Funktionen in der &amp;lt;tt&amp;gt;HashTable&amp;lt;/tt&amp;gt; Klasse:&lt;br /&gt;
  def __setitme__(self, key, value):&lt;br /&gt;
      index = hash(key) % self.capacity&lt;br /&gt;
      node = self.array[index]&lt;br /&gt;
      while node is not None:&lt;br /&gt;
          if node.key == key:&lt;br /&gt;
              #Element key ist schon in der Tabelle&lt;br /&gt;
              #Überschreibe die Daten mit dem neuen Wert&lt;br /&gt;
              node.data = value&lt;br /&gt;
              return&lt;br /&gt;
          #Kollision des Hashwerts, probiere nächsten Key aus&lt;br /&gt;
          node = node.next&lt;br /&gt;
       #Kein Element hatte den richtigen Schlüssel.&lt;br /&gt;
       #==&amp;gt;Es gibt diesen Schlüssel noch nicht&lt;br /&gt;
       #Füge also ein neues Element in die Hashtabelle ein&lt;br /&gt;
       &lt;br /&gt;
       self.array[index] = HashNode(key, value, self.array[index])&lt;br /&gt;
       #Der alte Anfang der List wurde der Nachfolger vom neue eingefügten&lt;br /&gt;
       #ersten Element&lt;br /&gt;
       &lt;br /&gt;
       size+=1&lt;br /&gt;
&lt;br /&gt;
Und die Implementierung der &amp;lt;tt&amp;gt;__getitem__&amp;lt;/tt&amp;gt; Funktionen:&lt;br /&gt;
  def __getItem__(self, key):&lt;br /&gt;
      index = hash(key) % self.capacity&lt;br /&gt;
      node = self.array[index]&lt;br /&gt;
      while node is not None:&lt;br /&gt;
           if node.key == key #Gefunden!&lt;br /&gt;
               return Node.data&lt;br /&gt;
           node = node.next&lt;br /&gt;
      raise KeyError(key)&lt;br /&gt;
&lt;br /&gt;
== Hashtabelle mit offener Adressierung (offenes Hashing) ==&lt;br /&gt;
Optimistischer Ansatz: Kollisionen werden nicht so häufig auftreten.&lt;br /&gt;
&lt;br /&gt;
=== Idee ===&lt;br /&gt;
Wenn &amp;lt;tt&amp;gt;array[index]&amp;lt;/tt&amp;gt; durch Kollision bereits vergeben ist, probiere einen&lt;br /&gt;
anderen Index aus.&lt;br /&gt;
&lt;br /&gt;
* Das Array enthält pro Element höchstens ein (key,value)-Paar&lt;br /&gt;
* Das Array muss stets mindestens ''einen'' freien Platz haben (sonst gäbe es eine   Endlosschleife). Es gilt immer &amp;lt;tt&amp;gt;self.size &amp;lt; self.capacity&amp;lt;/tt&amp;gt;. Dies galt für die vorige Hash Implementation nicht.&lt;br /&gt;
&lt;br /&gt;
=== Vorgehen bei Kollisionen ===&lt;br /&gt;
&lt;br /&gt;
==== Sequentielles Suchen ====&lt;br /&gt;
Probiere den nächsten Index: &amp;lt;tt&amp;gt;index = index+1 % capacity&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Vorteil: einfach&lt;br /&gt;
* Nachteil: Clusterbildung&lt;br /&gt;
&lt;br /&gt;
Clusterbildung heißt, dass sich größere zusammenhängende Bereiche bilden die belegt sind, unterbrochen von Bereichen die komplett frei sind. Beim Versuche des Einfügens eines Elements an einen Platz, der schon belegt ist, muss jetzt das ganze Cluster sequentiell durchlaufen werden, bis ein freier Platz gefunden wird. Damit entspricht die Komplexität der Suche der mittleren Länge der belegten Bereiche, was sich entsprechend in einer langsamen Suche widerspiegelt.&lt;br /&gt;
&lt;br /&gt;
==== Doppeltes Hashing ====&lt;br /&gt;
Bestimme einen neuen Index (bei Kollisionen) durch eine ''2. Hashfunktion''.&lt;br /&gt;
&lt;br /&gt;
Das doppelte Hashing wird typischerweise in der Praxis angewendet und liegt auch der Python Implementierung des Datentyps ''Dictionary'' (Syntax &amp;lt;tt&amp;gt;{'a':1, 'b':2, 'c':3}&amp;lt;/tt&amp;gt; zugrunde.&lt;br /&gt;
&lt;br /&gt;
Eine effiziente Implementierung dieses Datentyps ist für die Performance der Skriptsprache Python extrem wichtig, da z.B. beim Aufruf einer Funktion der auszuführunde Code in einem Dictionary unter dem Schlüssel ''Funktionsname'' nachgeschlagen wird oder die Werte lokaler Variablen innerhalb einer Funktion ebenfalls in einem Dictionary zu finden sind.&lt;br /&gt;
&lt;br /&gt;
Für die Implementierung in Python werden wieder die obigen Klassen &amp;lt;tt&amp;gt;HashNode&amp;lt;/tt&amp;gt; und &amp;lt;tt&amp;gt;HashTable&amp;lt;/tt&amp;gt; benötigt, es folgen die angepassten Implementationen von &amp;lt;tt&amp;gt;__setitem&amp;lt;/tt&amp;gt; und &amp;lt;tt&amp;gt;__getitem__&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
  def __setitem__(self, key, value):&lt;br /&gt;
      h = hash(key)&lt;br /&gt;
      index = h % self.capacity&lt;br /&gt;
      while True:&lt;br /&gt;
          if self.array[index] is None or self.array[index].key is None&lt;br /&gt;
               #das Feld ist frei (1. Abfrage)&lt;br /&gt;
               #oder das feld ist als frei markiert (2. Abfrage)&lt;br /&gt;
               self.array[index] = HashNode(key, value)&lt;br /&gt;
               self.size +=1&lt;br /&gt;
               return&lt;br /&gt;
          if self.array[index].key == key:&lt;br /&gt;
               #Es gibt diesen Schlüssel schon,&lt;br /&gt;
               #überschreibe die Daten&lt;br /&gt;
               self.array[index].data = value&lt;br /&gt;
          #Letzter Fall: Kollision&lt;br /&gt;
          index = (5*index+1+h) % self.capacity&lt;br /&gt;
          h = h &amp;gt;&amp;gt; 5&lt;/div&gt;</summary>
		<author><name>Thorben</name></author>	</entry>

	<entry>
		<id>https://alda.iwr.uni-heidelberg.de/index.php?title=Iteration_versus_Rekursion&amp;diff=1587</id>
		<title>Iteration versus Rekursion</title>
		<link rel="alternate" type="text/html" href="https://alda.iwr.uni-heidelberg.de/index.php?title=Iteration_versus_Rekursion&amp;diff=1587"/>
				<updated>2008-06-04T16:11:12Z</updated>
		
		<summary type="html">&lt;p&gt;Thorben: /* Hashtabelle mit offener Adressierung (offenes Hashing) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Hashtabelle mit linearer Verkettung ==&lt;br /&gt;
Pessimistischer Ansatz: Kollisionen treten häufig auf, deshalb wird unter jedem&lt;br /&gt;
Hashindex gleich eine Liste angelegt, in der Einträge aufgenommen werden können.&lt;br /&gt;
&lt;br /&gt;
===Implementation in Python===&lt;br /&gt;
''HashNode'' ist eine Hilfsdatenstruktur, die Schlüssel und Wert speichert&lt;br /&gt;
und mit hilfe von ''next'' eine verkettete Liste darstellt&lt;br /&gt;
  class HashNode:&lt;br /&gt;
      def __init__(self,key,data,next):&lt;br /&gt;
          self.key = key&lt;br /&gt;
          self.data = data&lt;br /&gt;
          self.next = next #Verkettung!&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Die eigentliche Hashtabelle wir in der Klasse ''HashTable'' implementier:&lt;br /&gt;
  class HashTable:&lt;br /&gt;
      def __init__(self):&lt;br /&gt;
         self.capacity = ... #Geigneter Wert&lt;br /&gt;
         self.size = 0&lt;br /&gt;
         self.array = [None]*self.capacity&lt;br /&gt;
&lt;br /&gt;
In Python wird der Zugriffsoperator ''[ ]'' für eine Datenstruktur wie folgt (innerhalb einer Klasse) implementiert:&lt;br /&gt;
  def __setitem__(self, key, value)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
So dass im Programmtext dann folgender Syntax möglich ist: &amp;lt;tt&amp;gt;a[key] = value&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Genauso wir die Zuweisung &amp;lt;tt&amp;gt;value=a[key]&amp;lt;/tt&amp;gt; wie folgt umgesetzt&lt;br /&gt;
  def __getitem__(self, key, value)&lt;br /&gt;
&lt;br /&gt;
Implementierung der &amp;lt;tt&amp;gt;__setitem__&amp;lt;/tt&amp;gt; Funktionen in der &amp;lt;tt&amp;gt;HashTable&amp;lt;/tt&amp;gt; Klasse:&lt;br /&gt;
  def __setitme__(self, key, value):&lt;br /&gt;
      index = hash(key) % self.capacity&lt;br /&gt;
      node = self.array[index]&lt;br /&gt;
      while node is not None:&lt;br /&gt;
          if node.key == key:&lt;br /&gt;
              #Element key ist schon in der Tabelle&lt;br /&gt;
              #Überschreibe die Daten mit dem neuen Wert&lt;br /&gt;
              node.data = value&lt;br /&gt;
              return&lt;br /&gt;
          #Kollision des Hashwerts, probiere nächsten Key aus&lt;br /&gt;
          node = node.next&lt;br /&gt;
       #Kein Element hatte den richtigen Schlüssel.&lt;br /&gt;
       #==&amp;gt;Es gibt diesen Schlüssel noch nicht&lt;br /&gt;
       #Füge also ein neues Element in die Hashtabelle ein&lt;br /&gt;
       &lt;br /&gt;
       self.array[index] = HashNode(key, value, self.array[index])&lt;br /&gt;
       #Der alte Anfang der List wurde der Nachfolger vom neue eingefügten&lt;br /&gt;
       #ersten Element&lt;br /&gt;
       &lt;br /&gt;
       size+=1&lt;br /&gt;
&lt;br /&gt;
Und die Implementierung der &amp;lt;tt&amp;gt;__getitem__&amp;lt;/tt&amp;gt; Funktionen:&lt;br /&gt;
  def __getItem__(self, key):&lt;br /&gt;
      index = hash(key) % self.capacity&lt;br /&gt;
      node = self.array[index]&lt;br /&gt;
      while node is not None:&lt;br /&gt;
           if node.key == key #Gefunden!&lt;br /&gt;
               return Node.data&lt;br /&gt;
           node = node.next&lt;br /&gt;
      raise KeyError(key)&lt;br /&gt;
&lt;br /&gt;
== Hashtabelle mit offener Adressierung (offenes Hashing) ==&lt;br /&gt;
Optimistischer Ansatz: Kollisionen werden nicht so häufig auftreten.&lt;br /&gt;
&lt;br /&gt;
=== Idee ===&lt;br /&gt;
Wenn &amp;lt;tt&amp;gt;array[index]&amp;lt;/tt&amp;gt; durch Kollision bereits vergeben ist, probiere einen&lt;br /&gt;
anderen Index aus.&lt;br /&gt;
&lt;br /&gt;
* Das Array enthält pro Element höchstens ein (key,value)-Paar&lt;br /&gt;
* Das Array muss stets mindestens ''einen'' freien Platz haben (sonst gäbe es eine   Endlosschleife). Es gilt immer &amp;lt;tt&amp;gt;self.size &amp;lt; self.capacity&amp;lt;/tt&amp;gt;. Dies galt für die vorige Hash Implementation nicht.&lt;br /&gt;
&lt;br /&gt;
=== Vorgehen bei Kollisionen ===&lt;br /&gt;
&lt;br /&gt;
==== Sequentielles Suchen ====&lt;br /&gt;
Probiere den nächsten Index: &amp;lt;tt&amp;gt;index = index+1 % capacity&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Vorteil: einfach&lt;br /&gt;
* Nachteil: Clusterbildung&lt;br /&gt;
&lt;br /&gt;
Clusterbildung heißt, dass sich größere zusammenhängende Bereiche bilden die belegt sind, unterbrochen von Bereichen die komplett frei sind. Beim Versuche des Einfügens eines Elements an einen Platz, der schon belegt ist, muss jetzt das ganze Cluster sequentiell durchlaufen werden, bis ein freier Platz gefunden wird. Damit entspricht die Komplexität der Suche der mittleren Länge der belegten Bereiche, was sich entsprechend in einer langsamen Suche widerspiegelt.&lt;br /&gt;
&lt;br /&gt;
==== Doppeltes Hashing ====&lt;br /&gt;
Bestimme einen neuen Index (bei Kollisionen) durch eine ''2. Hashfunktion''.&lt;br /&gt;
&lt;br /&gt;
Das doppelte Hashing wird typischerweise in der Praxis angewendet und liegt auch der Python Implementierung des Datentyps ''Dictionary'' (Syntax &amp;lt;tt&amp;gt;{'a':1, 'b':2, 'c':3}&amp;lt;/tt&amp;gt; zugrunde.&lt;br /&gt;
&lt;br /&gt;
Eine effiziente Implementierung dieses Datentyps ist für die Performance der Skriptsprache Python extrem wichtig, da z.B. beim Aufruf einer Funktion der auszuführunde Code in einem Dictionary unter dem Schlüssel ''Funktionsname'' nachgeschlagen wird oder die Werte lokaler Variablen innerhalb einer Funktion ebenfalls in einem Dictionary zu finden sind.&lt;br /&gt;
&lt;br /&gt;
Für die Implementierung in Python werden wieder die obigen Klassen &amp;lt;tt&amp;gt;HashNode&amp;lt;/tt&amp;gt; und &amp;lt;tt&amp;gt;HashTable&amp;lt;/tt&amp;gt; benötigt, es folgen die angepassten Implementationen von &amp;lt;tt&amp;gt;__setitem&amp;lt;/tt&amp;gt; und &amp;lt;tt&amp;gt;__getitem__&amp;lt;/tt&amp;gt;:&lt;/div&gt;</summary>
		<author><name>Thorben</name></author>	</entry>

	<entry>
		<id>https://alda.iwr.uni-heidelberg.de/index.php?title=Iteration_versus_Rekursion&amp;diff=1586</id>
		<title>Iteration versus Rekursion</title>
		<link rel="alternate" type="text/html" href="https://alda.iwr.uni-heidelberg.de/index.php?title=Iteration_versus_Rekursion&amp;diff=1586"/>
				<updated>2008-06-04T16:01:20Z</updated>
		
		<summary type="html">&lt;p&gt;Thorben: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Hashtabelle mit linearer Verkettung ==&lt;br /&gt;
Pessimistischer Ansatz: Kollisionen treten häufig auf, deshalb wird unter jedem&lt;br /&gt;
Hashindex gleich eine Liste angelegt, in der Einträge aufgenommen werden können.&lt;br /&gt;
&lt;br /&gt;
===Implementation in Python===&lt;br /&gt;
''HashNode'' ist eine Hilfsdatenstruktur, die Schlüssel und Wert speichert&lt;br /&gt;
und mit hilfe von ''next'' eine verkettete Liste darstellt&lt;br /&gt;
  class HashNode:&lt;br /&gt;
      def __init__(self,key,data,next):&lt;br /&gt;
          self.key = key&lt;br /&gt;
          self.data = data&lt;br /&gt;
          self.next = next #Verkettung!&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Die eigentliche Hashtabelle wir in der Klasse ''HashTable'' implementier:&lt;br /&gt;
  class HashTable:&lt;br /&gt;
      def __init__(self):&lt;br /&gt;
         self.capacity = ... #Geigneter Wert&lt;br /&gt;
         self.size = 0&lt;br /&gt;
         self.array = [None]*self.capacity&lt;br /&gt;
&lt;br /&gt;
In Python wird der Zugriffsoperator ''[ ]'' für eine Datenstruktur wie folgt (innerhalb einer Klasse) implementiert:&lt;br /&gt;
  def __setitem__(self, key, value)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
So dass im Programmtext dann folgender Syntax möglich ist: &amp;lt;tt&amp;gt;a[key] = value&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Genauso wir die Zuweisung &amp;lt;tt&amp;gt;value=a[key]&amp;lt;/tt&amp;gt; wie folgt umgesetzt&lt;br /&gt;
  def __getitem__(self, key, value)&lt;br /&gt;
&lt;br /&gt;
Implementierung der &amp;lt;tt&amp;gt;__setitem__&amp;lt;/tt&amp;gt; Funktionen in der &amp;lt;tt&amp;gt;HashTable&amp;lt;/tt&amp;gt; Klasse:&lt;br /&gt;
  def __setitme__(self, key, value):&lt;br /&gt;
      index = hash(key) % self.capacity&lt;br /&gt;
      node = self.array[index]&lt;br /&gt;
      while node is not None:&lt;br /&gt;
          if node.key == key:&lt;br /&gt;
              #Element key ist schon in der Tabelle&lt;br /&gt;
              #Überschreibe die Daten mit dem neuen Wert&lt;br /&gt;
              node.data = value&lt;br /&gt;
              return&lt;br /&gt;
          #Kollision des Hashwerts, probiere nächsten Key aus&lt;br /&gt;
          node = node.next&lt;br /&gt;
       #Kein Element hatte den richtigen Schlüssel.&lt;br /&gt;
       #==&amp;gt;Es gibt diesen Schlüssel noch nicht&lt;br /&gt;
       #Füge also ein neues Element in die Hashtabelle ein&lt;br /&gt;
       &lt;br /&gt;
       self.array[index] = HashNode(key, value, self.array[index])&lt;br /&gt;
       #Der alte Anfang der List wurde der Nachfolger vom neue eingefügten&lt;br /&gt;
       #ersten Element&lt;br /&gt;
       &lt;br /&gt;
       size+=1&lt;br /&gt;
&lt;br /&gt;
Und die Implementierung der &amp;lt;tt&amp;gt;__getitem__&amp;lt;/tt&amp;gt; Funktionen:&lt;br /&gt;
  def __getItem__(self, key):&lt;br /&gt;
      index = hash(key) % self.capacity&lt;br /&gt;
      node = self.array[index]&lt;br /&gt;
      while node is not None:&lt;br /&gt;
           if node.key == key #Gefunden!&lt;br /&gt;
               return Node.data&lt;br /&gt;
           node = node.next&lt;br /&gt;
      raise KeyError(key)&lt;br /&gt;
&lt;br /&gt;
== Hashtabelle mit offener Adressierung (offenes Hashing) ==&lt;br /&gt;
Optimistischer Ansatz: Kollisionen werden nicht so häufig auftreten.&lt;br /&gt;
&lt;br /&gt;
=== Idee ===&lt;br /&gt;
Wenn &amp;lt;tt&amp;gt;array[index]&amp;lt;/tt&amp;gt; durch Kollision bereits vergeben ist, probiere einen&lt;br /&gt;
anderen Index aus.&lt;br /&gt;
&lt;br /&gt;
* Das Array enthält pro Element höchstens ein (key,value)-Paar&lt;br /&gt;
* Das Array muss stets mindestens ''einen'' freien Platz haben (sonst gäbe es eine   Endlosschleife). Es gilt immer &amp;lt;tt&amp;gt;self.size &amp;lt; self.capacity&amp;lt;/tt&amp;gt;. Dies galt für die vorige Hash Implementation nicht.&lt;/div&gt;</summary>
		<author><name>Thorben</name></author>	</entry>

	<entry>
		<id>https://alda.iwr.uni-heidelberg.de/index.php?title=Iteration_versus_Rekursion&amp;diff=1583</id>
		<title>Iteration versus Rekursion</title>
		<link rel="alternate" type="text/html" href="https://alda.iwr.uni-heidelberg.de/index.php?title=Iteration_versus_Rekursion&amp;diff=1583"/>
				<updated>2008-06-04T15:56:06Z</updated>
		
		<summary type="html">&lt;p&gt;Thorben: /* Hashtabelle mit linearer Verkettung */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Hashtabelle mit linearer Verkettung ==&lt;br /&gt;
Pessimistischer Ansatz: Kollisionen treten häufig auf, deshalb wird unter jedem&lt;br /&gt;
Hashindex gleich eine Liste angelegt, in der Einträge aufgenommen werden können.&lt;br /&gt;
&lt;br /&gt;
===Implementation in Python===&lt;br /&gt;
''HashNode'' ist eine Hilfsdatenstruktur, die Schlüssel und Wert speichert&lt;br /&gt;
und mit hilfe von ''next'' eine verkettete Liste darstellt&lt;br /&gt;
  class HashNode:&lt;br /&gt;
      def __init__(self,key,data,next):&lt;br /&gt;
          self.key = key&lt;br /&gt;
          self.data = data&lt;br /&gt;
          self.next = next #Verkettung!&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Die eigentliche Hashtabelle wir in der Klasse ''HashTable'' implementier:&lt;br /&gt;
  class HashTable:&lt;br /&gt;
      def __init__(self):&lt;br /&gt;
         self.capacity = ... #Geigneter Wert&lt;br /&gt;
         self.size = 0&lt;br /&gt;
         self.array = [None]*self.capacity&lt;br /&gt;
&lt;br /&gt;
In Python wird der Zugriffsoperator ''[ ]'' für eine Datenstruktur wie folgt (innerhalb einer Klasse) implementiert:&lt;br /&gt;
  def __setitem__(self, key, value)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
So dass im Programmtext dann folgender Syntax möglich ist: &amp;lt;tt&amp;gt;a[key] = value&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Genauso wir die Zuweisung &amp;lt;tt&amp;gt;value=a[key]&amp;lt;/tt&amp;gt; wie folgt umgesetzt&lt;br /&gt;
  def __getitem__(self, key, value)&lt;br /&gt;
&lt;br /&gt;
Implementierung der &amp;lt;tt&amp;gt;__setitem__&amp;lt;/tt&amp;gt; Funktionen in der &amp;lt;tt&amp;gt;HashTable&amp;lt;/tt&amp;gt; Klasse:&lt;br /&gt;
  def __setitme__(self, key, value):&lt;br /&gt;
      index = hash(key) % self.capacity&lt;br /&gt;
      node = self.array[index]&lt;br /&gt;
      while node is not None:&lt;br /&gt;
          if node.key == key:&lt;br /&gt;
              #Element key ist schon in der Tabelle&lt;br /&gt;
              #Überschreibe die Daten mit dem neuen Wert&lt;br /&gt;
              node.data = value&lt;br /&gt;
              return&lt;br /&gt;
          #Kollision des Hashwerts, probiere nächsten Key aus&lt;br /&gt;
          node = node.next&lt;br /&gt;
       #Kein Element hatte den richtigen Schlüssel.&lt;br /&gt;
       #==&amp;gt;Es gibt diesen Schlüssel noch nicht&lt;br /&gt;
       #Füge also ein neues Element in die Hashtabelle ein&lt;br /&gt;
       &lt;br /&gt;
       self.array[index] = HashNode(key, value, self.array[index])&lt;br /&gt;
       #Der alte Anfang der List wurde der Nachfolger vom neue eingefügten&lt;br /&gt;
       #ersten Element&lt;br /&gt;
       &lt;br /&gt;
       size+=1&lt;br /&gt;
&lt;br /&gt;
Und die Implementierung der &amp;lt;tt&amp;gt;__getitem__&amp;lt;/tt&amp;gt; Funktionen:&lt;br /&gt;
  def __getItem__(self, key):&lt;br /&gt;
      index = hash(key) % self.capacity&lt;br /&gt;
      node = self.array[index]&lt;br /&gt;
      while node is not None:&lt;br /&gt;
           if node.key == key #Gefunden!&lt;br /&gt;
               return Node.data&lt;br /&gt;
           node = node.next&lt;br /&gt;
      raise KeyError(key)&lt;/div&gt;</summary>
		<author><name>Thorben</name></author>	</entry>

	<entry>
		<id>https://alda.iwr.uni-heidelberg.de/index.php?title=Iteration_versus_Rekursion&amp;diff=1582</id>
		<title>Iteration versus Rekursion</title>
		<link rel="alternate" type="text/html" href="https://alda.iwr.uni-heidelberg.de/index.php?title=Iteration_versus_Rekursion&amp;diff=1582"/>
				<updated>2008-06-04T15:54:36Z</updated>
		
		<summary type="html">&lt;p&gt;Thorben: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Hashtabelle mit linearer Verkettung ==&lt;br /&gt;
Pessimistischer Ansatz: Kollisionen treten häufig auf, deshalb wird unter jedem&lt;br /&gt;
Hashindex gleich eine Liste angelegt, in der Einträge aufgenommen werden können.&lt;br /&gt;
&lt;br /&gt;
===Implementation in Python===&lt;br /&gt;
''HashNode'' ist eine Hilfsdatenstruktur, die Schlüssel und Wert speichert&lt;br /&gt;
und mit hilfe von ''next'' eine verkettete Liste darstellt&lt;br /&gt;
  class HashNode:&lt;br /&gt;
      def __init__(self,key,data,next):&lt;br /&gt;
          self.key = key&lt;br /&gt;
          self.data = data&lt;br /&gt;
          self.next = next #Verkettung!&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Die eigentliche Hashtabelle wir in der Klasse ''HashTable'' implementier:&lt;br /&gt;
  class HashTable:&lt;br /&gt;
      def __init__(self):&lt;br /&gt;
         self.capacity = ... #Geigneter Wert&lt;br /&gt;
         self.size = 0&lt;br /&gt;
         self.array = [None]*self.capacity&lt;br /&gt;
&lt;br /&gt;
In Python wird der Zugriffsoperator ''[ ]'' für eine Datenstruktur wie folgt (innerhalb einer Klasse) implementiert:&lt;br /&gt;
  def __setitem__(self, key, value)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
So dass im Programmtext dann folgender Syntax möglich ist: &amp;lt;tt&amp;gt;a[key] = value&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Genauso wir die Zuweisung &amp;lt;tt&amp;gt;value=a[key]&amp;lt;/tt&amp;gt; wie folgt umgesetzt&lt;br /&gt;
  def __getitem__(self, key, value)&lt;br /&gt;
&lt;br /&gt;
Implementierung der &amp;lt;tt&amp;gt;__setitem__&amp;lt;/tt&amp;gt; Funktionen in der &amp;lt;tt&amp;gt;HashTable&amp;lt;/tt&amp;gt; Klasse:&lt;br /&gt;
  def __setitme__(self, key, value):&lt;br /&gt;
      index = hash(key) % self.capacity&lt;br /&gt;
      node = self.array[index]&lt;br /&gt;
      while node is not None:&lt;br /&gt;
          if node.key == key:&lt;br /&gt;
              #Element key ist schon in der Tabelle&lt;br /&gt;
              #Überschreibe die Daten mit dem neuen Wert&lt;br /&gt;
              node.data = value&lt;br /&gt;
              return&lt;br /&gt;
          #Kollision des Hashwerts, probiere nächsten Key aus&lt;br /&gt;
          node = node.next&lt;br /&gt;
       #Kein Element hatte den richtigen Schlüssel.&lt;br /&gt;
       #==&amp;gt;Es gibt diesen Schlüssel noch nicht&lt;br /&gt;
       #Füge also ein neues Element in die Hashtabelle ein&lt;br /&gt;
&lt;br /&gt;
       self.array[index] = HashNode(key, value, self.array[index])&lt;br /&gt;
       #Der alte Anfang der List wurde der Nachfolger vom neue eingefügten&lt;br /&gt;
       #ersten Element&lt;br /&gt;
&lt;br /&gt;
       size+=1&lt;br /&gt;
&lt;br /&gt;
Und die Implementierung der &amp;lt;tt&amp;gt;__getitem__&amp;lt;/tt&amp;gt; Funktionen:&lt;br /&gt;
  def __getItem__(self, key):&lt;br /&gt;
      index = hash(key) % self.capacity&lt;br /&gt;
      node = self.array[index]&lt;br /&gt;
      while node is not None:&lt;br /&gt;
           if node.key == key #Gefunden!&lt;br /&gt;
               return Node.data&lt;br /&gt;
           node = node.next&lt;br /&gt;
      raise KeyError(key)&lt;/div&gt;</summary>
		<author><name>Thorben</name></author>	</entry>

	</feed>