Complessità algoritmo in C

di il
17 risposte

Complessità algoritmo in C

Salve ho bisogno di un parere esterno riguardo l'algoritmo più efficace per questo problema:
Dati N punti nel piano (vengono forniti un vettore X con le ascisse ed un vettore Y con le ordinate e ovviamente il numero N) dire se ci sono coppie di punti equidistanti (basta trovare una coppia non serve specificare quale o andare avanti con il programma una volta trovata). Con coppie equidistanti si intendono ad esempio i punti A e D che distano 10m e i punti F e G che distano anche loro 10m.
Sono in dubbio su due metodi,in entrambe viene creata una funzione "int DistanzaQuadrata" che presi in input 4 valori interi(le due ascisse e le due ordinate dei due punti) restituisce la distanza al quadrato sfruttando pitagora. Ed inoltre inizializzo tutto a -1 un vettore int d[] ,di dimensione (n*(n-1))/2 ovvero le possibili combinazioni delle distanze. Poi viene il dubbio
Primo metodo: calcolo una distanza, la inserisco nel vettore e controllo che non sia uguale ad una già inserita così in caso positivo posso interrompere il programma senza dover calcolare tutte le distanze.
Secondo metodo: calcolo tutte le distanze e le inserisco nel vettore, poi ordino il vettore usando il merge sort e infine controllo se ci sono valori uguali adiacenti.
La domanda è quindi qual è tra questi due l'algoritmo più efficiente, o se si può far di meglio.
Grazie a tutti

