Datu struktūras un algoritmi

Hash tabulas datu struktūras apmācība

Hash tabulas datu struktūras apmācība
Datorzinātnēs vārds “karte” nozīmē saistīt vienumu vienā komplektā ar citu priekšmetu citā komplektā. Iedomājieties, ka lapā ir vārdi lokā pa kreisi, un tās pašas lapas labajā pusē ir vēl viens aplis, kurā ir citi vārdi. Pieņemsim, ka katrā aplī vārdi tiek rakstīti nejauši, izkaisīti apļa iekšienē. Pieņemsim arī, ka vārdus kreisajā lokā sauc par atslēgām, bet vārdus labajā aplī - par vērtībām. Ja bultiņa tiek novilkta no katra vārda pa kreisi uz katra vārda labajā pusē, tad teiktu, ka taustiņi ir kartēti uz vērtībām.

Pieņemsim, ka jūs esat īpašnieka liels pārtikas veikals apgabalā, kurā dzīvojat. Pieņemsim, ka jūs dzīvojat lielā teritorijā, kas nav komerciāla teritorija. Jūs neesat vienīgais, kuram šajā apgabalā ir pārtikas veikals; jums ir daži konkurenti. Un tad jums ienāk prātā, ka jums ir jāreģistrē klientu tālruņu numuri burtnīcā. Protams, vingrinājumu grāmata ir maza, un jūs nevarat ierakstīt visus tālruņu numurus visiem klientiem.

Tātad jūs nolemjat ierakstīt tikai savu pastāvīgo klientu tālruņa numurus. Tātad jums ir tabula ar divām kolonnām. Kolonnā kreisajā pusē ir klientu vārdi, savukārt labajā slejā ir attiecīgi tālruņu numuri. Tādā veidā notiek kartēšana starp klientu vārdiem un tālruņu numuriem. Tabulas labo kolonnu var uzskatīt par galveno jaukšanas tabulu. Klientu vārdus tagad sauc par atslēgām, un tālruņu numurus sauc par vērtībām. Ņemiet vērā, ka tad, kad klients veic pārskaitījumu, jums būs jāatceļ viņa rinda, ļaujot rindai iztukšoties vai jāaizstāj ar jauna pastāvīgā klienta rindu. Ņemiet vērā arī to, ka ar laiku pastāvīgo klientu skaits var palielināties vai samazināties, tāpēc galds var pieaugt vai sarukt.

Pieņemsim, ka kādā novadā ir vēl viens zemnieku klubs kā vēl viens kartēšanas piemērs. Protams, ne visi zemnieki būs kluba biedri. Daži kluba locekļi nebūs pastāvīgi dalībnieki (piedalās un piedalās). Advokāts var nolemt ierakstīt dalībnieku vārdus un viņu izvēlēto dzērienu. Viņš izstrādā divu kolonnu tabulu. Kreisajā slejā viņš raksta kluba biedru vārdus. Labajā slejā viņš raksta atbilstošo dzēriena izvēli.

Šeit ir problēma: labajā kolonnā ir dublikāti. Tas ir, tas pats dzēriena nosaukums tiek atrasts vairāk nekā vienu reizi. Citiem vārdiem sakot, dažādi dalībnieki dzer vienu un to pašu saldo dzērienu vai to pašu alkoholisko dzērienu, bet citi locekļi dzer atšķirīgu saldo vai alkoholisko dzērienu. Bar-man izlemj atrisināt šo problēmu, ievietojot šauru kolonnu starp abām kolonnām. Šajā vidējā kolonnā, sākot no augšas, viņš numurē rindas, sākot no nulles (t.i.e. 0, 1, 2, 3, 4 utt.), iet uz leju, viens indekss katrā rindā. Līdz ar to viņa problēma ir atrisināta, jo dalībnieka vārds tagad ir saistīts ar indeksu, nevis ar dzēriena nosaukumu. Tātad, tā kā dzēriens tiek identificēts ar indeksu, klienta vārds tiek piesaistīts attiecīgajam indeksam.

Tikai vērtību (dzērienu) kolonna veido pamata jaukšanas tabulu. Modificētajā tabulā indeksu kolonna un ar tām saistītās vērtības (ar dublikātiem vai bez tiem) veido normālu jaukšanas tabulu - pilnīga jaukšanas tabulas definīcija ir sniegta zemāk. Atslēgas (pirmā kolonna) ne vienmēr ir daļa no jaukšanas tabulas.

