Commit 842f99c9 authored by Paffenholz, Andreas's avatar Paffenholz, Andreas
Browse files

some comments in code

parent a2da65b2
......@@ -12,27 +12,43 @@
void dijkstra (struct network * g, int start) {
struct heap * h = init_heap(3, g->n_nodes);
// initializize a heap as priotity queue
// the heap keeps the node indices, not pointers to nodes
struct heap * h = init_heap(3);
// we need a secon list that tells us the current position of a node in the heap
int * heap_index = (int *)malloc(g->n_nodes * sizeof(int));
for ( int i = 0; i < g->n_nodes; ++i) {
heap_index[i] = 0;
}
// put root into heap
// the root ha no predecessor, we mark this by -1
// elements not in the heap implicitly have distance 0
push(h, heap_index, start, 0);
g->nodes[start]->pred=-1;
g->nodes[start]->dist=0;
g->nodes[start]->dist= 0;
while (h->length) {
// get the element with smallest distance
int node_index = pop(h, heap_index);
struct node * node = g->nodes[node_index];
node->visited = 1;
node->visited = 1; // mark the current node as visited
// now update distances to neighbors if necessary
for (int j = 0; j < node->n_outgoing_edges; j++) {
struct edge * e = node->outgoing_edges[j];
struct node * neighbor = g->nodes[e->head];
// we check if we have already seen the node,
// then we do nothing, this node has already the correct distance
// else we check if going to the node via the current one
// creates a shorter path
if (!neighbor->visited && node->dist + e->weight <= neighbor->dist) {
neighbor->pred = node_index;
neighbor->dist = node->dist + e->weight;
// if its index in the heap is still zero,
// then the node is not yet in the heap (still distance 0)
// In that case we push with current distance
// else we adjust the distance at the node
if ( heap_index[e->head] == 0 )
push(h, heap_index, e->head, neighbor->dist);
else
......@@ -40,10 +56,14 @@ void dijkstra (struct network * g, int start) {
}
}
}
// cleanup
free(heap_index);
free_heap(h);
}
// fill an array with the predecessors
// once the algorithm of Dijkstra has run
void predecessors(struct network * g, int * pred) {
for ( int i = 0; i < g->n_nodes; ++i ) {
pred[i] = g->nodes[i]->pred;
......
......@@ -17,7 +17,14 @@
#include "network.h"
#include "heap.h"
// compute distances and store those
// and predecessors on the network
// second argument is the start node
void dijkstra (struct network *, int);
// extract the predecessors from a network
// on which Dijkstra's algorithm has run
// second argument returns array with predecessors
void predecessors(struct network *, int *);
#endif
\ No newline at end of file
......@@ -30,13 +30,17 @@ int main(int argc, char** argv) {
int start = atoi(argv[2]);
struct network * g = read_network(infile);
// run algorithm
dijkstra(g,start);
// print distance for each node
printf("The nodes have distance \n");
for ( int i = 0; i < g->n_nodes; ++i ) {
printf("%d: %d\n", i, g->nodes[i]->dist);
}
// get predecessors
int * pred = (int *)malloc(g->n_nodes * sizeof(int));
predecessors(g,pred);
......@@ -46,8 +50,9 @@ int main(int argc, char** argv) {
printf("(%d, %d)\n", pred[i],i);
}
}
free(pred);
free(pred);
free_network(g);
return 0;
}
\ No newline at end of file
......@@ -14,7 +14,7 @@
#include "heap.h"
struct heap * init_heap (int n, int index_size) {
struct heap * init_heap (int n) {
struct heap * h = (struct heap *)malloc(sizeof (struct heap));
h->data = (int *)malloc((n+1) * sizeof (int));
......@@ -72,10 +72,14 @@ void decrease_key (struct heap * h, int * heap_index, int node, int key ) {
void push (struct heap * h, int * heap_index, int node, int key ) {
// adjust heap size if necessary
if ( h->size <= h->length )
resize_heap(h);
// find the new position before inserting
// so upheap only needs to shift elems downwards
int insert_pos = upheap(h, heap_index, h->length++, key);
// move into place
h->data[insert_pos] = node;
h->key[insert_pos ] = key;
heap_index[node] = insert_pos;
......@@ -107,9 +111,16 @@ int pop (struct heap * h, int * heap_index) {
return INT_MIN;
}
//store the return
int node = h->data[0];
h->length--;
// the element we need to downheap
// is in position h->length, we don't copy it into pos 0
// then downheap only needs to move elements upward
// until we have found the new position
int j = downheap(h,heap_index,0);
// move the element into position
// and fix head_index
h->data[j] = h->data[h->length];
h->key[j] = h->key[h->length];
heap_index[h->data[h->length]] = j;
......
......@@ -18,14 +18,25 @@ struct heap {
int size;
};
struct heap * init_heap (int, int);
// initialize a heap of given size
struct heap * init_heap (int);
void free_heap(struct heap *);
void print_heap(struct heap * h);
void push(struct heap *, int *, int, int);
// push element
// a array of element indices,
// node node index
// key distance at node
void push(struct heap * h, int * a, int node, int key);
// return root element
int pop(struct heap *, int *);
void decrease_key (struct heap *, int *, int, int);
// adjust key at element
// a array of element indices,
// node node index
// new_key adjusted distance at node
void decrease_key (struct heap * h, int * a, int node, int new_key);
#endif
\ No newline at end of file
......@@ -21,18 +21,16 @@ struct edge * init_edge(int head, int weight) {
e->chosen = 1;
return e;
}
struct node * init_node() {
struct node * n = (struct node *)malloc(sizeof(struct node));
n->outgoing_edges = NULL;
n->n_outgoing_edges = 0;
n->edge_struct_size = 0;
n->visited = 0;
n->dist = INT_MAX;
n->dist = INT_MAX; // no real distance should be that high
n->pred = -1;
return n;
}
struct network * init_network(int n_nodes) {
struct network * g = (struct network *)malloc(sizeof(struct network));
g->nodes = (struct node **)malloc(n_nodes * sizeof(struct node *));
......@@ -64,6 +62,7 @@ void free_network(struct network * g) {
free(g);
}
// checks if a given edge is in the network
int edge_exists(struct network * g, int tail, int head) {
struct node * n = g->nodes[tail];
......@@ -75,25 +74,39 @@ int edge_exists(struct network * g, int tail, int head) {
return 0;
}
// adds one edge to a network if not yet present
int add_edge(struct network * g, int tail, int head, int weight) {
// if nodes don't exist do nothing
if ( tail >= g->n_nodes || head >= g->n_nodes ) {
return -1;
}
struct node * n = g->nodes[tail];
// if edge exists to nothing
if ( edge_exists(g,tail,head) ) {
return 1;
}
// we may have to increase the storage size
if (n->n_outgoing_edges >= n->edge_struct_size ) {
n->edge_struct_size = n->edge_struct_size ? n->edge_struct_size * 3 / 2 : 3;
n->outgoing_edges = realloc(n->outgoing_edges, n->edge_struct_size * sizeof (struct edge *));
}
// add the edge
n->outgoing_edges[n->n_outgoing_edges++] = init_edge(head,weight);
return 0;
}
/* for a network with n nodes we expect a file in the form
---
n
tail-1 head-1 weight-1
tail-2 head-2 weight-2
...
tail-n head-n weight-n
---
*/
struct network * read_network(char* filename) {
const char s[2] = " ";
FILE *infile;
......
......@@ -32,8 +32,12 @@ struct network {
int n_nodes;
};
struct network * init_network(int);
// initialize a network of size n
struct network * init_network(int n);
// read network from file
struct network * read_network(char*);
void free_network(struct network *);
#endif
\ No newline at end of file
......@@ -19,11 +19,14 @@
#include "graham_scan.h"
// check for left turn
// by computing det of two vectors -> orientation
int ccw(struct point* p1, struct point* p2, struct point* p3) {
int turn = (p2->x - p1->x)*(p3->y - p1->y) - (p2->y - p1->y)*(p3->x - p1->x);
return turn;
}
// among those with minimal y finde the one with minimal x
int find_min(struct pointSet* pointset) {
struct point* point = pointset->points;
struct point* tmp = pointset->points;
......@@ -46,22 +49,32 @@ int find_min(struct pointSet* pointset) {
void graham_scan(struct pointSet* pointset, int* verts, int* n_verts) {
// some special cases
// no points -> no convex hull
if ( pointset->n_points == 0 ) {
*n_verts = 0;
verts[0] = 0;
return;
}
// a single point is its own convex hull
if ( pointset->n_points == 1 ) {
*n_verts = 1;
verts[0] = 0;
return;
}
// now start graham scan
// find start node
int index = find_min(pointset);
//place it at the beginning of the list
swap(pointset, 0, index);
// compute angles
angles(pointset);
// sort
// we need distance to the start node as a tie breaker
// if two points are collinear with the start node
struct point* start = (struct point*)malloc(sizeof(struct point));
start->x = (pointset->points[0]).x;
start->y = (pointset->points[0]).y;
......@@ -74,25 +87,32 @@ void graham_scan(struct pointSet* pointset, int* verts, int* n_verts) {
free(start);
// we build up a list of nodes on the convex hull
// head gives the current last known node
// of which we assume it is on the convex hull
// just decrease head if we need to backtrack
verts[0] = 0;
verts[1] = 1;
int head = 1;
for(int i = 2; i <= pointset->n_points; i++){
// backtracking until we have left turn
while(head >= 1 &&
ccw(pointset->points+verts[head-1],
pointset->points+verts[head],
pointset->points+(i % pointset->n_points)) <= 0 ) {
pointset->points+(i % pointset->n_points)) <= 0 )
head--;
}
// add point, unless we have closed the polygon
if ( i != pointset->n_points )
verts[head+1] = i;
head++;
}
// if we have backtracked to the start node, but there is another node,
// then put this as the next node
if ( head == 1 ) {
if ( pointset->points->x != (pointset->points+verts[1])->x || pointset->points->y != (pointset->points+verts[1])->y )
head++;
......
......@@ -13,6 +13,11 @@
#include "point_set.h"
// do a graham scan on the set of points
// given in the point set
// returns indices of points on the convex hull
// and total number of vertives
// in the last two arguments
void graham_scan(struct pointSet*, int*, int*);
#endif
\ No newline at end of file
......@@ -47,12 +47,18 @@ int compare(const void* a, const void* b, void* c) {
return (c1 > c2) - (c2 > c1);
}
// swap two points in the list
void swap(struct pointSet* pointset, int i1, int i2) {
struct point tmp = pointset->points[i1];
pointset->points[i1] = pointset->points[i2];
pointset->points[i2] = tmp;
}
// compute a representative of the angle for the vector from p2 tp p1 with the x-axis
// we use the negative of the squared cosine,
// where we preserve the sign of cos before we square
// this is a rational number, which we store as (num,denom)
// special case: start node, make it smallest, so it comes first
void angle(struct point* p1, struct point* p2, int* num, int* denom) {
int dot = p2->x-p1->x;
*num = (dot<0?-1:1)*dot*dot;
......@@ -63,6 +69,8 @@ void angle(struct point* p1, struct point* p2, int* num, int* denom) {
}
}
// return list of all angles of
// a ray from the start node to another node with the x-axis
void angles(struct pointSet* pointset) {
int num, denom;
(pointset->points[0]).angle_num = -1;
......@@ -78,6 +86,9 @@ void angles(struct pointSet* pointset) {
}
}
// read a list of points in the plane
// with integral coeffs
// each line gives coords (x,y) for one point
struct pointSet* read_input(char* filename) {
FILE *infile;
infile = fopen (filename, "r");
......@@ -138,6 +149,8 @@ void print_points(struct pointSet* pointset, int show_angle ) {
printf("---------------------------------\n");
}
// write result to a file
// gives a list of points on the convex hull
void store_verts(struct pointSet* pointset, int* verts, int n_verts, char* filename) {
FILE* file = fopen(filename, "w");
fprintf(file, "%d\n", n_verts);
......
......@@ -29,10 +29,22 @@ int compare(void*, const void*, const void*);
int compare(const void*, const void*, void*);
#endif
// read from file
struct pointSet* read_input(char*);
void store_verts(struct pointSet*, int*, int, char*);
// store the vertices of the convex hull in a file
// p original point set
// v array of indices of the vertices among p
// nv size of nv
// f filename
void store_verts(struct pointSet* p, int* v, int nv, char* f);
// swap two points in a point set given by indices
void swap(struct pointSet* , int, int);
// compute the angles of all points in a pointset
// of the ray from the first point to all other points
// to the x-axis
void angles(struct pointSet* );
void print_points(struct pointSet*,int);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment