Citat:
demon_01: ajoj cuj izvini,trebam se ja izvinut sto gnjavim uvjek...
napravio sam test kod je prosao ali program ne radi kako bi trebao vjerovatno sam ja nesto pogresno pozvao u mainu
na koji nacin cu sad hashirat listu?? i da li je ova funkcija tacna za ispis liste??
void ispisiTabelu(){
for (int i=0;i<VELICINA_TABELE;i++)
cout<<hashTabela<i>;}
Zdravo, evo mene opet.
Konacno sam se dohvatio alata, pa sam imao priliku i da vidim kakve sam sve gluposti nalupetao. Ali dobro, ocistio sam musice, video glavni nedostatak (pored ostalih bugova), te sredio.
Glavni nedostatak je bio u tome sto, posle izbacivanja jednog elementa iz liste, nije azuriran hash zapis onog koji dolazi posle njega.
Takodje, promenio sam funkciju izbaciDuplikate jer sam shvatio da ce na ovaj nacin, izbacivanje biti brze i korektnije.
Elem, evo ti kompletnog resenja, uglavnom baziranog na prethodnoj prici:
Code:
//esmain.cpp
#include <stdlib.h>
#include <iostream>
using namespace std;
struct Cvor {
int broj;
Cvor *sljedeci;
};
struct HashZapis {
Cvor *pok;
HashZapis *sljedeci;
};
#define VELICINA_TABELE 100
unsigned int hash(int vrednost) {
return abs(vrednost) % VELICINA_TABELE;
}
HashZapis *hashTabela[VELICINA_TABELE];
/*
prethodnik[in] - pokazivac na element u listi koji je prethodnik elementu koji zelimo da obrisemo
*/
Cvor *obrisiElementIzListe(Cvor *prethodnik) {
if(prethodnik == 0) return 0;//Ne zelimo da ispadnemo budale, te ako je argument NULL pointer, sa prezirom cemo izignorisati celu operaciju.
Cvor *zaBrisanje = prethodnik->sljedeci;
if(zaBrisanje == 0) return 0; //ovo je kraj liste, trazeni element ni ne postoji ili je u pitanju neka greska.
prethodnik->sljedeci = zaBrisanje->sljedeci;//prevezujemo elemente liste
free(zaBrisanje);//ili delete zaBrisanje - vidi 3. b)
return zaBrisanje;
}
int dajVrednostPodatka(HashZapis *zapis) {
if(zapis == 0) return 0;
Cvor *prethodnik = zapis->pok;
if(prethodnik == 0) return 0;
if(prethodnik->sljedeci == 0) return 0;
//ok, sada mozemo da dohvatimo podatak
return prethodnik->sljedeci->broj;
}
HashZapis *dajRedIzHashTabele(int kljuc) {
unsigned int indeks = hash(kljuc);
HashZapis *rezultat = hashTabela[indeks];
return rezultat;
}
/*
elementUHashTabeli[in] - hash zapis elementa cije duplikate valja zatuci.
return broj obrisanih elemenata
*/
unsigned int izbaciDuplikate(HashZapis *elementUHashTabeli) {
if(elementUHashTabeli == 0) return 0;
unsigned int rezultat = 0;
int kljuc = dajVrednostPodatka(elementUHashTabeli);
HashZapis *prethodni = elementUHashTabeli;//trebace nam za brisanje duplikata iz Hash tabele
elementUHashTabeli = elementUHashTabeli->sljedeci;//prvi posle originala
while(elementUHashTabeli) {
if(kljuc == dajVrednostPodatka(elementUHashTabeli)) {
//duplikat - obrisacemo ga
Cvor *previous = elementUHashTabeli->pok;
Cvor *obrisani = obrisiElementIzListe(previous);
//medjutim, sada je za element koji dolazi posle obrisanog
//potrebno promeniti hash zapis, tako da ovaj ukazuje na novog prethodnika.
Cvor *zaAzuriranje = previous->sljedeci;
if(zaAzuriranje != NULL) {
unsigned int indeks = hash(zaAzuriranje->broj);
HashZapis *hashAzuriranog = hashTabela[indeks];
while(hashAzuriranog) {
if(hashAzuriranog->pok == obrisani) {
hashAzuriranog->pok = previous;
break;
}
hashAzuriranog = hashAzuriranog->sljedeci;
}
}
//sada da izbacimo i ovaj hash zapis za obrisani element
prethodni->sljedeci = elementUHashTabeli->sljedeci;
free(elementUHashTabeli);//ili delete elementUHashTabeli;
++rezultat;
} else {
prethodni = elementUHashTabeli;
}
elementUHashTabeli = prethodni->sljedeci;
}
return rezultat;
}
void napraviTabelu(Cvor *headListe) {
//inicijalizacija
for(int i = 0; i < VELICINA_TABELE; ++i) {
hashTabela[i] = NULL;
}
//glavna prica
cout << "Pravljenje tabele" << endl;
if(headListe == NULL) return;
Cvor *prethodni = headListe;
Cvor *zaObradu = headListe->sljedeci;
while(zaObradu) {
HashZapis *zapis = (HashZapis *) malloc(sizeof(HashZapis));
zapis->pok = prethodni;
unsigned int indeks = hash(zaObradu->broj);
HashZapis *sledeci = hashTabela[indeks];
zapis->sljedeci = sledeci;
hashTabela[indeks] = zapis;
prethodni = zaObradu;
zaObradu = zaObradu->sljedeci;
}
return;
}
void pisiListu(Cvor *headListe) {
if(headListe == NULL) return;
Cvor *element = headListe->sljedeci;
cout << "Sadrzaj liste:" << endl;
while(element) {
cout << element->broj << ", ";
element = element->sljedeci;
}
cout << endl;
}
int main() {
Cvor head;
head.sljedeci = NULL;
int niz[30] = {
7, 9, 12, 347, 283, 25, 1200, 3047, 400, 83,
7, 9, 12, 347, 283, 25, 1200, 3047, 400, 83,
7, 9, 12, 347, 283, 25, 1200, 3047, 400, 83
};
for(int i = 0; i < 30; ++i) {//Ovo sve je sada da napravimo nekakvu test listu sa duplikatima
Cvor *novi = (Cvor *) malloc(sizeof(Cvor));
novi->broj = niz[i];
novi->sljedeci = head.sljedeci;
head.sljedeci = novi;
}
pisiListu(&head);
cout << "Izbacujem duplikate" << endl;
napraviTabelu(&head);
for(unsigned int i = 0; i < 100; ++i) {
HashZapis *trenutni = hashTabela[i];
while(trenutni != NULL) {
unsigned n = izbaciDuplikate(trenutni);
cout << "Izbacio " << n << " elemenata sa vrednoscu " << dajVrednostPodatka(trenutni) << endl;
pisiListu(&head);
trenutni = trenutni->sljedeci;
}
}
cout << "Na kraju je" << endl;
pisiListu(&head);
}
Zao mi je sto sam te samo smorio sa onom gomilom pogresnog i nabrzinu nakucanog koda. I ja sebe zovem programerom... e moj Vladimire...
Uzgred budi receno: primena jednostruko ulancane liste, kao sto vidis, prilicno komplikuje stvar. Sa dvostruko ulancanom listom, sve bi bilo daleko korektnije, jednostavnije i ne tako podlozno greskama. Zbog azuriranja hash zapisa elementa koji dolazi nakon obrisanog, bilo je potrebno izvrsiti poziv hash funkcije. Ova hash funkcija u ovom resenju je jednostavna i ne smatra se dobrom u praksi i realnim primenama. Hash funkcije znaju nekada biti dovoljno "skupe" i isplative su samo zbog indeksiranja ogromnog broja podataka.
Iskompajliraj, poteraj...
Eh, da... ako ovo budes davao profi, malo regulisi nazive promenljivih i funkcija i same komentare.

Bilo bi glupo da, ako ti pricas jekavicom, da se naleti na ekavicu.
Inace, ono "cout << hashTabela<i>" ce ti samo ispisati vrednosti pointera, dakle adrese, a ne smislene podatke.