Kā vēl vienu piemēru vēlreiz apsveriet tīkla serveri, kurā lietotājs no sava klienta datora var pievienot daļu informācijas, izdzēst informāciju vai modificēt to. Serverim ir daudz lietotāju.  Katrs lietotājvārds atbilst serverī saglabātai parolei. Tie, kas uztur serveri, var redzēt lietotājvārdus un atbilstošo paroli, tādējādi spējot sabojāt lietotāju darbu.

Tātad servera īpašnieks nolemj izveidot funkciju, kas šifrē paroli, pirms tā tiek saglabāta. Lietotājs piesakās serverī ar savu parasto saprotamo paroli. Tomēr tagad katra parole tiek saglabāta šifrētā formā. Ja kāds redz šifrētu paroli un mēģina pieteikties, izmantojot to, tas nedarbosies, jo, piesakoties, serveris saņem saprotamu paroli, nevis šifrētu paroli.

Šajā gadījumā saprotamā parole ir atslēga, un vērtība ir šifrēta parole. Ja šifrētā parole ir šifrētu paroļu kolonnā, šī kolonna ir pamata jaukšanas tabula. Ja pirms šīs kolonnas ir vēl viena kolonna ar indeksiem, kas sākas no nulles tā, ka katra šifrētā parole ir saistīta ar indeksu, tad gan indeksu kolonna, gan šifrētās paroles kolonna veido normālu jaukšanas tabulu. Atslēgas ne vienmēr ir daļa no jaukšanas tabulas.

Šajā gadījumā ņemiet vērā, ka katra atslēga, kas ir saprotama parole, atbilst lietotāja vārdam. Tātad, ir lietotāja vārds, kas atbilst atslēgai, kas ir kartēta ar indeksu, kas ir saistīta ar vērtību, kas ir šifrēta atslēga.

Hash funkcijas definīcija, hash tabulas pilnīga definīcija, masīva nozīme un cita informācija ir sniegta zemāk. Lai novērtētu pārējo šīs apmācības daļu, jums ir jābūt zināšanām norādēs (atsaucēs) un saistītajos sarakstos.

Hash funkcijas un hash tabulas nozīme

Masīvs

Masīvs ir secīgu atmiņas vietu kopums. Visas vietas ir vienāda lieluma. Vērtībai pirmajā vietā piekļūst ar indeksu 0; vērtībai otrajā vietā piekļūst ar indeksu 1; trešajai vērtībai piekļūst ar indeksu 2; ceturtais ar indeksu, 3; un tā tālāk. Masīvs parasti nevar palielināties vai samazināties. Lai mainītu masīva lielumu (garumu), ir jāizveido jauns masīvs un atbilstošās vērtības jānokopē jaunajā masīvā. Masīva vērtības vienmēr ir viena veida.

Hash funkcija

Programmatūrā hash funkcija ir funkcija, kas paņem atslēgu un izveido masīva šūnai atbilstošu indeksu. Masīvam ir noteikts izmērs (noteikts garums). Atslēgu skaits ir patvaļīgs, parasti lielāks par masīva lielumu. Indeksu, kas izriet no hash funkcijas, sauc par hash vērtību vai īssavilkumu, hash kodu vai vienkārši hash.

Hash tabula

Jaukšanas tabula ir masīvs ar vērtībām, uz kura indeksiem, taustiņiem tiek kartēti. Atslēgas netieši tiek piesaistītas vērtībām. Faktiski tiek uzskatīts, ka atslēgas ir saistītas ar vērtībām, jo ​​katrs indekss ir saistīts ar vērtību (ar dublikātiem vai bez tiem). Tomēr funkcija, kas veic kartēšanu (t.i.e. jaukšana) attiecas uz masīva indeksiem, nevis uz vērtībām, jo ​​vērtībās var būt dublikāti. Šī diagramma ilustrē jaukšanas tabulu cilvēku vārdiem un viņu tālruņu numuriem. Masīva šūnas (slotus) sauc par spaiņiem.

