Vanliga datastrukturer (sorterad array, sökträd, hashtabell) faller alla på något av kraven ovan.
tab
.
Den booleska variabeln tab[f(ord)]
låter vi vara
sann (1) då ord
ingår i ordlistan. Detta ger en snabb, minnessnål
och kodad datastruktur, men den har en stor brist: Om det råkar bli
så att hashfunktionen antar samma värde för ett ord i ordlistan som
för ett felstavat ord så kommer det felstavade ordet att godkännas.
Om hashtabellen exempelvis är fylld till häften med ettor så är sannolikheten
för att ett felstavat ord ska godkännas ungefär 50% vilket är alldeles för
mycket.
tab
. I Viggos stavningskontrollprogram Stava
används till exempel 14 olika hashfunktioner f0(ord),f1(ord),
f2(ord),...,f13(ord). Ett ord godkänns bara om
alla dessa 14 hashfunktioner samtidigt ger index till platser i tab
som innehåller sant (det vill säga 1).
Uppslagning av ett ord kan då ske på följande sätt:
for i in range(14): if not tab[f(i,ord)]: return False; return TrueOm hashtabellen är till hälften fylld med ettor blir sannolikheten för att ett felstavat ord godkänns så liten som (1/2)14=0.006%.
Denna datastruktur kallas bloomfilter efter en
datalogiforskare vid namn Bloom. Ett abstrakt bloomfilter har bara
två operationer: insert(x)
som stoppar in x i datastrukturen
och exists(x)
som kollar ifall x finns med i datastrukturen.
Programmet Stava kan köras på Nadas Unixdatorer
med kommandot
stava filnamn
(hjälp finns här) och i webben på
http://www.nada.kth.se/stava/
Sökning på flera ord ger flera listor och då visas först träffar på alla sökorden. Men det som gjort Google till ledande sökmotor är dess förmåga att visa dom bästa länkarna först. Googles upphovsmän är två studenter vid Stanford (Page och Brin) och deras geniala begrepp kallas page rank. Här följer en matematisk beskrivning skriven av Matlabs skapare, Cleve Moler.
Låt W vara mängden av webbsidor som Google kommit åt och låt n vara antalet sidor i W. Just nu är n drygt tre miljarder. Let G be the n-by-n connectivity matrix of W, that is, gij is 1 if there is a hyperlink from page i to page j and 0 otherwise. The matrix G is huge, but very sparse; its number of nonzeros is the total number of hyperlinks in the pages in W. Let cj and ri be the column and row sums of G.
cj = i
gij, ri=
j
gij
The quantities ck and rk are the indegree and outdegree of the k-th page. Vi tänker oss en slumpvandring genom sidorna i W, där vi med sannolikhet p följer en länk till en ny sida och med sannolikhet 1-p hoppar till en på måfå vald sida i W. Google usually takes p = 0.85. Then 1-p is the fraction of time that an arbitrary page is chosen. Let A be the n-by-n matrix whose elements are
aij = p gij / cj + (1-p) / n.
The matrix A is not sparse, but it is a rank one modification of a sparse matrix. Most of the elements of A are equal to the small constant (1-p) / n. När n = 2.7·109 är (1-p) / n = 5.5·10-11.
The matrix is the transition probability matrix of the Markov chain. Its elements are all strictly between zero and one and its column sums are all equal to one. An important result in matrix theory, the Perron-Frobenius Theorem, applies to such matrices. It tells us that the largest eigenvalue of A is equal to one and that the corresponding eigenvector, which satisfies the equation
x = Ax,
exists and is unique to within a scaling factor. When this scaling factor is chosen so that
ixi = 1
then x is the state vector of the Markov chain. The elements of x are Google?s PageRank.
If the matrix were small enough to fit in MATLAB, one way to compute the eigenvector x would be to start with a good approximate solution, such as the PageRanks from the previous month, and simply repeat the assignment statement
x = Ax
until successive vectors agree to within specified tolerance. This is known as the power method and is about the only possible approach for very large n.
I en prioritetskö stämplas en prioritet på varje objekt som stoppas in och vid uthämtning får man objektet med högst prioritet.
En abstrakt prioritetskö kan ha föjande anrop.
put(p,x)
x=get()
isempty()
put(x)
.
Hur den då skiljer sej från en stack och
från en vanlig kö ser man av följande exempel.
pq.put(1) pq.put(3) pq.put(2) x = pq.get() # x blir 3En kö hade skickat tillbaka det först instoppade talet 1; en stack hade skickat tillbaka det senast instoppade talet, 2; prioritetskön skickar tillbaka det bästa talet, 3. I denna prioritetskö betraktar vi största talet som bäst - vi har en så kallad maxprioritetskö. Det finns förstås också minprioritetsköer, där det minsta talet betraktas som bäst.
Prioritetsköer har många användningar. Man kan tänka sej en auktion där
budgivarna stoppar in sina bud i en maxprioritetskö och auktionsförrättaren efter
"första, andra, tredje" gör pq.get()
för att få reda på det
vinnande budet.
För att han ska veta vem som lagt detta bud behövs förstås båda
parametrarna i pq.put(p,x)
.
pq.put(bud,person) #person är ett objekt med budgivarens namn och bud winner = pq.get() #budgivaren med högst bud
tab
tolkad som binärträd.
tab[1]
, dess båda söner är
tab[2]
och tab[3]
osv. Allmänt
gäller att tab[i]
har sönerna
tab[2*i]
och tab[2*i+1]
.
Trappvillkoret är att pappa är bäst, dvs varje tal ligger
på två sämre tal.
Ett nytt tal läggs alltid in sist i trappan. Om trappvillkoret inte blir
uppfyllt, dvs om det är större än sin far, byter far och son plats och
så fortgår det tills villkoret uppfyllts. Det här kallas
upptrappning och kan i värsta fall föra det nya talet
hela vägen upp till toppen, alltså tab[1]
. För
att se till att det i alla fall stannar där kan man från början lägga
in ett jättestort tal i tab[0]
.
Man plockar alltid ut det översta talet ur trappan och fyller igen tomrummet med det sista talet i trappan. Då är inte trappvillkoret uppfyllt, så man får byta talet och dess störste son. Denna nedtrappning upprepas till villkoret åter gäller.
Både put
och get
har komplexitet log N
om trappan har N element. Nackdelen med trappan är man måste
bestämma arrayens storlek från början.
Exempel 1: Sök billigaste transport från Teknis till
Honolulu. All världens resprislistor finns tillgängliga.
Problemträdets poster innehåller en plats, ett pris och en
faderspekare. Överst i trädet står Teknis med priset noll. Sönerna
är alla platser man kan komma till med en transport och priset, till exempel
T-centralen, 9.50
. Man söker en Honolulupost i problemträdet. Med
breddenförstsökning får man den resa som har så få transportsteg som
möjligt. Med bästaförstsökning får man den billigaste resan. Detta
påstående är inte helt självklart utan man får tänka en del för att
inse det.
Exempel 2: Sök effektivaste processen för att framställa
en önskad substans från en given substans. All världens kemiska
reaktioner finns tillgängliga med uppgift om utbytet i procent.
Problemträdets poster innehåller substansnamn och procenttal. Överst i
trädet står utgångssubstansen med procenttalet 100. Sönerna är alla
substanser man kan framställa med en reaktion och utbytet, till
exempel C2H5OH, 96%
. Med en max-prioritetskö får man fram
den effektivaste process som leder till målet.