17 Risposte

  • Re: Complessità algoritmo in C

    Conta quanti test devi fare, e considera il CASO PEGGIORE.

    ci sono n punti, quindi n(n-1)/2 distanze

    1) devi fare 1+2+...+n(n-1)/2-1 test
    2) devi ordinare le distanze (complessita'=numero di confronti?) devi confrontare due distanze adiacenti, quindi (quanti?) confronti= totale uguale a ...

    Il vincitore e' .... rullo di tamburi ....

    In fremente attesa della risposta

    https://it.wikipedia.org/wiki/Stupid_sor
  • Re: Complessità algoritmo in C

    Con n punti le distanze non sono n(n-1) ma (n(n-1))/2
    ad esempio con 2 punti tu avresti 2 distanze quando in realtà è una sola. In pratica con n(n-1) conti la distanza tra A e B e anche quella tra B ed A che però è la stessa
  • Re: Complessità algoritmo in C

    Mi ero perso il */2 per strada

    Pero' NON E" CERTO il fattore 2 che fa cambiare le regole del gioco.

    Hai fatto i conti?

    Nulla all'orizzonte?
  • Re: Complessità algoritmo in C

    La complessità per il calcolo delle distanze sinceramente non saprei come farlo ma nel caso peggiore è uguale nei 2 casi mentre in quello medio la complessità nel primo è ovviamente la metà del secondo. I controlli nel primo caso peggiore sono una sommatoria classica quindi (chiamando k=(n(n-1))/2 ) viene (1/2)*(k*(k+1)) nel secondo caso la complessità è il costo per il controllo degli adiacenti ovvero k-1 (caso peggiore) ((k-1)/2 caso medio) + sempre uguale k*log(k) per il costo del Merge Sort . Comunque mi sembra che il secondo sia il più conveniente
  • Re: Complessità algoritmo in C

    Vabbe, l'autore ha gia' risolto.
    Tanto meglio


    https://it.wikipedia.org/wiki/Algoritmo_di_ordinament
  • Re: Complessità algoritmo in C

    Non ho completato usando gli O grandi ma i calcoli sono gli stessi che hai fatto tu a parte il costo del Merge Sort e non capisco perchè tu abbia usato O(n log(n)) quando va ordinato un vettore di (n(n-1))/2 ) elementi. Comunque anche con il Merge Sort cambiato il secondo è più efficiente
  • Re: Complessità algoritmo in C

    I calcoli sono sbagliati infatti.

    Ma i punti delle coppie devono essere tutti distinti? Ad esempio, se hai (N - 1) punti su una circonferenza, tutti a distanze diverse tra di loro e diverse dal raggio, più il centro della circonferenza, la risposta alla domanda è positiva o negativa?
  • Re: Complessità algoritmo in C

    L'ho spiegato all'inizio: basta trovare 2 coppie di punti alla stessa distanza e poi si interrompe il programma. Quindi si nel tuo caso appena si vedrà che ci sono 2 distanze uguali (presi due punti A e B nella circonferenza e C il centro) come ad esempio AC e BC il programma si interromperà e darà esito positivo
  • Re: Complessità algoritmo in C

    L'hai spiegato ora. Allora è O(N^2 logN)
  • Re: Complessità algoritmo in C

    @utahraptor, ma alla fin fine, hai capito quale e' la complessita dei vari approcci?

    E se invece del "Merge Sort" usi

    1) il "Bubble Sort" oppure
    2) il "Bogosort"

    e' meglio? peggio? o uguale?

    Fino ad ora i conti te li abbiamo fatti noi (magari sbagliati MA li abbiamo fatti!)
  • Re: Complessità algoritmo in C

    Avevo detto:" (basta trovare una coppia non serve specificare quale o andare avanti con il programma una volta trovata) ".
    Cos'è che è O(N^2 logN)?

    bubble sort e bogosort non li ho fatti
  • Re: Complessità algoritmo in C

    La soluzione con mergesort

    O(N*(N-1)/2 * log(N*(N-1)/2) + N*(N-1)/2 - 1) = O(N^2 * logN)
    Sicuramente più bassa del metodo 1. Non so se la più bassa in generale - non è un problema semplice come sembra
  • Re: Complessità algoritmo in C

    Basta trovare una coppia alla lettera è O(1) con (A,B) e (A,B)
    Il caso (A,B) (B,C) non è evidente dal primo post, l'hai specificato più avanti

    Non è questione di pignoleria, cambia proprio il risultato
  • Re: Complessità algoritmo in C

    Io non ho ben capito se allo OP serve una disanima teorica sul migliore tra i due algoritmi descritti oppure serve di cercare una soluzione "la più veloce"


    anche tra altre possibilità

    io, senza una grande trattazione teorica, propenderei per una (consistente) modifica al metodo 1
    posto n il numero di punti siamo tutti d'accordo che sia necessario calcolare n*(n-1)/2 distanze, qualunque sia il metodo successivamente usato?
    no, non è così, questo è solo il caso peggiore, ma prendiamolo per buono
    da questo consegue che la parte di calcolo delle distanze non si può migliorare (poi vediamo anche questo, comunque)
    e quindi la sua complessità non mi interessa: si tratta di un fardello che non posso scaricare dalle mie spalle

    ma identificare eventuali distanze ripetute si può fare in vari modi, è qui che ho pensato:

    lo OP presenta due casi, cito:
    Primo metodo: calcolo una distanza, la inserisco nel vettore e controllo che non sia uguale ad una già inserita così in caso positivo posso interrompere il programma senza dover calcolare tutte le distanze.
    Secondo metodo: calcolo tutte le distanze e le inserisco nel vettore, poi ordino il vettore usando il merge sort e infine controllo se ci sono valori uguali adiacenti.

    se i due metodi fossero cogenti io mi fermo qui,
    altrimenti mi permetto di presentare un paio di "migliorie" al metodo 1, migliorie che oserei dire significative

    a) inverto l'ordine: calcolo la distanza, controllo che non sia uguale ed eventualmente la inserisco nel vettore
    b) tengo il vettore ordinato, cosa che mi permetterà di cercare la prossima distanza calcolata con una ricerca dicotomica invece che con un semplice scorrimento, al prezzo di un continuo "riordinamento parziale" del vettore ho un forte alleggerimento della ricerca
    c) quando cerco una distanza, se non la trovo sono almeno già nel punto del vettore dove devo inserirla, questo ammetto sia un po' una banalità, discende del punto b), ma io sono dell'idea che "tutto fa brodo",
    ma quella che spero essere la vera differenza è un'altra
    d) pre-ordino il vettore dei punti (ok, ok, i vettori delle due coordinate, ma io ragiono come se fosse un singolo vettore di punti)
    perché ne effettuo un pre-ordinamento?
    ho pensato che la distanza tra due punti è "non maggiore" della somma delle distanze dei due punti dall'origine degli assi
    da questo discende che il valore massimo delle distanze è tanto più basso tanto i punti sono vicini all'origine degli assi
    da questo discende che la probabilità di trovare distanze basse è tra i punti vicini all'origine... da adesso li chiamo punti "bassi"
    se i punti sono distribuiti casualmente la probabilità di avere "doppioni" di distanze (credo, non ho una dimostrazione formale di questo) scende con l'aumentare della distanza dall'origine degli assi (in soldoni: è più facile trovare doppioni se i numeri sono piccoli)
    e quindi io testo per primi i punti bassi, sperando che mi vada bene
    ultimo (ma poi magari ne trovo ancora) trucco:
    tengo traccia del massimo (e magari del minimo) valore finora trovato, con un semplice test "prima" di cominciare la ricerca nell'array so già se per caso ho sforato il massimo, e siccome mi aspetto che i valori (dopo aver pre-ordinato i punti) mi si presentino tendenzialmente in salita (dai punti bassi ai punti alti), spero di poter abbastanza spesso, evitare proprio la ricerca nell'array e limitarmi ad aggiungere in fondo

    a dopo per un approccio completamente differente
Devi accedere o registrarti per scrivere nel forum
17 risposte