Ievērojiet, ka daži kausi ir tukši. Sajaukšanas tabulai nav obligāti jābūt vērtībām visās tās grupās. Grupu vērtībām nav obligāti jābūt augošā secībā. Tomēr indeksi, ar kuriem tie ir saistīti, ir augošā secībā. Bultiņas norāda kartēšanu. Ievērojiet, ka atslēgas nav masīvā. Viņiem nav jābūt nekādā struktūrā. Jaucējfunkcija aizņem jebkuru taustiņu un izjauc masīva indeksu. Ja segmentā, kas saistīts ar indeksa jaukšanu, nav vērtības, tajā var tikt ievietota jauna vērtība. Loģiskā saikne ir starp atslēgu un indeksu, nevis starp atslēgu un vērtību, kas saistīta ar indeksu.

Masīva vērtības, tāpat kā šīs jaucējtabulas vērtības, vienmēr ir viena un tā paša veida dati. Jaukšanas tabula (segmenti) var savienot atslēgas ar dažādu datu tipu vērtībām. Šajā gadījumā masīva vērtības ir visas norādes, kas norāda uz dažādiem vērtību tipiem.

Hash tabula ir masīvs ar hash funkciju. Funkcija paņem atslēgu un jauc atbilstošu indeksu, un tādējādi savieno atslēgas ar masīvā esošajām vērtībām. Taustiņiem nav jābūt daļai no jaukšanas tabulas.

Kāpēc masīvs, nevis sasaistītais saraksts Hash tabulai

Jaukšanas tabulas masīvu var aizstāt ar saistītu saraksta datu struktūru, taču radīsies problēma. Pirmais saistītā saraksta elements dabiski atrodas indeksā 0; otrais elements dabiski atrodas indeksā 1; trešais dabiski atrodas indeksā, 2; un tā tālāk. Saistītā saraksta problēma ir tā, ka, lai iegūtu vērtību, saraksts ir jāpārskata, un tas prasa laiku. Piekļuve masīva vērtībai notiek pēc nejaušas piekļuves. Kad indekss ir zināms, vērtību iegūst bez iterācijas; šī piekļuve ir ātrāka.

Sadursme

Jaucējfunkcija ņem taustiņu un jauc attiecīgo indeksu, lai nolasītu saistīto vērtību vai ievietotu jaunu vērtību. Ja mērķis ir nolasīt vērtību, līdz šim nav problēmu (nav problēmu). Tomēr, ja mērķis ir vērtības ievietošana, jauktajam indeksam jau var būt saistīta vērtība, un tā ir sadursme; jauno vērtību nevar likt tur, kur jau ir vērtība. Ir veidi, kā atrisināt sadursmi - skatīt zemāk.

Kāpēc notiek sadursme

Iepriekš sniegtajā veikalu veikalā klienta vārdi ir atslēgas, un dzērienu nosaukumi ir vērtības. Ievērojiet, ka klientu ir pārāk daudz, bet masīva izmērs ir ierobežots un nevar uzņemt visus klientus. Tātad masīvā tiek glabāti tikai pastāvīgo klientu dzērieni. Sadursme notiktu, kad neregulārs klients kļūtu par regulāru. Veikala klienti veido lielu komplektu, savukārt masīvu pircēju skaits klientiem ir ierobežots.

Izmantojot jaukšanas tabulas, tiek reģistrētas ļoti iespējamās atslēgu vērtības. Kad atslēga, kas nebija iespējama, kļūst iespējama, iespējams, notiks sadursme. Faktiski sadursme vienmēr notiek ar jaucējgaldiem.

Sadursmju risināšanas pamati

Divas pieejas sadursmju risināšanai sauc par atsevišķu ķēdi un atvērtu adresēšanu. Teorētiski atslēgām nevajadzētu būt datu struktūrā vai tām nevajadzētu būt daļai no jaukšanas tabulas. Tomēr abas pieejas prasa, lai atslēgas kolonna būtu pirms jaukšanas tabulas un kļūtu par daļu no kopējās struktūras. Tā vietā, lai atslēgas atrastos slejā atslēgas, norādes uz taustiņiem var būt atslēgas slejā.

Praktiskā jaukšanas tabula satur atslēgu kolonnu, taču šī atslēgu kolonna oficiāli nav jaukšanas tabulas sastāvdaļa.

Jebkurai pieejai izšķirtspējai var būt tukši segmenti, ne vienmēr masīva beigās.

Atsevišķa ķēde

