import networkx as nx import matplotlib.pyplot as plt import numpy as np import random as rd # G=nx.Graph() # G.add_edges_from([(1,2),(1,5),(2,3),(2,5),(3,4),(4,5),(4,6),(5,0)]) # nx.draw(G,with_labels=True) # plt.show() ############################# G=nx.Graph() G.add_edges_from([(1,2),(1,5),(2,3),(2,5),(3,4),(4,5),(4,6),(5,0)]) nx.draw(G,with_labels=True) plt.show() ############################# H=nx.Graph() H.add_nodes_from([1,2,3,4,5,6,7,8,9,10,11]) H.add_edges_from([(1,2),(1,5),(2,3),(2,5),(4,6),(5,0),(8,11),(9,8),(10,8)]) nx.draw(H,with_labels=True) plt.show() ############################# ####################### ArbreBin=nx.Graph() ArbreBin.add_edges_from([(1,2),(1,5),(3,4),(4,5),(4,6),(5,0)]) # dessin ́e comme ceci nx.draw(ArbreBin,with_labels=True) plt.show() # ou comme cela # dico_pos_arbre = {1:(0,0),2:(-1,-1),5:(2,-1),0:(1,-2),4:(3,-2),3:(2,-3), 6:(4,-3)} # nx.draw(ArbreBin,dico_pos_arbre,with_labels=True) plt.show() ###################### #################################### ## primitives des files #################################### ##enfiler def ajouter_file(F,v): F.append(v) return ##d ́efiler def enlever_tete_file(F): del F[0] return; ##regarder la valeur en tˆete de file def valeur_tete_file(F): return F[0] ##tester si la file est vide def est_file_vide(F): return len(F)==0 ## petit test sur les files : def test_file(): F=[] ajouter_file(F,5) print(F) ajouter_file(F,3) print(F) ajouter_file(F,8) ajouter_file(F,2) print(F) enlever_tete_file(F) print("on a enlev ́e la tete") print(F) if est_file_vide(F) : print("PB : la file est vide") else : print("en tete de file : " + str(valeur_tete_file(F))) enlever_tete_file(F) enlever_tete_file(F) enlever_tete_file(F) if est_file_vide(F) : print("OK : la file est vide") else : print("PB : la file n’est pas vide") return #################################### ## primitives des piles #################################### ##empiler def ajouter_pile(P,v): P.append(v) return ##d ́epiler def enlever_sommet_pile(P): del P[len(P)-1] # ou alors P.pop() return; ##regarder def valeur_sommet_pile(P): return P[len(P)-1] ##tester def est_pile_vide(P): return len(P)==0 ## petit test sur les piles : def test_pile(): P=[] ajouter_pile(P,5) ajouter_pile(P,3) ajouter_pile(P,8) ajouter_pile(P,2) print(P) enlever_sommet_pile(P) print("on a enlev ́e le sommet") print(P) if est_pile_vide(P) : print("la pile est vide") else : print("au sommet : " + str(valeur_sommet_pile(P))) enlever_sommet_pile(P) enlever_sommet_pile(P) enlever_sommet_pile(P) if est_pile_vide(P) : print("OK : la pile est vide") else : print("PB : la pile n’est pas vide") return ########### parcours en largeur ############## def parcours_largeur(G,s): visites = [] # sommets vus (compl`etement ou juste dans la fronti`ere) F = [] # la fronti`ere visites.append(s) ajouter_file(F,s) while(not est_file_vide(F)): v = valeur_tete_file(F) trouve = False # voisin de v non deja visite pas encore trouv ́e for u in G.neighbors(v): if (u not in visites) : visites.append(u) ajouter_file(F,u) trouve = True # voisin de v non deja visite trouv ́e break if not trouve : enlever_tete_file(F) return visites print(parcours_largeur(G,1)) # Une autre solution : def parcours_largeur(H,s): visites=[] F=[] visites.append(s) ajouter_file(F,s) while not est_file_vide(F): v = valeur_tete_file(F) L = [t for t in H.neighbors(v) if t not in visites] if len(L) != 0: visites.append(L[0]) ajouter_file(F,L[0]) else: enlever_tete_file(F) return visites print(parcours_largeur(G,1)) ########### parcours en profondeur ############## def parcours_profondeur(G,s): visites = [] P = [] # la fronti`ere visites.append(s) ajouter_pile(P,s) while(not est_pile_vide(P)): v = valeur_sommet_pile(P) trouve = False # voisin de v non deja visite pas encore trouv ́e for u in G.neighbors(v): if (u not in visites) : visites.append(u) ajouter_pile(P,u) trouve = True # voisin de v non deja visite trouv ́e break if not trouve : enlever_sommet_pile(P) return visites print(parcours_profondeur(G,1)) # Une autre solution : def parcours_profondeur(H,s): visites=[] P=[] visites.append(s) ajouter_pile(P,s) while not est_pile_vide(P): v = valeur_sommet_pile(P) L = [t for t in H.neighbors(v) if t not in visites] 6 if len(L) != 0: visites.append(L[0]) ajouter_pile(P,L[0]) else: enlever_sommet_pile(P) return visites print(parcours_profondeur(G,1)) # ! TP 4 # ? Exercice 1 # Ecrire une fonction est_connexe(G) qui determine si un graph G est connexe, en utlisant un des deux algorithmes de parcours vus en semaine 3 (voir solution sur moodle) def est_connexe(G): return len(parcours_largeur(G,1)) == len(G.nodes()) # Ecrire une fonction composantes connexes(G) qui calcule et retourne la liste des composantes connexes d'un graph G def composantes_connexes(G): visites = [] composantes = [] for s in G.nodes(): if s not in visites: composantes.append(parcours_largeur(G,s)) visites.extend(parcours_largeur(G,s)) return composantes # Tester les deux fonctions précédentes avec les graphes G et H print("=========================== Exo 1 ===========================") print(est_connexe(G)) print(est_connexe(H)) print(composantes_connexes(G)) print(composantes_connexes(H)) # ? Exercice 2 # Ecrire une fonction distances(G,s) qui, pour un graphe G connexe et un sommet s donn ́es, calcule la distance (en nombre d’arˆetes) entre s et chaque sommet de G. Cette fonction retourne un dictionnaire associant une distance `a chaque sommet. Pour cela, comme vu en cours, on modifie le parcours en largeur. def distances(G,s): visites = [] F = [] distances = {} visites.append(s) ajouter_file(F,s) distances[s] = 0 while(not est_file_vide(F)): v = valeur_tete_file(F) trouve = False # voisin de v non deja visite pas encore trouv ́e for u in G.neighbors(v): if (u not in visites) : visites.append(u) ajouter_file(F,u) distances[u] = distances[v] + 1 trouve = True # voisin de v non deja visite trouv ́e break if not trouve : enlever_tete_file(F) return distances print("=========================== Exo 2 ===========================") print(distances(G,1)) print(distances(H,1)) # (optionnel) ́Ecrire une fonction affiche plus courts chemins a partir de(G,s) qui, # pour un graphe G connexe et un sommet s donn ́es, affiche pour chaque sommet du # graphe un plus court chemin `a partir de s. # Cette fonction appellera la fonction plus courts chemins(G,s) qui calcule pour chaque # sommet son pr ́ed ́ecesseur (le sommet par lequel il est d ́ecouvert lors du parcours `a par- # tir de s). # Exemple : affiche plus courts chemins a partir de(G,1) (avec G de l’exercice # pr ́ec ́edent) donnera : # 1 # 2 <- 1 # 5 <- 1 # 3 <- 2 <- 1 # 4 <- 5 <- 1 # 6 <- 4 <- 5 <- 1 # 0 <- 5 <- 1 def affiche_plus_courts_chemins_a_partir_de(G,s): distance = distances(G,s) for i in range(len(G.nodes())): chemin = str(i) j = i while j != s: j = distance[j] chemin = str(j) + " <- " + chemin print(chemin) affiche_plus_courts_chemins_a_partir_de(G,1) # ? Exercice 3 # Un arbre binaire est un arbre qui poss`ede une unique racine (un sommet particulier) et # o`u chaque sommet a au plus deux sommets voisins sp ́eciaux, appel ́es ses fils. S’il a deux fils, # l’un est le fils gauche et l’autre est le fils droit. Un sommet est appel ́e le p`ere de son fils. Ainsi, # chaque sommet de l’arbre binaire a au maximum trois voisins (deux fils et un p`ere). La racine # n’a pas de p`ere, et les feuilles sont les sommets sans fils. # Dans cet exercice, on s’int ́eresse au parcours en profondeur d’un arbre binaire T `a partir de # sa racine r. Un certain traitement doit ˆetre effectu ́e une fois et une seule sur chaque sommet # au cours de ce parcours. Ici, le traitement consiste simplement `a afficher le nom du sommet. # Vous pourrez tester vos programmes sur l’arbre ArbreBin ci-dessous, dont la racine est le # sommet 1. # ####################### # ArbreBin=nx.Graph() # ArbreBin.add_edges_from([(1,2),(1,5),(3,4),(4,5),(4,6),(5,0)]) # # dessin ́e comme ceci # nx.draw(ArbreBin,with_labels=True) # plt.show() # # ou comme cela # dico_pos_arbre = {1:(0,0),2:(-1,-1),5:(2,-1),0:(1,-2),4:(3,-2),3:(2,-3), 6:(4,-3)} # nx.draw(ArbreBin,dico_pos_arbre,with_labels=True) # plt.show() # ####################### # Ecrire une fonction qui affiche le nom de chaque sommet au moment o`u il est ajout ́e `a la pile. Ce type de parcours en profondeur d’un arbre binaire s’appelle un parcours pr ́efixe. def parcours_prefixe(T,r): visites = [] P = [] visites.append(r) ajouter_pile(P,r) while(not est_pile_vide(P)): v = valeur_sommet_pile(P) trouve = False # voisin de v non deja visite pas encore trouv ́e for u in T.neighbors(v): if (u not in visites) : visites.append(u) ajouter_pile(P,u) trouve = True # voisin de v non deja visite trouv ́e break if not trouve : enlever_sommet_pile(P) return visites print("=========================== Exo 3 ===========================") print(parcours_prefixe(ArbreBin,1)) # Ecrire une fonction qui affiche le nom de chaque sommet au moment o`u il est supprim ́e # de la pile. Ce type de parcours en profondeur d’un arbre binaire s’appelle un parcours # postfixe. def parcours_postfixe(T,r): visites = [] P = [] visites.append(r) ajouter_pile(P,r) while(not est_pile_vide(P)): v = valeur_sommet_pile(P) trouve = False # voisin de v non deja visite pas encore trouv ́e for u in T.neighbors(v): if (u not in visites) : visites.append(u) ajouter_pile(P,u) trouve = True # voisin de v non deja visite trouv ́e break if not trouve : enlever_sommet_pile(P) print(v) return visites print("=========================== Exo 3 ===========================") print(parcours_postfixe(ArbreBin,1)) # Ecrire une fonction qui affiche le nom de chaque sommet la premi`ere fois qu’on le # rencontre s’il n’a qu’un fils et la deuxi`eme fois s’il en a deux. Ce type de parcours en # profondeur d’un arbre binaire s’appelle un parcours infixe. def parcours_infixe(T,r): visites = [] P = [] visites.append(r) ajouter_pile(P,r) while(not est_pile_vide(P)): v = valeur_sommet_pile(P) trouve = False # voisin de v non deja visite pas encore trouv ́e for u in T.neighbors(v): if (u not in visites) : visites.append(u) ajouter_pile(P,u) trouve = True # voisin de v non deja visite trouv ́e break if len(list(T.neighbors(v))) == 1: print(v) if not trouve : enlever_sommet_pile(P) if len(list(T.neighbors(v))) == 2: print(v) return visites print("=========================== Exo 3 ===========================") print(parcours_infixe(ArbreBin,1))