////////////////////////////////////////////
    //
    // structure.cpp
    //
    // Structure de données pour stocker
    // un graphe en mémoire.
    //
    // Michaël ORTEGA & Nicolas DUMOULIN
    // Projet de Graphe - Mai 2001
    //
    ////////////////////////////////////////////

#include "structure.h" 

/////////////////// classe sommet /////////////////////////////////

    //suppression de la liste des successeurs de la mémoire
void sommet::supprime_liste() 
/*suppression totale de la liste*/

    list_sommet * tmp; 
    while (succ!=NULL) { 
            tmp=succ->suivant; 
            delete succ; 
            succ=tmp; 
    } 


    //ajout d'un successeur dans la liste du sommet
void sommet::ajout_liste(sommet * s,const unsigned int p) 
/*insertion en début de liste, c'est a dire entre le sommet générateur de la liste et la tête de liste*/

    list_sommet * nouveau=new list_sommet; 
    nouveau->poids=p; 
    nouveau->contenu=s; 
    nouveau->suivant=succ; 
    succ=nouveau; 


    //affichage du numéro du sommet ainsi que de ses successeurs
void sommet::affiche() const 

    list_sommet * courant=succ; 
    cout<<"Liste des successeurs de "<<code<<" : "<<endl; 
    while (courant != NULL) 
    { 
        cout<<" sommet : "<<courant->contenu->code<<" poids de l'arc : "<<courant->poids<<endl; 
        courant=courant->suivant; 
    } 


    //renvoie si le sommet a pour successeur le sommet dont le numéro est passé en paramètre
int sommet::a_pour_succ(const unsigned int c) const 

    list_sommet * courant=succ; 
     
    while (courant!=NULL) 
    { 
        if (courant->contenu->code==c) return (courant->poids); 
        courant=courant->suivant; 
    } 
    return -1;    //le sommet n'était pas dans la liste de successeurs


/////////////////// classe graph //////////////////////////////////

    //affichage du graphe : liste des sommets et de leurs successeurs
void graph::affiche() const 

    cout<<"affichage du graphe :"<<endl; 
    for (unsigned int i=0;i<nbs;i++) tabsommet[i].affiche(); 


    //formation d'un arc de poids p, du sommet d au sommet a
void graph::ajout_succ(const unsigned int d,const unsigned int a,const unsigned int p) 

    tabsommet[d].ajout_liste(tabsommet+a,p); 



    //on test si S a tous ses sommets marqués
int graph::test(const unsigned int * s) const 

    for (unsigned int i=0;i<nbs;i++)  
        if (s[i]==0) return 1; 
    return 0; 


    //algorithme de Dijkstra
graph * graph::dijkstra(unsigned long int & temps) const 

    unsigned int progression=0;                    //indicateur de progression de l'algo
    cout<<".";                                            //affichage du début de la progression
    unsigned int * S = new unsigned int [nbs]; 
    unsigned int * Pi = new unsigned int [nbs]; 
    unsigned int xpivot=0;                        //initialisation de xpivot au premier sommet
    graph * resultat = new graph(nbs);    //allocation mémoire du graphe resultant
    list_sommet * courant;                //pour parcourir la liste des successeurs de xpivot
     
    struct timeb deb,fin; 

    ftime(&deb);        //debut du "chronomètrage"
     
    for (unsigned int i=0;i<nbs;i++) S[i]=0;    //initialisation du tableau (aucun des sommets n'est marqué)
#ifdef visualcpp 
    for (i=0;i<nbs;i++) Pi[i]=infini;    //initialisation de pi pour chaque sommet
#else 
    for (unsigned int i=0;i<nbs;i++) Pi[i]=infini;    //initialisation de pi pour chaque sommet