Atsevišķā ķēdē, kad notiek sadursme, jaunā vērtība tiek pievienota pa labi (nevis virs vai zem) no sadursmes vērtības. Tātad divām vai trim vērtībām galu galā ir viens un tas pats indekss. Retāk nekā trim vajadzētu būt vienādam indeksam.

Vai tiešām vairākām vērtībām var būt viens un tas pats indekss masīvā? - Nē. Tāpēc daudzos gadījumos pirmā indeksa vērtība ir rādītājs saistītā saraksta datu struktūrai, kurā ir vienas, divu vai trīs sadursmes vērtības. Šī diagramma ir jaukšanas tabulas piemērs atsevišķai klientu un viņu tālruņu numuru ķēdei:

Tukšie kausi ir apzīmēti ar burtu x. Pārējām laika nišām ir norādes uz saistītajiem sarakstiem. Katram saistītā saraksta elementam ir divi datu lauki: viens klienta vārdam un otrs tālruņa numuram. Konflikts rodas atslēgām: Pīters Džonss un Suzans Lī. Atbilstošās vērtības sastāv no diviem saistītā saraksta elementiem.

Konfliktējošām atslēgām vērtības ievietošanas kritērijs ir tas pats kritērijs, ko izmanto vērtības atrašanai (un lasīšanai).

Atveriet adresēšanu

Izmantojot atvērtu adresēšanu, visas vērtības tiek saglabātas grupas masīvā. Ja rodas konflikts, jaunā vērtība tiek ievietota tukšā segmentā, kas atbilst konflikta vērtībai, ievērojot kādu no kritērijiem. Kritērijs, ko izmanto, lai ievietotu vērtību konfliktā, ir tas pats kritērijs, ko izmanto vērtības atrašanai (meklēšanai un lasīšanai).

Šī diagramma ilustrē konfliktu risināšanu ar atklātu adresēšanu:

Jaucējfunkcija paņem atslēgu, Pīters Džonss, sajauc indeksu 152 un saglabā savu tālruņa numuru saistītajā spainī. Pēc kāda laika hash funkcija jauc to pašu indeksu, 152 no atslēgas Suzan Lee, saduroties ar Peter Jones indeksu. Lai to atrisinātu, Suzana Lī vērtība tiek glabāta nākamā indeksa 153 spainī, kas bija tukšs. Hash funkcija jauc atslēgas Robina Huda indeksu 153, taču šis indekss jau ir izmantots, lai atrisinātu iepriekšējās atslēgas konfliktu. Tātad Robina Huda vērtība tiek ievietota nākamajā tukšajā spainī, kas ir 154. indeksa vērtība.

Konfliktu risināšanas metodes atsevišķai ķēdei un atklātai adresēšanai

Atsevišķai ķēdei ir konfliktu risināšanas metodes, un atklātajai adresēšanai ir arī savas konfliktu risināšanas metodes.

Metodes atsevišķu ķēdes konfliktu risināšanai

Atsevišķu ķēdes jaukšanas tabulu metodes ir īsi paskaidrotas tagad:

Atsevišķa ķēde ar saistītajiem sarakstiem

Šī metode ir tāda, kā paskaidrots iepriekš. Tomēr katram saistītā saraksta elementam nav obligāti jābūt atslēgas laukam (piemēram,.g. klienta vārda lauks iepriekš).

Atsevišķa ķēde ar saraksta galvas šūnām

Šajā metodē pirmais saistītā saraksta elements tiek glabāts masīva spainī. Tas ir iespējams, ja masīva datu tips ir saistītā saraksta elements.

Atsevišķa ķēde ar citām konstrukcijām

Saistītā saraksta vietā var izmantot jebkuru citu datu struktūru, piemēram, Pašbalansējošo bināro meklēšanas koku, kas atbalsta nepieciešamās darbības - skatiet vēlāk.

Metodes atklātu adresācijas konfliktu risināšanai

Metodi konfliktu risināšanai atklātā adresēšanā sauc par zondes secību. Tagad ir īsi izskaidrotas trīs labi zināmas zondes sekvences:

Lineārā zondēšana

Izmantojot lineāru zondēšanu, konflikta laikā tiek meklēts tuvākais tukšais spainis zem konflikta spaiņa. Arī ar lineāru zondēšanu gan atslēga, gan tās vērtība tiek saglabāta vienā un tajā pašā spainī.

Kvadrātiskā zondēšana

