1.Prim实现
#include
#include
#define MaxVertices 100
#define INF 65535
int graph[MaxVertices][MaxVertices];
typedef char DataType;
//建立边表
typedef struct node
{
int adjvex; //指向边表结点
struct node *nextarc; //指向下一条边,没有则为NULL
int info; //权值
}ArcNode;
//建立顶点表
typedef struct
{
DataType data[MaxVertices]; //顶点数据
ArcNode *firstarc; //指向该顶点的第一个边表结点
}VerNode;
//建立图
typedef struct
{
VerNode adjlist[MaxVertices];//顶点数组
int n; //总顶点的个数
int e; //总的边数
}ALGraph;
//建立邻接表
void CrateGraph(ALGraph *G)
{
int i,j, k;
int v1, v2; //输入的两个边
int weight; //权值
printf_s("请输入邻接表的总顶点数和边数:");
scanf_s("%d %d", &G->n, &G->e);
for (i = 1; i <= G->n; i++) //prim最小生成树初始化,不用可省略
{
for (j = 1; j <= G->e; j++)
{
graph[i][j] = INF;
}
}
fflush(stdin);
printf_s("请输入顶点(回车结束一个输入)\n");
for (i = 0; i < G->n; i++)
{
gets_s(G->adjlist[i].data, MaxVertices);
G->adjlist[i].firstarc = NULL; //初始化边头没有连接的边表
}
printf_s("请根据顶点的位置从1开始输入两两相邻的边和权值(中间用空格隔开)\n");
for (k = 0; k < G->e; k++)
{
fflush(stdin);
printf_s("第%d个连接点:", k + 1);
scanf_s("%d %d %d", &v1, &v2, &weight); //输入相邻的边和权值
graph[v1][v2] = weight;
graph[v2][v1] = weight;
v1--; v2--; //按顶点排序从1开始,减去1方便数组计算
ArcNode *s = (ArcNode *)malloc(sizeof(ArcNode));
s->info = weight;
s->adjvex = v2;
s->nextarc = G->adjlist[v1].firstarc;
G->adjlist[v1].firstarc = s;
/*s->nextarc = NULL; //尾插法
ArcNode *p;
p = G->adjlist[v1].firstarc;
if (p == NULL)
{
G->adjlist[v1].firstarc = s;
}
else
{
while (p->nextarc)
{
p = p->nextarc;
}
p->nextarc = s;
}*/
}
}
//打印邻接表
void DisGraph(ALGraph *G)
{
int i;
printf_s("序号\t顶点名称\t\t边表\n");
for (i = 0; i < G->n; i++)
{
printf_s("%d\t", i+1); //打印序号
printf_s("%s\t\t->", G->adjlist[i].data); //打印顶点
while (G->adjlist[i].firstarc)
{
printf_s("%d(%d)->", G->adjlist[i].firstarc->adjvex+1, G->adjlist[i].firstarc->info);
G->adjlist[i].firstarc = G->adjlist[i].firstarc->nextarc;
}
printf_s("NULL\n");
}
}
//广度优先遍历
int visited[MaxVertices];
typedef struct LoopQueue
{
int data[MaxVertices];
int front;
int rear;
}Queue, *LQueue;
void InitQueue(LQueue Q){ //初始化队列
Q->front = Q->rear = 0;
}
int QueueisFull(LQueue Q){ //判断队列是否满了
if ((Q->rear + 1) % MaxVertices == Q->front){
return -1; //已满
}
else{
return 1;
}
}
int QueueisEmpty(LQueue Q){//判断队列是否为空
if (Q->front == Q->rear){
return -1;
}
return 1;
}
void EnQueue(LQueue Q, int i){ //入队列
if (!QueueisFull(Q)){
Q->data[Q->rear] = i;
Q->rear = (Q->rear + 1) % MaxVertices; //队尾指针后移
}
}
void DeQueue(LQueue Q, int *k){ //出队列
if (!QueueisEmpty(Q)){
*k = Q->data[Q->front];
Q->front = (Q->front + 1) % MaxVertices;
}
}
void BFS(ALGraph *G)
{
Queue Q;
for (int i = 0; i < G->n; i++)
{
visited[i] = 0;
}
InitQueue(&Q); //初始化队列
for (int i = 0; i < G->n; i++)
{
visited[i] = 1;
printf("%s ", G->adjlist[i].data);
EnQueue(&Q, i);
while (!QueueisEmpty(&Q))
{
DeQueue(&Q, &i); //这里不断的修改i的值!!
ArcNode *e = G->adjlist[i].firstarc; //i顶点的邻接链表的第一个结点
while (e)
{ //e存在时,将e的所有邻接点加入队列,也就是遍历i的所有邻接点
if (!visited[e->adjvex])
{ // adjvex是e所表示的结点下标
visited[e->adjvex] = 1;
printf("\t%s", G->adjlist[e->adjvex].data);
EnQueue(&Q, e->adjvex); //将该结点入队
}
e = e->nextarc; //遍历i的下一个邻接点
}
printf_s("\n");
}
}
}
//深度优先遍历
int visited1[MaxVertices];
void DFS(ALGraph *G, int i)
{
ArcNode *p;
visited1[i] = 1;
printf_s("%s ", G->adjlist[i].data);
p = G->adjlist[i].firstarc;
while (p)
{
if (!visited1[p->adjvex])
{
DFS(G, p->adjvex);
}
p = p->nextarc;
}
}
//广度优先遍历
void BFSTravel(ALGraph *G)
{
int v, front, rear;
ArcNode *p;
int queue[MaxVertices];
front = rear = -1;
for (v = 0; v < G->n; v++)
{
visited[v] = 0;
}
v = 0;
visited[v] = 1;
printf_s("%c ", G->adjlist[v].data);
rear = (rear + 1) % MaxVertices;
queue[rear] = v;
while (front < rear)
{
front = (front + 1) % MaxVertices;
v = queue[front];
p = G->adjlist[v].firstarc;
while (p != NULL)
{
if (visited[p->adjvex] == 0)
{
visited[p->adjvex] = 1;
printf_s("%c ", G->adjlist[p->adjvex].data);
rear = (rear + 1) % MaxVertices;
queue[rear] = p->adjvex;
}
p = p->nextarc;
}
}
}
void DFSTravel(ALGraph *G)
{
int i;
for (i = 0; i < G->n; i++)
{
visited1[i] = 0;
}
for (i = 0; i < G->n; i++)
{
if (!visited1[i])
{
DFS(G, i);
}
}
}
//prim最小生成树
int Prim(int graph[][MaxVertices], int n)
{
int lowcost[MaxVertices], mst[MaxVertices];
/*
lowcost[i]记录以i为终点的边的最小权值,当lowcost[i]=0时表示终点i加入生成树
mst[i]记录对应lowcost[i]的起点,当mst[i]=0时表示起点i加入生成树
*/
int i, j, min, minid, sum = 0;
for (i = 2; i <= n; i++) //默认选择1号节点加入生成树,从2号节点开始初始化
{
lowcost[i] = graph[1][i]; //最短距离初始化为其他节点到1号节点的距离
mst[i] = 1; //标记所有节点的起点皆为默认的1号节点
}
mst[1] = 0; //标记1号节点加入生成树
for (i = 2; i <= n; i++) //n个节点至少需要n-1条边构成最小生成树
{
min = INF;
minid = 0;
for (j = 2; j <= n; j++) //找满足条件的最小权值边的节点minid
{
if (lowcost[j] < min && lowcost[j] != 0) //边权值较小且不在生成树中
{
min = lowcost[j];
minid = j;
}
}
printf("%d - %d : %d\n", mst[minid], minid, min); //输出生成树边的信息:起点,终点,权值
sum += min; //累加权值
lowcost[minid] = 0; //标记节点minid加入生成树
for (j = 2; j <= n; j++) //更新当前节点minid到其他节点的权值
{
if (graph[minid][j] < lowcost[j]) ///发现更小的权值
{
lowcost[j] = graph[minid][j]; //更新权值信息
mst[j] = minid; //更新最小权值边的起点
}
}
}
return sum; //返回最小权值和
}
void main()
{
ALGraph G;
CrateGraph(&G);
printf_s("\n");
DisGraph(&G);
printf_s("\n最小生成树的权值之和:%d\n", Prim(graph, G.n));
}
#include
#include
#define MaxVertices 100
#define INF 65535
int sum = 0;
//建立边表
typedef struct node
{
int adjvex; //该边指向的结点位置
struct node* next; //指向下一条边
int info; //权重
}ArcNode;
//建立顶点表
typedef struct
{
char data;
ArcNode *first;
}VerNode;
//定义边集数组
typedef struct Edge
{
int v1;
int v2;
int weight;
}Edge;
//建立连接表
typedef struct
{
VerNode adjList[MaxVertices];//邻接表的顶点存放数组
int n, e; //顶点数,边数
Edge *p; //存放边集的数组
int *m; //存放
}AdjList;
//生成无向邻接表
void CreateGraph1(AdjList *L)
{
int i, j, a, b, c;
ArcNode *s; //边表
printf_s("请输入总顶点数和总边数:\n");
scanf_s("%d%d", &L->n, &L->e);
L->p = (Edge*)malloc(sizeof(Edge)*(L->e + 1));
L->m = (int *)malloc(sizeof(int)*L->n);
printf_s("建立顶点表:\n");
for (i = 0; i < L->n; i++)
{
scanf_s("%d", &L->adjList[i].data);
L->m[i] = L->adjList[i].data; //最小生成树算法顶点数组
L->adjList[i].first = NULL; //初始化当前顶点指向的边表全部为空
}
//头插法创建边表
printf_s("建立边表:\n");
for (i = 0; i < L->e; i++)
{
printf_s("请输入有连接的顶点:");
scanf_s("%d%d%d", &a, &b, &c);
L->p[i].v1 = a;
L->p[i].v2 = b;
L->p[i].weight = c;
a -= 1; b -= 1; //输入顶点从一开始,减去1后方便数组存储
s = (ArcNode*)malloc(sizeof(ArcNode)); //边表申请存储空间
s->adjvex = b; //边表的数据域赋值,指向边表的结点位置
s->info = c; //两个连接的权重
s->next = NULL; //尾插法
ArcNode *p;
p = L->adjList[a].first;
if (p == NULL)
{
L->adjList[a].first = s;
}
else
{
while (p->next)
{
p = p->next;
}
p->next = s;
}
/*
s->next = L->adjList[a].first; //头插法
L->adjList[a].first = s;
*/
/*加入这部分就是无向邻接表
s = (ArcNode*)malloc(sizeof(ArcNode));
s->adjvex = a;
s->next = L->adjList[b].first;
L->adjList[b].first = s;
*/
}
for (i = 0; i < L->e; i++) //根据权值冒泡排序
{
for (j = L->e - 1; j > i; j--)
{
if (L->p[i].weight > L->p[j].weight)
{
L->p[L->e] = L->p[i];
L->p[i] = L->p[j];
L->p[j] = L->p[L->e];
}
}
}
}
int Find(int *parent, int g) //通过parent[]找到可连接的边
{
while (parent[g] != 0)
{
g = parent[g];
}
return g;
}
int Finish(AdjList *G, int *parent) //判断生成树是否完成,完成的标志是生成树的边等于顶点的数量减1
{
int i, n = 0;
for (i = 0; i<G->n; i++)
{
if (parent[i])
{
n++;
}
}
if (n == G->n - 1)
{
return 1;
}
return 0;
}
int FindPeak(AdjList *G, int g) //找到顶点的下标
{
int i;
for (i = 0; i<G->n; i++)
{
if (G->m[i] == g)
return i;
}
return -1;
}
int MinTree_Kruskal(AdjList *G)
{
int i, a, b;
int parent[MaxVertices];
for (i = 0; i<G->n; i++) //初始化parent[]
{
parent[i] = 0;
}
printf_s("编号\t顶点\t生成树\n");
for (i = 0; i<G->e; i++)
{
a = Find(parent, FindPeak(G, G->p[i].v1));
b = Find(parent, FindPeak(G, G->p[i].v2));
if (a != b) //如果a==b则表是a和b在同一颗生成树上,如果a和b连接则为生成环,不符合生成树
{
parent[a] = b;
printf_s("%d\t%c\t",i+1,i+'a');
printf("%d->%d = %d\n", G->p[i].v1, G->p[i].v2, G->p[i].weight);
sum += G->p[i].weight;
}
if (Finish(G, parent)) //完成后返回
{
return sum;
}
}
return -1;
}
void DisGraph1(AdjList *L)
{
int i;
for (i = 0; i < L->n; i++)
{
printf_s("%d->", i + 1);
while (1)
{
if (L->adjList[i].first == NULL)
{
break;
}
printf_s("%d(%d)->", L->adjList[i].first->adjvex + 1, L->adjList[i].first->info);
L->adjList[i].first = L->adjList[i].first->next;
}
printf_s("NULL\n");
}
}
void main()
{
AdjList *L = (AdjList*)malloc(sizeof(AdjList));
CreateGraph1(L);
printf_s("\n");
printf_s("权值和:%d\n", MinTree_Kruskal(L));
}