#include #include #include #include #define ZNAKU 256 #define MAX_SLOVO 80 #define MAX_TEXT 500 struct slovo { char hodnota[MAX_SLOVO]; int delka; int posledni_vyskyt; struct slovo * predchozi; struct slovo * nasledujici; }; struct vrchol { char znak; struct vrchol * zpet; struct vrchol * dopredu[ZNAKU]; struct vrchol * rodic; struct slovo * koncici; }; int slov, vrcholu; //spojový seznam slov struct slovo * slova_zacatek, * slova_konec; struct vrchol * koren; //ukazatel na kořen trie //informace o zatím nejlepším nalezeném výskytu int nej_zacatek = -1, nej_delka = INT_MAX; char text[MAX_TEXT]; //prohledávaný text //ze slov v seznamu slova postaví trii s kořenem koren void postav_trii(void) { int i; struct slovo * s; koren = calloc(1, sizeof(struct vrchol)); koren->rodic = koren; koren->zpet = koren; vrcholu = 1; for (s = slova_zacatek; s; s = s->nasledujici) { struct vrchol * v = koren; for (i = 0; i < s->delka; i++) { char znak = s->hodnota[i]; //pokud následující vrchol //v trii zatím není, vytvoříme ho if (!v->dopredu[znak]) { v->dopredu[znak] = calloc(1, sizeof(struct vrchol)); v->dopredu[znak]->znak = znak; v->dopredu[znak]->rodic = v; //pokud tady končilo nějaké slovo, //je podřetězcem přidávaného v->koncici = NULL; vrcholu++; } v = v->dopredu[znak]; } v->koncici = s; } //všechny zatím neexistující dopředné hrany //z kořene namíříme zpátky do kořene for (i = 0; i < ZNAKU; i++) if (!koren->dopredu[i]) koren->dopredu[i] = koren; } //zpracuje jeden znak, vrátí nový aktuální vrchol z trie struct vrchol * krok(struct vrchol * v, char znak) { while (!v->dopredu[znak]) v = v->zpet; return v->dopredu[znak]; } //určí zpětné hrany v trii void spocitej_zpetne(void) { struct vrchol ** fronta = malloc((vrcholu - 1) * sizeof(struct vrchol *)); int zacatek = 0, konec = 0; int i; //přidá do fronty syny kořene for (i = 0; i < ZNAKU; i++) if (koren->dopredu[i] != koren) fronta[konec++] = koren->dopredu[i]; while (zacatek < konec) { struct vrchol * aktualni = fronta[zacatek]; if (aktualni->rodic == koren) aktualni->zpet = koren; // vrchol je syn kořene, // zpětná hrana musí vést do kořene else aktualni->zpet = krok(aktualni->rodic->zpet, aktualni->znak); //pokud tam končilo slovo, je podřetězcem aktuálního aktualni->zpet->koncici = NULL; //přidáme syny aktuálního vrcholu do fronty for (i = 0; i < ZNAKU; i++) if (aktualni->dopredu[i]) fronta[konec++] = aktualni->dopredu[i]; zacatek++; } } //zvýší hodnotu posledního výskytu slova void zvys(struct slovo * slovo, int posledni) { if (slovo->nasledujici) { if (slovo->predchozi) slovo->predchozi->nasledujici = slovo->nasledujici; else slova_zacatek = slovo->nasledujici; slovo->nasledujici->predchozi = slovo->predchozi; slovo->predchozi = slova_konec; slovo->nasledujici = NULL; slova_konec->nasledujici = slovo; slova_konec = slovo; } slovo->posledni_vyskyt = posledni - slovo->delka + 1; if (slova_zacatek->posledni_vyskyt >= 0) { //všechna slova se už v textu vyskytla int delka = posledni - slova_zacatek->posledni_vyskyt + 1; if (delka < nej_delka) { nej_delka = delka; nej_zacatek = slova_zacatek->posledni_vyskyt; } } } int main(void) { int i; struct vrchol * v; struct slovo * prvni; scanf("%d", &slov); getchar(); //načtení prvního slova prvni = malloc(sizeof(struct slovo)); prvni->predchozi = NULL; prvni->nasledujici = NULL; slova_zacatek = prvni; slova_konec = prvni; gets(prvni->hodnota); prvni->delka = strlen(prvni->hodnota); prvni->posledni_vyskyt = -1; for (i = 1; i < slov; i++) { struct slovo * aktualni = malloc(sizeof(struct slovo)); aktualni->predchozi = slova_konec; aktualni->nasledujici = NULL; slova_konec->nasledujici = aktualni; slova_konec = aktualni; gets(aktualni->hodnota); aktualni->delka = strlen(aktualni->hodnota); aktualni->posledni_vyskyt = -1; } postav_trii(); spocitej_zpetne(); gets(text); v = koren; for (i = 0; text[i]; i++) { v = krok(v, text[i]); if (v->koncici) zvys(v->koncici, i); } if (nej_zacatek == -1) puts("Některé slovo nebylo nalezeno."); else { char * reseni = malloc((nej_delka+1) * sizeof(char)); strncpy(reseni, &text[nej_zacatek], nej_delka); reseni[nej_delka] = 0; puts(reseni); } return 0; }