#endif     
    //marquage du premier sommet
    S[0]=1;     
    Pi[0]=0; 

    while ( test(S) && (Pi[xpivot]<infini) ) 
    { 
        courant=tabsommet[xpivot].succ; 
        unsigned int x; 
        while (courant!=NULL) 
        { 
            x=courant->contenu->code; 
            if ( Pi[x] > (Pi[xpivot] + courant->poids) ) 
                Pi[x] = Pi[xpivot] + courant->poids; 
            courant=courant->suivant; 
        } 
        //recherche du Pi minimum parmis les sommets non marqués
        unsigned int min=infini; 
        for (unsigned int i=0;i<nbs;i++) if (S[i]==0) if (Pi[i]<min) {min=Pi[i];xpivot=i;} 
        //on a trouvé notre xpivot
        S[xpivot]=1; 
        //affichage de la progression : 10 points affichés= progression terminée
        progression++; 
        if (progression%((nbs+11)10)==0) cout<<"."; 
        //on a mis nbs+11 car si on a moins de 10 sommet ça plante!
#ifdef visualcpp 
        for (i=0;i<nbs;i++) if (S[i]==1) 
#else 
        for (unsigned int i=0;i<nbs;i++) if (S[i]==1) 
#endif     
        { 
            courant=tabsommet[i].succ; 
            while ((courant!=NULL) && (courant->contenu->code != xpivot)) 
                //tant que l'on est pas à la fin de la liste des successeurs du sommet i
                // et que le successeur courant n'est pas xpivot faire
                courant=courant->suivant; 
            if (courant!=NULL) 
                if (Pi[xpivot]==(Pi[i] + courant->poids)) 
                { 
                    resultat->ajout_succ(i,xpivot,courant->poids); 
                    i=nbs; 
            } 
        } 
         
    } 
    ftime(&fin);        //fin du "chronomètrage"
    temps=(fin.time-deb.time)*1000+fin.millitm-deb.millitm; 
    return resultat; 


#include <fstream> 

    //chargement d'un garphe à partir d'un fichier
void graph::charger() 

    int tmp; 
    char tmpc[20]; 
    char nom_fichier[256]; 

    cout<<" Veuillez saisir le nom du fichier : "; 
    cin>>nom_fichier; 
     
    ifstream fich(nom_fichier); 
    fich>>nbs; 
    tabsommet = new sommet [nbs]; 
    for (unsigned int i=0;i<nbs;i++)  
    { 
        fich>>tmpc; //pour les sauts de lignes des séparations de chaque sommet dans le fichier
        tabsommet[i].code=i; 
        for (unsigned int j=0;j<nbs;j++) 
        { 
            fich>>tmp; 
            if (tmp!=-1) ajout_succ(i,j,tmp); 
        } 
         
    } 
    fich.close(); 


    //enregistrement d'un graphe dans un fichier
void graph::enregistrer() const 

    int choix=0;         
    if (nbs>20) 
    { 
        cout<<"Attention, votre graphe est volumineux, l'enregistrer dans un fichier risque de prendre du temps !"<<endl; 
        cout<<"  de plus la lecture de ce fichier sera tres fastidieuse"<<endl<<endl; 
        cout<<"              Voulez-vous tout de même "; 
        if (nbs>200) cout<<"prendre un cafe et "; 
        cout<<"lancer l'enregistrement : Oui (tapez 0)  Non (tapez 1)"<<endl<<endl<<"  ? -> "; 
        cin>>choix; 
    } 
    if (!choix) 
    { 
        char nom_fichier[256]; 

        cout<<" Veuillez saisir le nom du fichier : "; 
        cin>>nom_fichier; 
         
        ofstream fich(nom_fichier); 
        fich<<nbs<<endl; 
        for (unsigned int i=0;i<nbs;i++) 
        { 
            fich<<"******"<<endl;    //ligne de séparation pour augmenter la lisibilité
            for (unsigned int j=0;j<nbs;j++) fich<<tabsommet[i].a_pour_succ(j)<<endl; 
        } 
    } 


    //propose à l'utilisateur d'afficher en d'enregistrer un graphe
