1. 程式人生 > >用一維陣列的無向圖寫Prim演算法(用最小堆優化)

用一維陣列的無向圖寫Prim演算法(用最小堆優化)

#include <stdio.h>
#include <malloc.h>

#define true 1
#define false 0
#define INFINITY 1000000
#define MaxVertexNum 10000
#define MaxArcNum 100000

int Visite[MaxVertexNum];
struct ArcStruct {
    int v1, v2, dist;
};
struct GraphStruct {//建立一個最簡單的無向圖
    int vexnum, arcnum;
    int dist[MaxArcNum];
};
struct MinHeapStruct {
    int size;
    struct ArcStruct a[MaxArcNum];
};
typedef struct GraphStruct* Graph;
typedef struct MinHeapStruct* MinHeap;
typedef struct ArcStruct* Edge;

Graph createGraph();
void initializeGraph( Graph G );
int prim( Graph G, int u );
void swap( int *p1, int *p2 );
int computeNum( int a );
void assignEdge( Edge e, int v1, int v2, int dist );
Edge deleteMinHeap( MinHeap h );

void insertMinHeap( MinHeap h, Edge e );
void swapHeapNode ( Edge e1, Edge e2 );
void assignHeapNode( Edge e1, Edge e2 );

int main( void ) {

    Graph G = createGraph();
    int i = 0;
    int V1, V2;
    int dist;
    int num = 0;
    FILE *fp = fopen("kruskal2.txt", "r");
    int mindist = 0;
    for( i = 0; i < G->arcnum; i++ ) {
        fscanf(fp, "%d %d %d", &V1, &V2, &dist);
        if( V1 < V2 ) {
            swap( &V1, &V2 );
        }
        num = computeNum( V1-1 ) + V2-1;
        G->dist[num] = dist;
    }
    //printf("%d %d", G->dist[19], G->dist[20]);
    mindist = prim( G, 0 );

    //printf("%d", mindist);

    return 0;
}

Graph createGraph() {
    Graph G = ( Graph )malloc( sizeof( struct GraphStruct ) );
    initializeGraph( G );
    return G;
}
void initializeGraph( Graph G ) {
    int i = 0;
    int n = 0;
    FILE* fp = fopen("kruskal1.txt", "r");
    fscanf(fp, "%d %d", &G->vexnum, &G->arcnum);
    n = computeNum( G->vexnum );
    for( i = 0; i < n; i++ ) {
        G->dist[i] = INFINITY;
    }
    for( i = 0; i < G->vexnum; i++ ) {
        Visite[i] = false;//好像這裡也可以提出來一個函式
    }

}
int prim( Graph G, int u ) {
    MinHeap h = ( MinHeap )malloc( sizeof(struct MinHeapStruct) );
    h->size = 0;
    h->a[0].dist = -INFINITY;
    Visite[u] = true;
    int mindist = 0;
    Edge e = ( Edge )malloc( sizeof(struct ArcStruct) );

    //make all edges of u into h
    int num, i;
    num = computeNum( u );
    for( i = 0; i < u; i++ ) {
        if( G->dist[num] != INFINITY ) {
            assignEdge( e, u, i, G->dist[num] );
            insertMinHeap( h, e );
        }
        num++;
    }
    for( i = u+1; i < G->vexnum; i++ ) {
        num = computeNum( i ) + u;
        if( G->dist[num] != INFINITY ) {
            assignEdge( e, u, i, G->dist[num] );
            insertMinHeap( h, e );
        }
    }
    //next: MinHeap brings minest dist out, until empty.
    while( h->size != 0 ) {// deleteHeap only  returns one element, so union what need
        e = deleteMinHeap( h );
        if( !Visite[e->v2] ) {
            //make all edges of e->v2 into h
            u = e->v2;
            Visite[u] = true;
            mindist += e->dist;
            num = computeNum( u );
            for( i = 0; i < u; i++ ) {
                if( G->dist[num] != INFINITY && !Visite[i] ) {
                    assignEdge( e, u, i, G->dist[num] );
                    insertMinHeap( h, e );
                }
                num++;
            }
            for( i = u+1; i < G->vexnum; i++ ) {
                num = computeNum( i ) + u;
                if( G->dist[num] != INFINITY && !Visite[i] ) {
                    assignEdge( e, u, i, G->dist[num] );
                    insertMinHeap( h, e );
                }
            }
        }
    }

    return mindist;
}
void assignEdge( Edge e, int v1, int v2, int dist ) {
    e->v1 = v1;
    e->v2 = v2;
    e->dist = dist;
}
void insertMinHeap( MinHeap h, Edge e ) {
    if( h->size == 0 ) {
        assignHeapNode( &(h->a[++h->size]), e );
        return;
    }
    h->size++;
    int parent, child = h->size;
    assignHeapNode( &(h->a[child]), e );

    for( parent = h->size/2; parent >= 1; parent = child/2 ) {
        if( h->a[parent].dist <= h->a[child].dist ) { break; }
        swapHeapNode( &h->a[parent], &h->a[child] );
        child = parent;
    }
}
Edge deleteMinHeap( MinHeap h ) {
    Edge e = ( Edge )malloc( sizeof(struct ArcStruct) );
    assignHeapNode( e, &(h->a[1]) );
    assignHeapNode( &(h->a[1]), &(h->a[h->size]) );
    h->size--;
    int parent, child;

    for( parent = 1; parent*2 <= h->size; parent = child ) {
        child = parent*2;
        if( child < h->size && (h->a[child+1].dist < h->a[child].dist) ) { child++; }
        if( h->a[parent].dist <= h->a[child].dist ) { break; }
        swapHeapNode( &(h->a[parent]), &(h->a[child]) );
    }

    return e;
}
void assignHeapNode( Edge e1, Edge e2 ) {
    e1->dist = e2->dist;
    e1->v1 = e2->v1;
    e1->v2 = e2->v2;
}
void swapHeapNode ( Edge e1, Edge e2 ) {
    Edge e3 = ( Edge )malloc( sizeof( struct ArcStruct) );
    assignHeapNode( e3, e2 );
    assignHeapNode( e2, e1 );
    assignHeapNode( e1, e3 );
}
int computeNum( int a ) {
    return a*(a-1)/2;
}
void swap( int *p1, int *p2 ) {
    int tmp = 0;
    tmp = *p2;
    *p2 = *p1;
    *p1 = tmp;
}
水平太低了。寫得很慢。Prim中間有一段沒有優化,但是,我知道了,用鄰接表不好寫(反正我是沒寫出來),如果是無向圖的話我認為最好還是用一維陣列的無向圖再加上這個演算法。其中過程容易錯,唉。不多說。