2. Naloga: Citati

2. Naloga: Citati

Avtor: Mateja Smerdel

OPIS PROBLEMA IN IDEJA REŠITVE

Navodilo naloge

Recimo, da bi radi citirali razne strani iz neke knjige; to naredimo tako, da naštejemo številke teh strani v strogo naraščajočem vrstnem redu, na primer 2, 5, 6, 8, 11, 28, 29, 30, 31, 67. Če se v tem seznamu kdaj pojavita dve ali več zaporednih strani, ga lahko zapišemo krajše: obdržimo le prvo in zadnjo številko strani iz take skupine večzaporednih številk, med njiju pa zapišimo vezaj: 2, 5–6, 8, 11, 28–31, 67. Napiši program, ki prebere več seznamov številk strani z vhodne datoteke (pri čemer bo vsaka številka v svoji vrstici), na izhodno datoteko pa izpiše te sezname v zgoraj določeni obliki (v eni vrstici, z vejicami, presledki in vezaji). Seznami števil na vhodni datoteki so med seboj ločeni z vrstico, v kateri je le niz "#NOV SEZNAM#". V vhodnem seznamu številke strani niso nujno v naraščajočem vrstnem redu, vse pa so cela števila, večja od 0. Predpostaviš lahko, da je v vhodnem seznamu vsaj ena številka in da se nobena številka v njem ne pojavi več kot enkrat.

Ideja rešitve

Z vhodne datoteke preberemo sezname v katerih so shranjene številke strani in nato te sezname uredimo po velikosti ter poskrbimo za ustrezen izpis na izhodno datoteko. In sicer če se pojavita v seznamu dve ali več zaporednih strani na izhodno datoteko ne napišemo vseh strani, ampak le prvo in zadnjo ter med njiju dodamo vezaj. Ker so številke strani na datoteki vsaka v svoji vrstici, datoteko preberemo po vrsticah. Najprej se sprehodimo čez celo datoteko in v primeru da je element v vrstici različen od niza #NOV SEZNAM#, vemo da se v vrstici nahaja cifra zato povečamo števec, katerega na začetku nastavimo na 0 in bomo v njem hranili število števk v datoteki. Ko pridemo do konca datoteke tako vemo koliko cifer je v seznamu, ustvarimo novo tabelo številskega tipa, v katero bomo te cifre shranjevali. Na podoben način kot prej se še enkrat sprehodimo čez datoteko in v primeru da je v vrstici cifra le-to shranimo v tabelo.

Na koncu tabelo le še uredimo po velikosti, za to bomo uporabili funkcijo za urejanje tabele iz vaj – HitroUredi in pa poskrbimo za ustrezen izpis (postavljanje vezajev, vejic) ter zapis na datoteko.

RAZLAGA ALOGRITMA

Na začetku definiramo novo funkcijo Citati , katera sprejme kot vhodna elementa dva parametra, in sicer string vhod ter string izhod . Prvi parameter je vhodna datoteka, to je datoteka iz katere bomo podatke pobirali. Drugi parameter pa je izhodna datoteka, to je datoteka na katero bomo na koncu ustrezno zapisali.

