📄 emst.c
字号:
/*********************************************************************** File: emst.c Rev: b-1 Date: 02/28/2001 Copyright (c) 1993, 2001 by Martin Zachariasen & David M. Warme************************************************************************ Routines to compute Euclidean Minimum Spanning Trees.************************************************************************ Modification Log: a-1: 11/10/98 martinz : Created. b-1: 02/28/2001 warme : Renamed build_edges, and eliminated its 3rd "at_least" : parameter. Build complete graph when N < 10. : Use common routines now in mst.c. : Fix duplicate points problem.************************************************************************/#include "dsuf.h"#include "steiner.h"#define ANSI_DECLARATORS#define REAL coord_t#include "triangle.h"/* * Global Routines */int euclidean_mst (struct pset *, struct edge *);dist_t euclidean_mst_length (struct pset *);/* * External References */ /* none *//* * Local Routines */static int build_euclidean_edges (struct pset *, struct edge **);static int * heapsort_x (struct pset *);/* * This routine computes the total length of the Euclidean Minimum * Spanning Tree of the given set of points. */ dist_teuclidean_mst_length (struct pset * pts /* IN - point set to find MST length of. */){int i;int nedges;dist_t total;struct edge * ep;struct edge * edges; edges = NEWA (pts -> n - 1, struct edge); nedges = euclidean_mst (pts, &edges [0]); if (nedges NE pts -> n - 1) { fatal ("euclidean_mst_length: Bug 1."); } total = 0; ep = &edges [0]; for (i = 0; i < nedges; i++) { total += ep -> len; ++ep; } free ((char *) edges); return (total);}/* * This routine computes an Euclidean Minimum Spanning Tree for the * given point set. The output is a list of edges. * * The "Triangle" package by Jonathan Richard Shewchuk is used * to provide the Delaunay triangulation for the set of points. */ inteuclidean_mst (struct pset * pts, /* IN - point set. */struct edge * edges /* OUT - edge list. */){int nedges;int mst_edge_count;struct edge * edge_array; nedges = build_euclidean_edges (pts, &edge_array); mst_edge_count = mst_edge_list (pts -> n, nedges, &edge_array [0], edges); free ((char *) edge_array); return (mst_edge_count);}/* * This routine builds an edge-list containing all edges in * the Delaunay triangulation of the set of points. */ static intbuild_euclidean_edges (struct pset * pts, /* IN - set of points */struct edge ** edges_out /* OUT - edge list */){int i, i1;int j, j1;int k;int n;int nedges;int ndup;struct edge * edges;struct point * p1;struct point * p2;int * order;int * orig_vnum;bool * dflags;struct edge * zedges;struct triangulateio in, out, vorout; n = pts -> n; if (n < 10) { /* Build the complete graph... */ nedges = n * (n - 1) / 2; edges = NEWA (nedges, struct edge); *edges_out = edges; p1 = &(pts -> a [0]); for (i = 0; i < n; i++, p1++) { p2 = p1 + 1; for (j = i + 1; j < n; j++, p2++) { edges -> len = EDIST (p1, p2); edges -> p1 = ((pnum_t) i); edges -> p2 = ((pnum_t) j); ++edges; } } return (nedges); } /* Triangle does a "good" job when given duplicate points -- it */ /* emits edges to only one of the given coincident points. */ /* This is bad for us, however, since we want a fully connected */ /* MST, and cannot get one if there are vertices for which we */ /* have no incident edges. Therefore we must detect all */ /* duplicate points and manually generate one zero-length edge */ /* for each (copies 2 through K of a point each have an edge to */ /* the first copy of the point). */ order = heapsort_x (pts); dflags = NEWA (n, bool); memset (dflags, FALSE, n * sizeof (dflags [0])); zedges = NEWA (n, struct edge); memset (zedges, 0, n * sizeof (zedges)); ndup = 0; for (i = 0; i < n - 1; ) { i1 = order [i]; p1 = &(pts -> a [i1]); for (j = i; ; ) { ++j; if (j >= n) break; j1 = order [j]; p2 = &(pts -> a [j1]); if (p1 -> x NE p2 -> x) break; if (p1 -> y NE p2 -> y) break; /* Point j1 is a duplicate of point i1. The */ /* sort also guarantees that i1 < j1. Omit */ /* point j1. */ dflags [j1] = TRUE; /* Generate zero-length edge (i1,j1). */ zedges [ndup].len = 0.0; zedges [ndup].p1 = i1; zedges [ndup].p2 = j1; ++ndup; } i = j; } free (order); /* Get array to map duplicate-free points back to originals. */ orig_vnum = NEWA (n, int); /* Set up data structure to call triangle. */ in.pointlist = NEWA (2 * n, coord_t); j = 0; for (i = 0; i < n; i++) { if (dflags [i]) continue; in.pointlist [2*j ] = pts -> a [i].x; in.pointlist [2*j + 1] = pts -> a [i].y; orig_vnum [j] = i; ++j; } in.numberofpoints = j; free (dflags); in.numberofpointattributes = 0; in.pointattributelist = 0; in.pointmarkerlist = 0; in.numberofsegments = 0; in.numberofholes = 0; in.numberofregions = 0; in.regionlist = 0; out.pointlist = 0; out.edgelist = 0; out.trianglelist = 0; out.neighborlist = 0; triangulate ("zeNBQ", &in, &out, &vorout); free (in.pointlist); free (out.pointlist); free (out.trianglelist); free (out.neighborlist); nedges = out.numberofedges; edges = NEWA (nedges + ndup, struct edge); *edges_out = edges; for (k = 0; k < ndup; k++) { *edges++ = zedges [k]; } free (zedges); for (k = 0; k < nedges; k++) { i = orig_vnum [out.edgelist [2*k ]]; j = orig_vnum [out.edgelist [2*k + 1]]; p1 = &(pts -> a [i]); p2 = &(pts -> a [j]); edges -> len = EDIST (p1, p2); edges -> p1 = ((pnum_t) i); edges -> p2 = ((pnum_t) j); ++edges; } free (out.edgelist); free (orig_vnum); return (nedges + ndup);}/* * Use the heapsort algorithm to sort the given terminals in increasing * order by the following keys: * * 1. X coordinate * 2. Y coordinate * 3. index (i.e., position within input data) * * Of course, we do not move the points, but rather permute an array * of indexes into the points. */ static int *heapsort_x (struct pset * pts /* IN - the terminals to sort */){int i, i1, i2, j, k, n;struct point * p1;struct point * p2;int * index; n = pts -> n; index = NEWA (n, int); for (i = 0; i < n; i++) { index [i] = i; } /* Construct the heap via sift-downs, in O(n) time. */ for (k = n >> 1; k >= 0; k--) { j = k; for (;;) { i = (j << 1) + 1; if (i + 1 < n) { /* Increment i (to right subchild of j) */ /* if the right subchild is greater. */ i1 = index [i]; i2 = index [i + 1]; p1 = &(pts -> a [i1]); p2 = &(pts -> a [i2]); if ((p2 -> x > p1 -> x) OR ((p2 -> x EQ p1 -> x) AND ((p2 -> y > p1 -> y) OR ((p2 -> y EQ p1 -> y) AND (i2 > i1))))) { ++i; } } if (i >= n) { /* Hit bottom of heap, sift-down is done. */ break; } i1 = index [j]; i2 = index [i]; p1 = &(pts -> a [i1]); p2 = &(pts -> a [i2]); if ((p1 -> x > p2 -> x) OR ((p1 -> x EQ p2 -> x) AND ((p1 -> y > p2 -> y) OR ((p1 -> y EQ p2 -> y) AND (i1 > i2))))) { /* Greatest child is smaller. Sift- */ /* down is done. */ break; } /* Sift down and continue. */ index [j] = i2; index [i] = i1; j = i; } } /* Now do actual sorting. Exchange first/last and sift down. */ while (n > 1) { /* Largest is at index [0], swap with index [n-1], */ /* thereby putting it into final position. */ --n; i = index [0]; index [0] = index [n]; index [n] = i; /* Now restore the heap by sifting index [0] down. */ j = 0; for (;;) { i = (j << 1) + 1; if (i + 1 < n) { /* Increment i (to right subchild of j) */ /* if the right subchild is greater. */ i1 = index [i]; i2 = index [i + 1]; p1 = &(pts -> a [i1]); p2 = &(pts -> a [i2]); if ((p2 -> x > p1 -> x) OR ((p2 -> x EQ p1 -> x) AND ((p2 -> y > p1 -> y) OR ((p2 -> y EQ p1 -> y) AND (i2 > i1))))) { ++i; } } if (i >= n) { /* Hit bottom of heap, sift-down is done. */ break; } i1 = index [j]; i2 = index [i]; p1 = &(pts -> a [i1]); p2 = &(pts -> a [i2]); if ((p1 -> x > p2 -> x) OR ((p1 -> x EQ p2 -> x) AND ((p1 -> y > p2 -> y) OR ((p1 -> y EQ p2 -> y) AND (i1 > i2))))) { /* Greatest child is smaller. Sift- */ /* down is done. */ break; } /* Sift down and continue. */ index [j] = i2; index [i] = i1; j = i; } } return (index);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -