void pq_delete_min(PQ pq, void *retval) { int floater; /* previous loser floating down */ int small_child; /* smaller child of floater */ assert(!pq_is_empty(pq)); /* first copy out the winner */ memcpy(retval, REF(pq, 0), pq->element_length); --(pq->n); if(pq_is_empty(pq)) { /* pq empty, nothing to do */ return; } /* else */ memcpy(REF(pq, 0), REF(pq, pq->n), pq->element_length); floater = 0; for(;;) { /* find smaller child of floater */ if(Child(floater, 0) >= pq->n) { return; /* no children, bail out */ } else if(Child(floater, 1) >= pq->n) { small_child = Child(floater, 0); } else if(pq->compare(REF(pq, Child(floater, 0)), REF(pq, Child(floater, 1))) < 0) { small_child = Child(floater, 0); } else { small_child = Child(floater, 1); } /* is floater <= small_child? */ if(pq->compare(REF(pq, floater), REF(pq, small_child)) <= 0) { /* yes, we are done */ return; } else { /* no, swap and continue floating down */ pq_swap(pq, floater, small_child); floater = small_child; } } }
PCB* pq_dequeue(process_queue* pq) { if (pq_is_empty(pq)) return NULL; PCB* ret = NULL; ret = pq->head; ret->p_next = NULL; pq->head = (pq->head)->p_next; if (pq->head == NULL) pq->tail = NULL; return ret; }
void pq_enqueue(PCB* next, process_queue* pq) { assert(pq != NULL && next != NULL); next->p_next = NULL; if (pq_is_empty(pq)) { pq->head = next; pq->tail = pq->head; } else { (pq->tail)->p_next = next; pq->tail = next; } }
void dijkstra(graph_t *graph, int source, int *dist, int *parent) { push_data_t data; pq_elem_t e; int n, i; if (!dist) return; data.dist = dist; data.pq = pq_create(sizeof(pq_elem_t), pq_elem_compare); if (!data.pq) return; n = graph_vertex_count(graph); for (i=0; i<n; i++) dist[i] = INT_MAX; if (parent) { for (i=0; i<n; i++) { parent[i] = DIJKSTRA_NULL_PARENT; } } push(graph, source, source, -INT_MAX, &data); while(! pq_is_empty(data.pq)) { pq_delete_min(data.pq, &e); printf("%d -> %d: %d\n", e.source, e.sink, e.distance); if (dist[e.sink] == INT_MAX) { /* new edge */ dist[e.sink] = e.distance; if (parent) parent[e.sink] = e.source; graph_foreach_weighted(graph, e.sink, push, &data); } } pq_destroy(data.pq); }
/************************************************************* * Support Functionality *************************************************************/ static int compute_shortest_path_dijkstra(netloc_data_collection_handle_t *handle, netloc_node_t *src_node, netloc_node_t *dest_node, int *num_edges, netloc_edge_t ***edges) { int exit_status = NETLOC_SUCCESS; int i; pq_queue_t *queue = NULL; int *distance = NULL; bool *not_seen = NULL; netloc_node_t *node_u = NULL; netloc_node_t *node_v = NULL; netloc_node_t **prev_node = NULL; netloc_edge_t **prev_edge = NULL; int alt; int idx_u, idx_v; int num_rev_edges; netloc_edge_t **rev_edges = NULL; struct netloc_dt_lookup_table_iterator *hti = NULL; netloc_node_t *cur_node = NULL; unsigned long key_int; // Just in case things go poorly below (*num_edges) = 0; (*edges) = NULL; /* * Allocate some data structures */ queue = pq_queue_t_construct(); if( NULL == queue ) { fprintf(stderr, "Error: Failed to allocate the queue\n"); exit_status = NETLOC_ERROR; goto cleanup; } distance = (int*)malloc(sizeof(int) * netloc_lookup_table_size(handle->node_list)); if( NULL == distance ) { fprintf(stderr, "Error: Failed to allocate the distance array\n"); exit_status = NETLOC_ERROR; goto cleanup; } not_seen = (bool*)malloc(sizeof(bool) * netloc_lookup_table_size(handle->node_list)); if( NULL == not_seen ) { fprintf(stderr, "Error: Failed to allocate the 'not_seen' array\n"); exit_status = NETLOC_ERROR; goto cleanup; } prev_node = (netloc_node_t**)malloc(sizeof(netloc_node_t*) * netloc_lookup_table_size(handle->node_list)); if( NULL == prev_node ) { fprintf(stderr, "Error: Failed to allocate the 'prev_node' array\n"); exit_status = NETLOC_ERROR; goto cleanup; } prev_edge = (netloc_edge_t**)malloc(sizeof(netloc_edge_t*) * netloc_lookup_table_size(handle->node_list)); if( NULL == prev_edge ) { fprintf(stderr, "Error: Failed to allocate the 'prev_edge' array\n"); exit_status = NETLOC_ERROR; goto cleanup; } /* * Initialize the data structures */ // Make sure to initialize the arrays for( i = 0; i < netloc_lookup_table_size(handle->node_list); ++i){ distance[i] = INT_MAX; not_seen[i] = true; prev_node[i] = NULL; prev_edge[i] = NULL; } i = 0; hti = netloc_dt_lookup_table_iterator_t_construct(handle->node_list); while( !netloc_lookup_table_iterator_at_end(hti) ) { cur_node = (netloc_node_t*)netloc_lookup_table_iterator_next_entry(hti); if( NULL == cur_node ) { break; } if( cur_node == src_node ) { pq_push(queue, 0, cur_node); distance[i] = 0; } else { pq_push(queue, INT_MAX, cur_node); distance[i] = INT_MAX; } not_seen[i] = true; prev_node[i] = NULL; prev_edge[i] = NULL; cur_node->__uid__ = i; ++i; } /* * Search */ while( !pq_is_empty(queue) ) { //pq_dump(queue); // Grab the next hop node_u = pq_pop(queue); // Mark as seen idx_u = -1; i = 0; idx_u = node_u->__uid__; not_seen[idx_u] = false; // For all the edges from this node for(i = 0; i < node_u->num_edges; ++i ) { node_v = NULL; idx_v = -1; // Lookup the "dest" node node_v = node_u->edges[i]->dest_node; idx_v = node_v->__uid__; // If the node has been seen, skip if( !not_seen[idx_v] ) { continue; } // Otherwise check to see if we found a shorter path // Future Work: Add a weight factor other than 1. // Maybe calculated based on speed/width alt = distance[idx_u] + 1; if( alt < distance[idx_v] ) { distance[idx_v] = alt; prev_node[idx_v] = node_u; prev_edge[idx_v] = node_u->edges[i]; // Adjust the priority queue as needed pq_reorder(queue, alt, node_v); } } } /* * Reconstruct the path by picking up the edges * The edges will be in reverse order (dest to source). */ num_rev_edges = 0; rev_edges = NULL; // Find last hop SUPPORT_CONVERT_ADDR_TO_INT(dest_node->physical_id, handle->network->network_type, key_int); node_u = netloc_lookup_table_access_with_int( handle->node_list, dest_node->physical_id, key_int); idx_u = node_u->__uid__; node_v = NULL; idx_v = -1; while( prev_node[idx_u] != NULL ) { // Find the linking edge if( node_u != dest_node) { for(i = 0; i < node_u->num_edges; ++i ) { if( node_v->physical_id_int == node_u->edges[i]->dest_node->physical_id_int ) { ++num_rev_edges; rev_edges = (netloc_edge_t**)realloc(rev_edges, sizeof(netloc_edge_t*) * num_rev_edges); if( NULL == rev_edges ) { fprintf(stderr, "Error: Failed to re-allocate the 'rev_edges' array with %d elements\n", num_rev_edges); exit_status = NETLOC_ERROR; goto cleanup; } rev_edges[num_rev_edges-1] = node_u->edges[i]; break; } } } node_v = node_u; idx_v = idx_u; // Find the next node SUPPORT_CONVERT_ADDR_TO_INT(prev_node[idx_u]->physical_id, handle->network->network_type, key_int); node_u = netloc_lookup_table_access_with_int( handle->node_list, prev_node[idx_u]->physical_id, key_int); idx_u = node_u->__uid__; } for(i = 0; i < src_node->num_edges; ++i ) { if( NULL == node_v ) { fprintf(stderr, "Error: This should never happen, but node_v is NULL at line %d in file %s\n", __LINE__, __FILE__); exit_status = NETLOC_ERROR; goto cleanup; } if( node_v->physical_id_int == src_node->edges[i]->dest_node->physical_id_int ) { ++num_rev_edges; rev_edges = (netloc_edge_t**)realloc(rev_edges, sizeof(netloc_edge_t*) * num_rev_edges); if( NULL == rev_edges ) { fprintf(stderr, "Error: Failed to re-allocate the 'rev_edges' array with %d elements\n", num_rev_edges); exit_status = NETLOC_ERROR; goto cleanup; } rev_edges[num_rev_edges-1] = node_u->edges[i]; break; } } /* * Copy the edges back in correct order */ (*num_edges) = num_rev_edges; (*edges) = (netloc_edge_t**)malloc(sizeof(netloc_edge_t*) * (*num_edges)); if( NULL == (*edges) ) { fprintf(stderr, "Error: Failed to allocate the edges array\n"); exit_status = NETLOC_ERROR; goto cleanup; } for( i = 0; i < num_rev_edges; ++i ) { (*edges)[i] = rev_edges[num_rev_edges-1-i]; //printf("DEBUG: \t Edge: %s\n", netloc_pretty_print_edge_t( (*edges)[i] ) ); } /* * Cleanup */ cleanup: if( NULL != queue ) { pq_queue_t_destruct(queue); queue = NULL; } if( NULL != rev_edges ) { free(rev_edges); rev_edges = NULL; } if( NULL != distance ) { free(distance); distance = NULL; } if( NULL != not_seen ) { free(not_seen); not_seen = NULL; } if( NULL != prev_node ) { free(prev_node); prev_node = NULL; } if( NULL != prev_edge ) { free(prev_edge); prev_edge = NULL; } netloc_dt_lookup_table_iterator_t_destruct(hti); return exit_status; }
// The "standard" version of Dijkstra's, // ie the one that is the same as shown in the lecture // see page 16 of lec08.pdf // Comments starting with //* are the lines from pseudocode in page 16 // Print out the shortest paths from the source node to each other node void dijkstras(graph_t *g, int v0) { int v; int u, w; double weight; // generous vars for edge (u->w,weight) // To store current min-costs and previous vertices int *prev; // prev[v]=u if v was reached from u double *dist; // dist[v]= current best dist from source to v bool *inQ; // a helping array for quick check if v in Q assert(prev= malloc( g->n * sizeof(*prev) ) ); assert(dist= malloc( g->n * sizeof(*dist) ) ); assert(inQ= malloc( g->n * sizeof(*inQ) ) ); /* Initialization ------------------------------ */ for (v = 0; v < g->n; v++) { //* foreach v in V prev[v] = NO_PREV; //* prev[v]= nil dist[v] = INFINITY; //* dist[v]= infinity } dist[v0] = 0; //* dist[v0]=0 //* Q = InitPriorityQueue(V) pq_t *Q = new_pq(); for (v = 0; v < g->n; v++) { pq_enqueue(Q, v, dist[v]); inQ[v]= true; // marks v as being inside the queue } /* Main loop of Dijkstra's ------------------------------ */ // buddy array of n elements to store the adjacency list of a vertex data_t *neighbours; int n; assert(neighbours= malloc( g->n * sizeof(*neighbours) ) ); while (!pq_is_empty(Q)) { //* while Q is non empty do // remove min vertex u = pq_remove_min(Q); //* u= EjectMin(Q) inQ[u]= false; // marks u as not in Q anymore // With this vertex u: // first, copies the adjacency list of u to array neighbours n= list_2_array(g->vs[u].A, neighbours); for (v = 0; v < n; v++) { //* for each (u,w) in E do w = neighbours[v].id; // having:edge (u-->w,weight) weight= neighbours[v].weight; //* if (w in Q && dist[v]+weight(u,w) <dist[v] if ( inQ[w] && dist[w] > dist[u]+weight) { dist[w] = dist[u]+weight; //* dist[w]= dist[u]+weight(u,v) prev[w] = u; //* prev[w]= u //* Update(Q, w, dist[w]) pq_update(Q, w, dist[w]); } } } /* Prints out all shortest paths ------------------------------ */ print_all_path(dist, prev, g, v0); // free the dynamic data structures free(dist); free(prev); free(neighbours); free_pq(Q); }
// NON-standard version of Dijkstra's: // Print out the shortest paths from the source node to each other node void dijkstras(graph_t *g, int source) { int i; int u, v; double weight; // generous vars for edge (u->v,weight) double new_weight; // To store current min-costs and previous vertices int *prev; // prev[v]=u if v was reached from u double *dist; // dist[v]= current best dist from source to v assert(prev= malloc( g->n * sizeof(*prev) ) ); assert(dist= malloc( g->n * sizeof(*dist) ) ); /* Initialization ------------------------------ */ for (i = 0; i < g->n; i++) { prev[i] = NO_PREV; dist[i] = INFINITY; } dist[source] = 0; // enqueue "source" - the only one that has limitted dist pq_t *queue = new_pq(); pq_enqueue(queue, source, dist[source]); /* Main loop of Dijkstra's ------------------------------ */ // buddy array of n elements to store the adjacency list of a vertex data_t *neighbours; int n; assert(neighbours= malloc( g->n * sizeof(*neighbours) ) ); while (!pq_is_empty(queue)) { // remove min vertex u = pq_remove_min(queue); // With this vertex u: // * first, copies the adjacency list of u to array neighbours n= list_2_array(g->vs[u].A, neighbours); // * then, inspects each of the neighbour for (i = 0; i < n; i++) { v = neighbours[i].id; // looking at edge (u-->v,weight) weight = neighbours[i].weight; new_weight = dist[u] + weight; // if v was reached before with a better outcome // then we just ignore the edge u-->v if ( dist[v] <= new_weight) continue; // updates vertex v in the queue if (dist[v] == INFINITY) { // if v never been reached before, adds it to queue pq_enqueue(queue, v, new_weight); } else { // otherwise, updates weight of v in the queue // note that the update must be successful if ( !pq_update(queue, v, new_weight) ){ fprintf(stderr, "Internal error: Something wrong " "in code or in data (such as negative weight)\n"); exit(EXIT_FAILURE); } } // now updaes dist[v] and prev[v] dist[v] = new_weight; prev[v] = u; } } /* Prints out all shortest paths ------------------------------ */ print_all_path(dist, prev, g, source); // free the dynamic data structures free(dist); free(prev); free(neighbours); free_pq(queue); }