Najprej z ukazom File.OpenText odpremo ustrezno datoteko v načinu za branje. Definiramo števec s katerim bomo šteli koliko cifer imamo v datoteki in ga nastavimo na 0. Sedaj moramo ugotoviti koliko vrstic ima datoteka, da bomo kasneje lahko ustvarili tabelo v katero bomo podatke shranjevali. Ker pa nas zanimajo samo cifre, ki so v datoteki bomo pri štetju tiste vrstice kjer se nahaja niz #NOV SEZNAM# izpustili. Preberemo vrstico iz datoteke in gremo z while zanko čez datoteko in preverjamo ali se v tekoči vrstici nahaja niz #NOV SEZNAM# , če tega niza ni potem vemo da je v vrstici shranjeno število zato števec povečujemo. Znotraj while zanke pa v vsakem koraku še preberemo novo vrstico iz datoteke. Na koncu zanke poskrbimo datoteko ki smo jo uporabljali ustrezno zapremo. V spremenljivki stVrstic imamo tako na koncu shranjeno število, koliko cifer je bilo v datoteki in ki ga bomo v nadaljevanju potrebovali.

 public static void Citati(string vhod,string izhod)
        {
            StreamReader vhodnaDat = File.OpenText(vhod); //odpremo datoteko za branje
            int stVrstic = 0;//števec s katerim bomo prešteli št.vrsti nastavimo na 0

            string vrstica = vhodnaDat.ReadLine();//definiramo spremenljivko in preberemo vrstico iz datoteke
            while (vrstica!=null)
            {
                if(vrstica!="#NOV SEZNAM#")
                    stVrstic++; //če je v vrstici cifra števec povečamo

                //Console.WriteLine(stVrstic);
                vrstica = vhodnaDat.ReadLine();//preberemo vrstico
            }
            vhodnaDat.Close();//datoteko na koncu zapremo 

V nadaljevanju deklariramo novo tabelo številskega tipa (int ), ki je takšne velikosti, kolikor smo v prejšnjem koraku ugotovili, da imamo številk v datoteki. Zopet odpremo datoteko v načinu za branje in preberemo vrstico iz datoteke. Podobno kot prej se z while zanko sprehodimo čez celotno datoteko in vrstico za vrstico primerjamo z nizom #NOV SEZNAM# , v primeru da se tekoča vrstica razlikuje od tega niza, vrstico zapišemo v tabelo ter preberemo novo vrstico iz datoteke. Po koncu izvajanja while zanke imamo tako tabelo napolnjeno s številkami strani iz vhodne datoteke. Na koncu le še datoteko zapremo.

 int[] tabela = new int[stVrstic];//ustvarimo tabelo, ki je takšne velikosti kot imamo
            StreamReader vhodnaDat1 = File.OpenText(vhod); //števk v datoteki
            string vrstica1=vhodnaDat1.ReadLine();
            int i = 0;
            while (vrstica1!=null)
            {
                if (vrstica1 != "#NOV SEZNAM#")
                {
                   tabela[i] = int.Parse(vrstica1);//napolnimo tabelo
                   //Console.WriteLine(tabela[i]);
                   //izhodnaDat.WriteLine(tabela[i]);
                   i++;
                }
                vrstica1 = vhodnaDat1.ReadLine();
            }
            vhodnaDat.Close(); 

Sedaj imamo tabelo, v kateri imamo podatke številskega tipa. Te podatke je potrebno urediti po velikosti. Za urejanje tabele bomo uporabil funkcijo UrediHitro , katero smo ustvarili že v sklopu vaj tega predmeta. Funkcija uredi tabelo celih števil, kot vhodne parametre ji podamo tabelo, začetni indeks, ki je kar enak 0 ter končni indeks urejanja, ki je enak velikosti tabele.

 UrediHitro(tabela,0,tabela.Length-1);//na tabeli uporabimo funkcijo UrediHitro,ki bo uredila števila v tabeli 

V nadaljevanju poskrbimo še za izpis, katerega bomo zapisali na datoteko. Ustvarimo spremenljivko tipa string v kateri bomo shranjevali niz, ki ga želimo zapisati na datoteko. Potem pa se s for zanko sprehodimo čez tabelo in izpisu dodajamo ustrezne znake. V primeru da je niz za izpis še prazen, izpisu dodamo kar prvi znak iz tabele. V primeru, da sta v tabeli vsaj dve zaporedni številki enaki, potem izpisu dodamo vezaj in pa zadnjo cifro iz takega zaporedja. Če so v tabeli cifre, ki si ne sledijo ena za drugo, v izpisu cifre med seboj ločimo z vejico.

Na koncu odpremo datoteko v načinu za pisanje. Na datoteko zapišemo niz, katerega smo definirali zgoraj in datoteko zapremo.

 string izpis="";//definiramo spremenljivko v kateri bomo hranili besedilo za izpis

            for (int j = 0; j < stVrstic; j++)
            {
                if (izpis.Length==0)
                    izpis=izpis+tabela[0];//na začetku samo dodamo prvo števko iz tabele

                else if (tabela[j]-1 == tabela[j-1])
                {
                    if (j == stVrstic- 1)
                        izpis = izpis + "-" + tabela[j];//če smo na koncu tabele in sta na koncu vsaj dve
                                                    //zaporedni strani dodamo vezaj+zadnjo cifro iz tabele
                    while (tabela[j]-1 == tabela[j-1])//dokler sta zaporedni cifri enaki števec samo
                        j++;                            //povečujemo

                    izpis = izpis + "-" + tabela[j - 1];//v izpis dodamo vezaj+cifro, ki je zadnja zaporedna
                    j--;
                }
                else
                    izpis = izpis + ", " + tabela[j];//če si števila ne sledijo zaporedno dodamo v izpis
            }                                        //vejico in presledek ter števko iz tabele

            StreamWriter izhodnaDat = File.AppendText(izhod);//odpremo datoteko v načinu za pisanje
            izhodnaDat.WriteLine(izpis);//zapišemo besedilo na datoteko
            izhodnaDat.Close();//na koncu datoteko za pisanje zapremo
        } 

Koda funkcije UrediHitro, katero smo uporabili znotraj programa Citati.

 static void UrediHitro(int[] tabela, int zacetek, int konec)
        {

            if (zacetek >= konec) { } //če zacetek >= konec, ni kaj narediti

            else
            {
                int p = Preuredi(tabela, zacetek, konec); //drugače poiščemo pivotni indeks p

                if (zacetek < p) //v primeru da je zacetek < p rekurzivno kličemo:
                    UrediHitro(tabela, zacetek, p - 1);

                if (p < konec) //če pa je p < konec rekurzivno kličemo
                    UrediHitro(tabela, p + 1, konec);
            }
        }
        static int Preuredi(int[] tabela, int zacetek, int konec)
        {
            int x = tabela[zacetek]; // pivotna vrednost
            int i = zacetek;
            int j = konec;
            while (i < j)
            {
                while ((i < j) && (tabela[j] >= x))
                { // poiščemo prvi indeks z desne, kjer je tabela[j] < x
                    j--;
                }
                if (i != j)
                { // in ta element damo na levo
                    tabela[i] = tabela[j];
                    i++;
                }
                while ((i < j) && (tabela[i] <= x))
                {// poiščemo prvi indeks z leve, kjer je tabela[j] > x
                    i++;
                }
                if (i != j)
                { // in ta element damo na desno
                    tabela[j] = tabela[i];
                    j--;
                }
            }
            // na koncu bo pivotni indeks enak (trenutnemu levemu indeksu) i
            tabela[i] = x;
            return i;
        } 

TESTNI PRIMER

Posnetek testiranja programa Citati.

0%
0%