Pieņemsim, ka konflikts notiek indeksā H. Nākamais tukšais slots (spainis) indeksā H + 12 tiek izmantots; ja tas jau ir aizņemts, tad nākamais tukšais pie H + 22 tiek izmantots, ja tas jau ir aizņemts, tad nākamais tukšais pie H + 32 tiek izmantots utt. Tam ir varianti.

Dubultā jaukšana

Ar dubultu jaukšanu ir divas hash funkcijas. Pirmais aprēķina (jauc) indeksu. Ja rodas konflikts, otrais izmanto to pašu atslēgu, lai noteiktu, cik tālu uz leju ir jāievieto vērtība. Šajā ziņā ir vairāk - skatiet vēlāk.

Perfekta hash funkcija

Ideāla hash funkcija ir hash funkcija, kuras rezultātā nevar notikt sadursme. Tas var notikt, ja atslēgu kopa ir salīdzinoši maza, un katrs taustiņš kartē konkrētu veselu skaitli jaukšanas tabulā.

ASCII rakstzīmju kopā lielos burtus var kartēt ar atbilstošajiem mazajiem burtiem, izmantojot jaucējfunkciju. Burti datora atmiņā tiek attēloti kā cipari. ASCII rakstzīmju kopā A ir 65, B ir 66, C ir 67 utt. un a ir 97, b ir 98, c ir 99 utt. Lai kartētu no A līdz a, pievienojiet 32 ​​līdz 65; lai kartētu no B līdz b, pievienojiet 32 ​​līdz 66; lai kartētu no C līdz c, pievienojiet 32 ​​līdz 67; un tā tālāk. Šeit lielie burti ir atslēgas, un mazie burti ir vērtības. Jaukšanas tabula tam var būt masīvs, kura vērtības ir saistītie indeksi. Atcerieties, ka masīva kausi var būt tukši. Tātad masīva spaiņi no 64 līdz 0 var būt tukši. Hash funkcija vienkārši pievieno 32 lielajiem burtu koda numuriem, lai iegūtu indeksu, līdz ar to arī mazo burtu. Šāda funkcija ir ideāla hash funkcija.

Jaukšana no veselā līdz veselā indeksa

Veselā skaitļa jaukšanai ir dažādas metodes. Vienu no tiem sauc par Modulo dalīšanas metodi (funkciju).

Modulo nodaļas jaukšanas funkcija

Funkcija datoru programmatūrā nav matemātiska funkcija. Skaitļošanā (programmatūrā) funkcija sastāv no paziņojumu kopas, pirms kurām ir argumenti. Funkcijai Modulo Division taustiņi ir veseli skaitļi, un tie tiek kartēti ar kopu masīva indeksiem. Atslēgu kopa ir liela, tāpēc tiktu kartēti tikai tie taustiņi, kuri, visticamāk, rodas aktivitātē. Tātad sadursmes rodas, ja ir jāaplāno maz ticams taustiņi.

Paziņojumā,

20/6 = 3R2

20 ir dividende, 6 ir dalītājs, un 3 atlikums 2 ir koeficients. Atlikušo 2 sauc arī par modulo. Piezīme: ir iespējams, ka modulis ir 0.

Lai veiktu šo jaukšanu, galda lielums parasti ir 2, piemēram, jauda.g. 64 = 26 vai 256 = 28, utt.  Šīs jaucējfunkcijas dalītājs ir galvenais skaitlis, kas ir tuvu masīva izmēram. Šī funkcija sadala atslēgu ar dalītāju un atgriež moduli. Modulis ir spaiņu masīva indekss. Saistītā vērtība segmentā ir jūsu izvēlēta vērtība (atslēgas vērtība).

Maināma garuma taustiņu jaukšana

Šeit atslēgu komplekta taustiņi ir dažāda garuma teksti. Dažādus veselus skaitļus var saglabāt atmiņā, izmantojot vienādu baitu skaitu (angļu rakstzīmes lielums ir baits). Ja dažādiem taustiņiem ir dažādi baitu lielumi, tiek uzskatīts, ka tie ir mainīga garuma. Viena no mainīgā garuma jaukšanas metodēm tiek saukta par Radix Conversion Hashing.

Radix reklāmguvumu jaukšana

Virknē katra rakstzīme datorā ir skaitlis. Šajā metodē,

Hash kods (indekss) = x0ak − 1+x1ak − 2+… + Xk − 2a1+xk − 1a0