void graph::sortie_graphe() 

    int choix_menu; 

    cout<<"  Voulez-vous : 1 -> afficher ce graphe"<<endl; 
    cout<<"                2 -> sauver ce graphe dans un fichier"<<endl; 
    cout<<"                3 -> passer a la suite"<<endl<<endl; 
    cout<<"                ? -> "; 
    cin>>choix_menu; 
    cout<<endl<<endl; 
    if (choix_menu==1) this->affiche(); 
    else if (choix_menu==2) enregistrer(); 


    //génération aléatoire de graphe ayant n sommets
void graph::hasard(const unsigned int n, const unsigned int proba) 

    unsigned int progression=0;                    //indicateur de progression
    cout<<".";                            //affichage du début de la progression
    nbs=n; 
    tabsommet = new sommet [nbs]; 
    for (unsigned int i=0;i<nbs;i++)  
    { 
        tabsommet[i].code=i; 
        //affichage de la progression : 10 points affichés= progression terminée
        progression++; 
        if (progression%((nbs+11)10)==0) cout<<"."; 
        //on a mis nbs+11 car si on a moins de 10 sommet ça plante!
        //attribution des successeurs
        for (unsigned int j=0;j<nbs;j++) 
        { 
            if (i!=j) 
            { 
                int p=rand() % 100; 
                if (p<proba) 
                { 
                    p=rand()%10+1; 
                    ajout_succ(i,j,p); 
                } 
            } 
        } 
    } 
    cout<<endl<<endl<<"        generation terminee"<<endl<<endl;
    cout<<" Verification de la connexite du graphe genere : ..."<<endl<<endl;
    connexe();
    cout<<"        Verification et eventuelles corrections effectuees."<<endl<<endl<<endl;



//verifie si un graphe est connexe en utilisant un parcours en largeur, et dans le cas échéant le rend connexe
//renvoie un si une correction a été apportée
int graph::connexe()
{
    int resultat=1;            //valeur de retour
    unsigned int * S = new unsigned int [nbs];    //tableau des sommets marqués
    unsigned int * F = new unsigned int [nbs+1];    //File
    list_sommet * courant;        //pour parcourir la liste des successeurs de xpivot
    unsigned int xpivot=0,tete=0,queue=0;        //sommet en cours de traitement, tête et queue de la file
    
    for (unsigned int i=0;i<nbs;i++) S[i]=0;    //initialisation du tableau (aucun des sommets n'est marqué)
    F[tete]=0;                                    //marquage de la racine
    while (tete<=queue)
    {
        xpivot=F[tete];
        //parcours de la liste des successeurs de xpivot
        courant=tabsommet[xpivot].succ;
        while (courant!=NULL)        
        {
            if (!S[courant->contenu->code])
            {
                S[courant->contenu->code]=S[xpivot]+1;
                queue++;
                F[queue]=courant->contenu->code;
            }
            courant=courant->suivant;
        }
        tete++;
    }
    //fin du marquage
    delete [] F;
    //on teste maintenant si des sommets ne sont pas marqués, auquel cas le graphe n'est
    //pas connexe. On ajoute alors un arête pour le connecter au reste du graphe
#ifdef visualcpp
    for (i=1;i<nbs;i++)
#else
    for (unsigned int i=1;i<nbs;i++)
#endif
    if ( (!S[i])&&(tabsommet[i-1].a_pour_succ(i)==-1) ) 
    {
        ajout_succ(i-1,i,rand()%10+1);
        resultat=0;
    }
    //si on a un sommet isolé, on rajoute un arc entre le sommet le précédent (dans la numérotation)
    //en vérifiant qu'ils ne sont pas déjà liés : en effet ces deux sommets n'étaient peut-être
    //pas connectés au reste du graphe, mais son prédecesseur a déjà subit le test et est donc
    // désormais connecté au reste du graphe, le sommet courant l'est donc aussi ...
    return resultat;
}