稠密图、稀疏图(记住公式: | E | < | V | ×log | V | 是稀疏图) |
#include <stdio.h>
#include <stdlib.h>
#define MaxVertices 100 //定义最大容量
typedef struct AdjMatrix{
int Vertices[MaxVertices]; //用来保存顶点信息
int Edge[MaxVertices][MaxVertices]; //用来保存边的信息
int numV,numE; //图当前的顶点数与边数
}AdjMatrix;
void CreateGraph(AdjMatrix *G){
int n,e,vi,vj,w,i,j;
printf("请输入图的顶点数和边数(用空格分隔):" );
scanf("%d%d",&n,&e);
G->numV = n;
G->numE = e;
for(i=0;i<n;i++) //开始初始化
{
for(j=0;j<n;j++){
if(i=j){
G->Edge[i][j] = 0;
}
else{
G->Edge[i][j] = 32767; //暂时这条边长度为无穷大
}
}
for(i=0;i<G->numV;i++) //将顶点存入数组中
{
printf("请输入第%d个顶点的信息(整型):",i+1);
scanf("%d",&G->Vertices[i]);
}
}
printf("\n");
for(i=0;i<G->numE;i++){
printf("请输入边的信息i,j,w(以空格分隔):");
scanf("%d%d%d",&vi,&vj,&w);
//若为不带权值的图,则w输入1
//若为带权值的图,则w输入对应权值
G->Edge[vi-1][vj-1]=w;//①
G->Edge[vj-1][vi-1]=w;//②
//无向图具有对称性的规律,通过①②实现
//有向图不具备此性质,所以只需要①
}
}
void DispGraph(AdjMatrix G){ //输出邻接矩阵的信息
int i,j;
printf("\n输出顶点的信息(整型):\n");
for(i=0;i<G.numV;i++){
printf("%8d",G.Vertices[i]);
}
printf("\n输出邻接矩阵:\n");
printf("\t");
for(i=0;i<G.numV;i++){
printf("%8d",G.Vertices[i]);
}
for(i=0;i<G.numV;i++)
{
printf("\n%8d",i+1);
for(j=0;j<G.numV;j++){
if(G.Edge[i][j]==32767)
//两点之间无连接时权值为默认的32767,
//在无向图中一般用"0"表示,在有向图中一般用"∞",
//
这里为了方便统一输出 "∞"
printf("%8s", "∞");
else
printf("%8d",G.Edge[i][j]);
}
printf("\n");
}
}
int main()
{
AdjMatrix G;
CreateGraph(&G);
DispGraph(G);
}
#include <stdio.h>
#include <stdlib.h>
#define MaxSize 25
#define TRUE 1
#define FALSE 0
int visited[MaxSize];
typedef struct{
char data[MaxSize];
int front,rear;
}SqQueue;
typedef struct ArcNode{ //边结点
int adjvex; //该边所指向的顶点的位置
struct ArcNode *nextarc; //指向下一条边的指针
int info; //和边有关的信息
}ArcNode;
typedef struct VexNode{ //表头结点
int data;
ArcNode *firstarc; //指向第一条依附于该节点的边的指针
}VexNode,AdjList[MaxSize]; //AbjList表示一个表头结点表
typedef struct ALGraph{
AdjList vertices;
int vexNum,arcNum;
}ALGraph;
//循环队列
void InitQueue(SqQueue *Q){
Q->front = 0;
Q->rear = 0; //初始化队首,队尾指针
}
int isEmpty(SqQueue Q){
if(Q.rear == Q.front){
return TRUE;
}
else{
return FALSE;
}
}
int EnQueue(SqQueue *Q,char x){
if((Q->rear+1)%MaxSize == Q->front){
return FALSE;
}
else{
Q->data[Q->rear] = x;
Q->rear = (Q->rear+1)%MaxSize;
return TRUE;
}
}
int DeQueue(SqQueue *Q){
if(Q->rear == Q->front){
return FALSE; //队列是空的,不行
}
else{
Q->front = (Q->front+1)%MaxSize;
return TRUE;
}
}
int LocateVex(ALGraph G,char v){ //定位顶点的位置
int i;
for(i=0;i<G.vexNum;i++){
if(G.vertices[i].data == v){
return i;
}
}
}
void CreateUDG(ALGraph *G){
int i,j,k;
char vi,vj;
printf("scanf vexNum and arcNum\n");
scanf("%d", &G->vexNum); //输入顶点数与边数
scanf("%d", &G->arcNum);
getchar();
for(i=0;i<G->vexNum;i++){
printf("scanf vexs\n");
scanf("%c",&G->vertices[i].data); //输入顶点信息
getchar();
G->vertices[i].firstarc = NULL; //刚开始每个表头结点的第一条边指针都设置为NULL
}
for(k=0;k<G->arcNum;k++){ //输入各个边,构造邻接表
printf("scanf vi and vj\n");
scanf(" %c", &vi);
getchar();
scanf(" %c", &vj);
i = LocateVex(*G, vi);
printf("%d", i);
j = LocateVex(*G, vj);
printf("%d", j);
ArcNode *p1; //创建一个边结点p1
p1->adjvex = j;
p1->nextarc = G->vertices[i].firstarc;
G->vertices[i].firstarc = p1; //插入新的边结点
ArcNode *p2; //对称的边结点,这就是所有边出现两次的原因
p2->adjvex = i;
p2->nextarc = G->vertices[j].firstarc;
G->vertices[j].firstarc = p2;
}
}
int main(int argc, char const *argv[]) {
ALGraph G;
CreateUDG(&G);
BFS(G,'a');
return 0;
}
#include <stdio.h>
#define MaxVertexNum 100
typedef struct ArcNode //弧结点
{
int tailvex, headvex; //该弧的头尾结点
struct ArcNode *hlink, *tlink; //分别指向弧头相同和弧尾相同的结点
}ArcNode;
typedef struct VNode //顶点结点
{
int data;
ArcNode *firstin,*firstout; //指向第一条入弧和出弧
}VNode;
typedef struct GLGraph{
VNode xlist[MaxVertexNum]; //邻接表
int vexnum, arcnum; //图的顶点数和弧数
}GLGraph;
#include <stdio.h>
#define MaxVertexNum 100
typedef struct ArcNode //弧结点
{
int mark; //访问标记
int ivex, jvex; //该弧的头尾结点
struct ArcNode *ilink, *jlink; //分别指向两个顶点的下一条边
}ArcNode;
typedef struct VNode //顶点结点
{
int data;
ArcNode ,*firstedge; //指向第一条依附该顶点的边
}VNode;
typedef struct AMLGraph{
VNode adjmulist[MaxVertexNum]; //邻接表
int vexnum, arcnum; //图的顶点数和弧数
}AMLGraph;
#include <stdio.h>
#include <stdlib.h>
#define MaxSize 25
#define TRUE 1
#define FALSE 0
int visited[MaxSize];
typedef struct{
char data[MaxSize];
int front,rear;
}SqQueue;
typedef struct AMGraph{
char vexs[MaxSize];
int arcs[MaxSize][MaxSize];
int vexNum,arcNum;
}AMGraph;
//循环队列
void InitQueue(SqQueue *Q){
Q->front = 0;
Q->rear = 0; //初始化队首,队尾指针
}
int isEmpty(SqQueue Q){
if(Q.rear == Q.front){
return TRUE;
}
else{
return FALSE;
}
}
int EnQueue(SqQueue *Q,char x){
if((Q->rear+1)%MaxSize == Q->front){
return FALSE;
}
else{
Q->data[Q->rear] = x;
Q->rear = (Q->rear+1)%MaxSize;
return TRUE;
}
}
int DeQueue(SqQueue *Q){
if(Q->rear == Q->front){
return FALSE; //队列是空的,不行
}
else{
Q->front = (Q->front+1)%MaxSize;
return TRUE;
}
}
int LocateVex(AMGraph G,char v){ //定位顶点的位置
int i;
for(i=0;i<G.vexNum;i++){
if(G.vexs[i] == v){
return i;
}
}
}
void CreateUDG(AMGraph *G){
int i,j,k;
char vi,vj;
printf("scanf vexNum and arcNum\n");
scanf("%d", &G->vexNum); //输入顶点数与边数
scanf("%d", &G->arcNum);
getchar();
for(i=0;i<G->vexNum;i++){
printf("scanf vexs\n");
scanf("%c",&G->vexs[i]); //输入顶点信息
getchar();
}
for(i=0;i<G->vexNum;i++){
for(j=0;j<G->vexNum;j++){
G->arcs[i][j] = 0;
}
}
for(k=0;k<G->arcNum;k++){
printf("scanf vi and vj\n");
scanf(" %c", &vi);
getchar();
scanf(" %c", &vj);
i = LocateVex(*G, vi);
printf("%d", i);
j = LocateVex(*G, vj);
printf("%d", j);
G->arcs[i][j] = G->arcs[j][i] = 1;
}
}
void BFS(AMGraph G, char v0) { //v0相当于初始节点
SqQueue Q;
InitQueue(&Q); //初始化一个辅助队列
int i,v;
char u,w;
v = LocateVex(G,v0); //获得初始结点的位置
printf("%c",v0);
visited[v] = 1; //标志现在的结点已经被访问
EnQueue(&Q,v0); //入队列
while (isEmpty(Q) == 0) {
u = Q.data[Q.front]; //队列头元素出来
v = LocateVex(G,u);
DeQueue(&Q);
for(i=0;i<G.vexNum;i++){
w = G.vexs[i];
if(G.arcs[v][i]==1 && visited[i]==0){ //顶点u和w间有边,且顶点w未被访问
printf("%c", w);
EnQueue(&Q,w);
visited[i] = 1;
}
}
}
}
int main(int argc, char const *argv[]) {
AMGraph G;
CreateUDG(&G);
BFS(G,'a');
return 0;
}
void BFS_MIN_Distance(Graph G, int u){
//d[i]表示从u到i结点的最短路径
for(i=0;i<G.vexnum;++i){
d[i] = NoPath; //初始化路径长度
}
visited[u] = TRUE;
d[u] = 0;
EnQueue(Q,u);
while(!isEmpty(Q)){ //BFS算法主过程
DeQueue(Q,u); //队头元素u出队
for(w=FirstNeighbor(G,u);w>=0;w=NextNeighbor(G,u,w)){ //检测所有邻接点
if(!visited[w]){
visited[w] = TRUE;
d[w] = d[u] + 1; //利用性质了
EnQueue(Q,w);
}
}
}
}
#include <stdio.h>
#include <stdlib.h>
#define MaxSize 25
#define TRUE 1
#define FALSE 0
int visited[MaxSize];
typedef struct AMGraph{
char vexs[MaxSize];
int arcs[MaxSize][MaxSize];
int vexNum,arcNum;
}AMGraph;
int LocateVex(AMGraph G,char v){ //定位顶点的位置
int i;
for(i=0;i<G.vexNum;i++){
if(G.vexs[i] == v){
return i;
}
}
}
void CreateUDG(AMGraph *G){
int i,j,k;
char vi,vj;
printf("scanf vexNum and arcNum\n");
scanf("%d", &G->vexNum); //输入顶点数与边数
scanf("%d", &G->arcNum);
getchar();
for(i=0;i<G->vexNum;i++){
printf("scanf vexs\n");
scanf("%c",&G->vexs[i]); //输入顶点信息
getchar();
}
for(i=0;i<G->vexNum;i++){
for(j=0;j<G->vexNum;j++){
G->arcs[i][j] = 0; //初始化
}
}
for(k=0;k<G->arcNum;k++){
printf("scanf vi and vj\n");
scanf(" %c", &vi);
getchar();
scanf(" %c", &vj);
i = LocateVex(*G, vi);
j = LocateVex(*G, vj);
G->arcs[i][j] = G->arcs[j][i] = 1;
}
}
void DFS(AMGraph G,char v0){
int i,v;
printf("%c ", v0);
v = LocateVex(G,v0);
visited[v] = 1;
for(i=0;i<G.vexNum;i++){
if(G.arcs[v][i]==1&&visited[i]==0){
DFS(G,G.vexs[i]);
}
}
}
int main(int argc, char const *argv[]) {
int i,j;
AMGraph G;
CreateUDG(&G);
for(i=0;i<G.vexNum;i++){
for(j=0;j<G.vexNum;j++){
printf("%d ", G.arcs[i][j]);
}
}
DFS(G,'a');
return 0;
}
性质
Prim算法(基于贪心算法)
#include <stdio.h>
#include <stdlib.h>
#define MaxSize 25
typedef struct{
int from;
int to;
int weight;
int flag; //用来判断这个结点有没有被加入最小生成树中
}ArrayNode; //辅助数组,用来更新结点最短路径
typedef struct AMGraph{
char vexs[MaxSize];
int arcs[MaxSize][MaxSize];
int vexNum,arcNum;
}AMGraph;
int LocateVex(AMGraph G,char v){ //定位顶点的位置
int i;
for(i=0;i<G.vexNum;i++){
if(G.vexs[i] == v){
return i;
}
}
}
void CreateUDG(AMGraph *G){
int i,j,k;
char vi,vj;
int weight;
printf("scanf vexNum and arcNum\n");
scanf("%d", &G->vexNum); //输入顶点数与边数
scanf("%d", &G->arcNum);
getchar();
for(i=0;i<G->vexNum;i++){
printf("scanf vexs\n");
scanf("%c",&G->vexs[i]); //输入顶点信息
getchar();
}
for(i=0;i<G->vexNum;i++){
for(j=0;j<G->vexNum;j++){
G->arcs[i][j] = 0;
}
}
for(k=0;k<G->arcNum;k++){
printf("scanf vi and vj\n");
scanf(" %c", &vi);
getchar();
scanf(" %c", &vj);
i = LocateVex(*G, vi);
j = LocateVex(*G, vj);
printf("scanf weight between vi and vj\n");
scanf("%d", &weight);
G->arcs[i][j] = G->arcs[j][i] = weight;
}
}
void Init_Tree(AMGraph *Tree){ //初始化Prim的最小生成树
int i,j;
printf("scanf vexNum and arcNum");
scanf("%d", &Tree->vexNum); //包含原连通无向图所有结点
scanf("%d", &Tree->arcNum); //比结点数刚好少一个的边数
for(i=0;i<Tree->vexNum;i++){
Tree->vexs[i] = '\0';
}
for (i=0;i<Tree->vexNum;i++) {
for (j=0;j<Tree->arcNum;j++) {
Tree->arcs[i][j] = 0;
}
}
}
void Prim(AMGraph G,AMGraph T,char v0) { //Prim求最小生成树
int i,j,k;
int index; //指向权值最小的边
ArrayNode edgeArray[MaxSize*2]; //辅助数组
int length=0; //数组长度,当然了,从0开始
int n = 1; //统计数组已经加入了多少个结点
//初始状态把第一个结点加入最小生成树中
T.vexs[0] = v0;
printf("%-3c",T.vexs[0]);
i = LocateVex(G,v0);
while(1){
//寻找与顶点i相接且这条边的另一个顶点不在树中的边,存入edgeArray数组中
for(j=0;j<G.vexNum;j++){
if(G.arcs[i][j] > 0){//这个代表这两点之间有路径到达
//判断这条边的另一个结点是否已经在树中
for(k=0;k<T.vexNum;k++){
if(G.vexs[j] == T.vexs[k]){
break;
}
}
if(k == T.vexNum){ //这个时候就说明这条边另一个结点不在树中
edgeArray[length].from = i;
edgeArray[length].to = j;
edgeArray[length].weight = G.arcs[i][j];
edgeArray[length].flag = 0; //现在只是辅助数组中存储,还没有被选中哦
length++;
}
}
}
//接下来就要从数组中选择最小权值的结点咯
//printf("print length: %d", length);
index = -1;
for(j=0;j<length;j++){
if(index == -1 && edgeArray[j].flag == 0){
index=j;
}
if(edgeArray[j].flag==0 && edgeArray[j].weight < edgeArray[index].weight){ //index保存了上一个目标结点
index=j;
}
}
//printf("print index: %d", index);
//printf("edgeArray[index].to: %d", edgeArray[index].to);
//把选中的结点加入生成树中,把相关的边也加入
T.vexs[edgeArray[index].to] = G.vexs[edgeArray[index].to];
//printf("%-3c", G.vexs[edgeArray[index].to]);
//printf("%-3c", T.vexs[edgeArray[index].to]);
edgeArray[index].flag = 1; //这个选中的结点被使用了
T.arcs[edgeArray[index].from][edgeArray[index].to] = edgeArray[index].weight;
T.arcs[edgeArray[index].to][edgeArray[index].from] = edgeArray[index].weight;
//切分定理的舍弃部分,提高效率
for(k=0;k<length;k++){
if(edgeArray[k].to == edgeArray[index].to){
edgeArray[k].flag = 1;
}
}
i = edgeArray[index].to;
//printf("print i: %d", i);
printf("%-3c",T.vexs[i]);
n++; //个数增加
//当有G.vexNum个顶点时,最小生成树构造完成
if(n==G.vexNum)
break;
}
for(i=0;i<T.vexNum;i++){
for(j=0;j<T.arcNum;j++){
printf("%d\n", T.arcs[i][j]);
}
}
}
Kruskal算法(基于贪心算法)
#include <stdio.h>
#include <stdlib.h>
#define MaxSize 25
typedef struct{
int from;
int to;
int weight;
int flag; //用来判断这个结点有没有被加入最小生成树中
}ArrayNode; //辅助数组,用来更新结点最短路径
typedef struct AMGraph{
char vexs[MaxSize];
int arcs[MaxSize][MaxSize];
int vexNum,arcNum;
}AMGraph;
int LocateVex(AMGraph G,char v){ //定位顶点的位置
int i;
for(i=0;i<G.vexNum;i++){
if(G.vexs[i] == v){
return i;
}
}
}
void CreateUDG(AMGraph *G){
int i,j,k;
char vi,vj;
int weight;
printf("scanf vexNum and arcNum\n");
scanf("%d", &G->vexNum); //输入顶点数与边数
scanf("%d", &G->arcNum);
getchar();
for(i=0;i<G->vexNum;i++){
printf("scanf vexs\n");
scanf("%c",&G->vexs[i]); //输入顶点信息
getchar();
}
for(i=0;i<G->vexNum;i++){
for(j=0;j<G->vexNum;j++){
G->arcs[i][j] = 0;
}
}
for(k=0;k<G->arcNum;k++){
printf("scanf vi and vj\n");
scanf(" %c", &vi);
getchar();
scanf(" %c", &vj);
i = LocateVex(*G, vi);
j = LocateVex(*G, vj);
printf("scanf weight between vi and vj\n");
scanf("%d", &weight);
G->arcs[i][j] = G->arcs[j][i] = weight;
}
}
void Init_Tree(AMGraph *Tree){ //初始化Prim的最小生成树
int i,j;
printf("scanf vexNum and arcNum");
scanf("%d", &Tree->vexNum); //包含原连通无向图所有结点
scanf("%d", &Tree->arcNum); //比结点数刚好少一个的边数
for(i=0;i<Tree->vexNum;i++){
Tree->vexs[i] = '\0';
}
for (i=0;i<Tree->vexNum;i++) {
for (j=0;j<Tree->arcNum;j++) {
Tree->arcs[i][j] = 0;
}
}
}
//之后的库鲁斯卡尔算法会用到,判断两个结点是否相连
int connected(AMGraph T,int from,int to){
int i,j,k;
int vertex[MaxSize];//看做是队列
int front, rear;
if(from == to){
return 1;
}
front = rear = 0;
//把第一个顶点存入队列
vertex[rear++] = from;
//遍历树
while(front <= rear){
i = vertex[front]; //现在是第一个结点
for(j=0;j<T.vexNum;j++)
if(T.arcs[i][j]>0){
if(j==to)
return 1; //返回1就是两个结点相连
//判断此顶点是否在队列中
for(k=0;k<rear;k++) //遍历现在在队列中的所有结点
if(vertex[k] == j)
break;
if(k==rear) //BFS的操作
vertex[rear++]=j;
}
front++;
}
return 0;
}
//库鲁斯卡尔算法
void Kruskal(AMGraph G,AMGraph T){
ArrayNode edgeArray[MaxSize]; //老样子,辅助数组
int length=0;
int i,j,k,index,n; //与Prim算法基本一致
//先将所有顶点先加入到最小生成树中
for(i=0;i<T.vexNum;i++){
T.vexs[i] = G.vexs[i];
}
//接下来把所有边有序(从小到大)的插入edgeArray数组中
for(i=0;i<G.vexNum;i++){
for(j=0;j<G.vexNum;j++){
if(i<j && G.arcs[i][j]>0){
//寻找插入的位置index
for(k=0;k<length;k++){
if(edgeArray[k].weight > G.arcs[i][j])
break;
}
index=k;
//移位
for(k=length;k>index;k--)
edgeArray[k]=edgeArray[k-1];
//插入
length++;
edgeArray[index].flag=0;
edgeArray[index].from=i;
edgeArray[index].to=j;
edgeArray[index].weight=G.arcs[i][j];
}
}
}
//从小到大取出n-1条边构造最小生成树
n = 0;
printf("%d", n);
while (n<G.vexNum-1) {
/* code */
//从小到大开始选择
for(k=0;k<length;k++){
if(edgeArray[k].flag==0&&connected(T,edgeArray[k].from,edgeArray[k].to)==0){
printf("fail!!!!");
break;
}
printf("%d", n);
//把这条边加入到树中
T.arcs[edgeArray[k].from][edgeArray[k].to] = edgeArray[k].weight;
T.arcs[edgeArray[k].to][edgeArray[k].from] = edgeArray[k].weight;
edgeArray[k].flag =1;
printf("%d", edgeArray[k].weight);
n++;
}
}
}
int main(int argc, char const *argv[]) {
int i,j;
AMGraph G;
AMGraph T;
CreateUDG(&G);
Init_Tree(&T);
// for (i=0;i<T.vexNum;i++) {
// printf("%c ", T.vexs[i]);
// }
//
// for(i=0;i<T.vexNum;i++){
// for(j=0;j<T.arcNum;j++){
// printf("%d ", T.arcs[i][j]);
// }
// }
//Prim(G,T,'a');
Kruskal(G,T);
return 0;
}
Comments
😅 Commenting is disabled on this post.