Kur (x0, x1,…, xk − 1) ir ievades virknes rakstzīmes un a ir radix, e.g. 29 (skatīt vēlāk). k ir virknes rakstzīmju skaits. Šajā ziņā ir vairāk - skatiet vēlāk.

Atslēgas un vērtības

Atslēgu / vērtību pārī vērtība var nebūt skaitlis vai teksts. Tas var būt arī ieraksts. Ieraksts ir saraksts, kas rakstīts horizontāli. Atslēgu / vērtību pārī katrs taustiņš faktiski var atsaukties uz kādu citu tekstu vai numuru vai ierakstu.

Asociatīvais masīvs

Saraksts ir datu struktūra, kurā saraksta vienumi ir saistīti, un tajā ir darbību kopums, kas darbojas sarakstā. Katrs saraksta vienums var sastāvēt no vienumu pāra. Vispārējo jaukšanas tabulu ar tās atslēgām var uzskatīt par datu struktūru, taču tā drīzāk ir sistēma, nevis datu struktūra. Atslēgas un tām atbilstošās vērtības nav ļoti atkarīgas viena no otras. Viņi nav ļoti saistīti viens ar otru.

No otras puses, asociatīvs masīvs ir līdzīga lieta, bet atslēgas un to vērtības ir ļoti atkarīgas viena no otras; tie ir ļoti saistīti viens ar otru. Piemēram, jums var būt asociatīvs augļu un to krāsu klāsts. Katram auglim dabiski ir sava krāsa. Augļa nosaukums ir atslēga; krāsa ir vērtība. Ievietošanas laikā katrs taustiņš tiek ievietots ar tā vērtību. Dzēšot, katrs taustiņš tiek izdzēsts ar tā vērtību.

Asociatīvais masīvs ir hash tabulas datu struktūra, kas sastāv no atslēgu / vērtību pāriem, kur atslēgām nav dublikātu. Vērtībām var būt dublikāti. Šajā situācijā taustiņi ir struktūras sastāvdaļa. Tas ir, atslēgas ir jāuzglabā, turpretī, izmantojot vispārējo ātrgaitas tabulu, atslēgas nav jāuzglabā. Dublēto vērtību problēmu dabiski atrisina spaiņu masīva indeksi. Nejauciet starp dublētām vērtībām un sadursmi indeksā.

Tā kā asociatīvais masīvs ir datu struktūra, tam ir vismaz šādas darbības:

Asociatīvās masīva operācijas

ievietot vai pievienot

Tas kolekcijā ievieto jaunu atslēgu / vērtību pāri, atslēgu piesaistot tās vērtībai.

norīkot citādi

Šī darbība aizstāj konkrētas atslēgas vērtību ar jaunu vērtību.

dzēst vai noņemt

Tādējādi tiek noņemta atslēga un tai atbilstošā vērtība.

uzmeklēšana

Šī darbība meklē konkrētas atslēgas vērtību un atgriež vērtību (to nenoņemot).

Secinājums

Hash tabulas datu struktūra sastāv no masīva un funkcijas. Funkciju sauc par hash funkciju. Funkcija kartē atslēgas masīva vērtībām, izmantojot masīva indeksus. Atslēgām nav obligāti jābūt datu struktūras daļai. Atslēgu kopa parasti ir lielāka par saglabātajām vērtībām. Kad notiek sadursme, to atrisina vai nu ar atsevišķu ķēdes pieeju, vai ar atvērto adresēšanas pieeju. Asociatīvs masīvs ir īpašs hash tabulas datu struktūras gadījums.

Kā instalēt un spēlēt Doom uz Linux
Ievads liktenī Doom sērija radās 90. gados pēc sākotnējā Doom izlaišanas. Tas bija tūlītējs hīts, un kopš tā laika spēļu sērija ir saņēmusi daudzas ba...
Vulkan Linux lietotājiem
Ar katru jauno grafisko karšu paaudzi mēs redzam, kā spēļu izstrādātāji pārspēj grafiskās uzticamības robežas un tuvojas fotoreālismam. Neskatoties uz...
OpenTTD vs Simutrans
Transporta simulācijas izveide var būt jautra, relaksējoša un ārkārtīgi vilinoša. Tāpēc jums jāpārliecinās, ka izmēģināt pēc iespējas vairāk spēļu, la...