Semestrální práce z KIV/PC Řešení kolizí frekvencí sítě vysílačů
Kolja Matuševský (A14B0310P)
[email protected]
10. ledna 2016
Obsah 1 Zadání
2
2 Analýza úlohy 2.1 Vytvoření grafu . . . . . . . . . . . . . . . . . . . . . . . . . . 2.2 Obarvovací funkce . . . . . . . . . . . . . . . . . . . . . . . . 2.3 Vyhledávací funkce . . . . . . . . . . . . . . . . . . . . . . . .
3 3 4 4
3 Popis implementace 3.1 Soubor main . . . 3.2 Soubor graph . . . 3.3 Soubor linked list . 3.4 Soubor transmitter 3.5 Soubor util . . . .
5 5 6 7 7 7
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
4 Uživatelská příručka
8
5 Závěr
9
1
Kapitola 1
Zadání Naprogramujte v ANSI C přenositelnou konzolovou aplikaci, která jako vstup načte z parametru příkazové řádky název textového souboru obsahující informaci o pozici vysílačů na mapě a na jeho základě přidělí každému vysílači frekvenci tak, aby jeho signál nekolidoval s vysílači v blízkém okolí. Program se bude spouštět příkazem freq.exe <soubor-s-vysílači>. Symbol <soubor-s-vysílači> zastupuje jméno textového souboru, který obsahuje informaci o rozmístění vysílačů na mapě a o dostupných vysílacích frekvencích, které jim je možné přidělit. Váš program tedy může být během testování spuštěn například takto: freq.exe vysilace-25.txt Výsledkem práce programu bude výpis do konzole se seznamem přidělených frekvencí každému vysílači ze vstupního souboru. V případě chyby nebo neřešitelné situaci skončí program výpisem příslušné chybové hlášky. Pokud nebude na příkazové řádce uveden právě jeden argument, vypište chybové hlášení a stručný návod k použití programu v angličtině podle běžných zvyklostí (viz např. ukázková semestrální práce na webu předmětu Programování v jazyce C). Vstupem programu je pouze argument na příkazové řádce – interakce s uživatelem pomocí klávesnice či myši v průběhu práce programu se neočekává.
2
Kapitola 2
Analýza úlohy Abychom tento problém mohli vyřešit, je dobré rozdělit si ho na menší celky. Tyto celky jsou vytvoření grafu, vytvoření obarvovací funkce a zvolení správného vyhledávacího algoritmu. Tyto jednotlivé problémy jsou rozebrané v kapitolách 2.1 - 2.3.
sekcích
2.1
Vytvoření grafu
Každý graf má seznam vrcholů a každý vrchol má seznam jeho sousedů. Pokud chceme vytvářet graf, musíme se nejdříve rozhodnout, jakou datovou strukturu zvolíme pro jeho implementaci. Mohli bychom použít pole, do kterého bychom ukládali vrcholy daného grafu a poté vytvořit pole u každého vrcholu daného grafu, do kterého bychom ukládali jeho sousedy. Avšak nevýhodou pole je, že musíme vědět přesný počet prvků, terý do něj budeme chtít vkládat. To bychom mohli vyřešit dynamickým polem, ale dle mého názoru by práce s ním byla příliš těžkopádná. Rozhodl jsem se proto spojový seznam. Jeho výhodou je, že nemusíme vědět, kolik prvků do něj budeme vkládat a rychlé vkládání prvků. Nevýhodou by mohl být fakt, že vybírání prvků ze středu seznamu je celkem náročné, ale vzhledem k tomu že potřebujeme pracovat pouze s prvky na začátku a na konci, tak to zde není problém.
3
2.2
Obarvovací funkce
Zvolil jsem obarvovací funkci, která vybere nejmenší možnou barvu, kterou nemá žádný z jeho sousedů. Výhoda této funkce je, že je velmi jednoduchá na implementaci. Její nevýhoda je, že nemusí vždy dát to nejlepší řešení. Její efektivita je určena vyhledávací funkci, proto když zvolíme správnou vyhledávací funkci tak dostaneme i správné řešení.
2.3
Vyhledávací funkce
Celý algoritmus závisí na pořadí výběru vrcholů. Vrcholy se mohou vybírat náhodně (First Fit), nebo podle stupně vrcholu, kdy se nejdříve vyberou vrcholy s nejvyšším stupněm (Largest Degree Ordering). Já jsem však jako vyhledávací funkci zvolil BFS (vyhledávání do šířky). Jeho výhodou je, dle mého názoru, jeho jednoduchá implementace a pro tento typ úlohy by mohla být jeho efektivita více než dostačující. Pro složitější grafy by však nemusel dávat nejlepší výsledky (jako třeba pro Fruchtůf graf).
4
Kapitola 3
Popis implementace Projekt se skládá z několika souborů: • main - obsahuje vstup progamu, stará se o načtení dat, vytvoření grafu, přiřazení frekvencí k vysílačům a vypisuje výstup na obrazovku • graph - obsahuje graf • linked list - obsahuje spojový seznam, který, krom jiného, funguje jako fronta i jako zásobník • transmitter - obsahuje vysílač, jeho index, x-ovou a y-ovou souřadnici • util - obsahuje makro pro bezpečné alokování paměti, které ukončí program, pokud není k dispozici dostatek operační paměti V kapitolách 3.1 - 3.5 jsou postupně rozebrány jednotlivé soubory.
3.1
Soubor main
Zdrojový soubor main je hlavní vstupní bod programu. O načtení dat se stará funkce int load data(char *file name, linked list **frequency list, unsigned int *p radius, linked list **transmitter list), kde file name je název souboru, ze kterého data načítáme, frequency list je seznam frekvencí, do kterého načtené frekvence budeme ukládat, p radius je promněnná, do které uložíme radius a transmitter list je seznam vysílačů, do kterého budeme ukládat jednotlivé vysílače.
5
Funkce int colides(transmitter* a, transmitter* b, int radius) kontroluje, jestli vysílače a a b se protínají. Parametr raduis je okruh vzdálenosti vysílání jejich signálu. Funkce int assign frequency(graph *p graph, linked list *frequency list) připisuje frekvence k jednotlivým vysílačům podle jejich barvy, kdy p graph je graf, který obsahuje zadané vysílače a frequency list je seznam frekvencí, ze kterého budeme zadané frekvence přiřazovat. Funkce void print(graph *p graph) vypíše daný graf p graph na obrazovku.
3.2
Soubor graph
Tento zdrojový soubor obsahuje datovou strukturu uzlu a hrany. Funkce node add node (graph *p graph) přidá uzel do daného grafu p graph a funkce void add edge (node *a, node *b) přidá neorientovanou hranu mezi uzly a a b. Funkce void colour node(node *p node) vybarví daný uzel nejmenší možnou barvou, kterou nemá žádný z jeho sousedů. To funguje tak, že se nejprve nastaví promněnná colour na 1, jako nejmenší možná barva. Pak se projede seznam sousedů daného uzlu a do seznamu barev sousedů neighbour colours se uloží barvy jeho sousedů. Pak se daný seznam postupně testuje jesti je promněnná colour v tomto seznamu obsažena. Pokud ano, zvýší se colour o 1 a znovu se otestuje. Takto to pokračuje, dokud barva není v seznamu obsažena. Poté se tato barva nastaví danému uzlu. Funkce void bfs(node *from) je klasické vyhledávání do šířky, kdy from je počáteční vrchol, od kterého se vyhledává. Funkce void colour graph(graph *graph) vybarví celý graf tak, že provede funkci bfs(node *from) pro každý vrchol daného grafu. Pořadí vrcholů je dáno seznamem vrcholů grafu, kdy se postupně vybírají vrcholy od prvního do posledního.
6
3.3
Soubor linked list
Rozhodl jsem se implementovat upravený spojový seznam, který funguje také jako fronta. Pokud budeme chtít použít tento seznam jako frontu, budeme přidávat prvky na konec pomocí funkce void add last(linked list *p linked list, void *data), kdy p linked list je seznam, do kterého budeme prvek vkládat a data jsou data, která tam chceme vložit. Odebírat prvky ze začátku budeme pomocí funkce void *remove first(linked list *p linked list), kdy p linked list je seznam, ze kterého budeme prvek vybírat. Seznam má dále také funkci unsigned int get size(linked list *p linked list) pro zjištění jeho počtu prvků a funkci int contains(linked list *p linked list), která zjistí, jestli se daný prvek v daném seznamu vskytuje kdy p linked list je seznam, pro který tyto informace zjišťujeme.
3.4
Soubor transmitter
Tento hlavičkový soubor obsahuje vysílač, jeho index, x-ovou a y-ovou souřadnici.
3.5
Soubor util
Tento zdrojový soubor obsahuje makro pro bezpečné alokování paměti, které ukončí program, pokud není k dispozici dostatek operační paměti chybovou hláškou ERR#2: Out of memory!
7
Kapitola 4
Uživatelská příručka Program lze sestavit z příkazové řádky příkazem make pro Linux, nebo příkazem nmake -f Makefile.win pro Windows. Pro Windows je třeba mít nainstalované Visual Studio. Program lze spustit pouze s jedním parametrem na příkazové řádce, což je soubor (nebo cesta k souboru) s informacemi o vysílačích a frekvencích, které má program přidělovat. Program tento soubor zpracuje a vypíše na obrazovku správné řešení a vrátí kód 0. V případě chyby vrátí jeden z chybových hlášek, viz Tabulka 4.1
Chybové hlášení
Popis Na příkazové řádce nebyl předán parametr, specifikující vstupní soubor s informacemi o vysílačích. Není k dispozici dostatek operační paměti. Řešení pro daný počet vysílacích frekvencí nebylo nalezeno. Chyba při otvírání souboru. Chyba při čtení souboru.
ERR#1: Missing argument!
ERR#2: Out of memory! ERR#3: Non-existent solution! ERR#4: Error while opening file! ERR#5: Error while reading file!
Tabulka 4.1: Seznam chybových hlášek 8
Kapitola 5
Závěr Program zvládne správně přiřadit frekvence pro dané rozmístění vysílačů a pokud nenalezne řešení, tak správně vypíše chybovou hlášku ERR#3: Non-existent solution!. Můj program tedy funguje podle zadání. Pro vzorový soubor s 25 vysílači sice program výsledné řešení nenalezne, ale to může být způsobeno jiným pořadím výběru prvků při obarvování grafu, než jaký má vzorový program. Pro vzorový soubor s 1000 vysílači však funguje program správně. Proto dle mého názoru ale funguje program optimálně, i když nevyhledává nejlepší řešení. To by se v budoucnu mohlo vyřešit výběrem jiné vyhledávácí funkce.
9