作业3 图型结构及其应用
作业要求1:
分别实现无向图(或有向图)的邻接矩阵和邻接表存储结构的建立算法,分析和比较各建立算法的时间复杂度以及存储结构的空间占用情况。
void CreatMGraph(MTgraph*G)//邻接矩阵表示,数组表示法
{
//printf("Adjacency matrix representation, array representation, array representation\n");
int w;//记录权值
int i,j;
FILE* fp=fopen("graph.txt","r");//将图中结点信息保存在文件中
FILE* fq=fopen("data.txt","r");
//printf("Please enter the number of nodes:");
fscanf(fq,"%d ",&G->n);//节点数目
//printf("Please enter the number of edges:");
fscanf(fq,"%d ",&G->e);//边的数目
for(i=0;i<G->n;i++)
{
fscanf(fp,"%d ",&(G->v[i]));//读入节点名称
}
fclose(fp);
for(i=0;i<G->n;i++)
for(j=0;j<G->n;j++)
G->edge[i][j]=0;
for(int k=0;k<G->e;k++)
{
//printf("Please enter a node of the edge:");
fscanf(fq,"%d ",&i);//左顶点的位置信息
//printf("Please enter another node for the edge:");
fscanf(fq,"%d ",&j);//右顶点的位置信息
//printf("Please enter the weights:");
fscanf(fq,"%d ",&w);
G->edge[i][j]=w;
G->edge[j][i]=w;
}
fclose(fq);
printf("Build successfully!\n");
}
邻接矩阵建立算法,时间复杂度为o(n),空间占用:n2矩阵,占用大小为n2的sizeof(int)。
void CreateGraph(Adjgraph*G)//邻接表存储结构建立的算法
{
//printf("Adjacency list storage structure establishment algorithm\n");
FILE* fp=fopen("graph.txt","r");
FILE* ft=fopen("data2.txt","r");
int head,tail,weight;
//printf("Please enter the number of nodes:");
fscanf(ft,"%d ",&G->n);//输入顶点个数
//printf("Please enter the number of edges:");
fscanf(ft,"%d ",&G->e);//输入边数
for(int i=0;i<G->n;i++)
{
fscanf(fp,"%d ",&(G->vlist[i].v));//输入顶点信息
G->vlist[i].firstedge=NULL;//将边表设置为空表
}
fclose(fp);
for(int i=0;i<G->e;i++)
{
//printf("Please enter a node of the edge:");
fscanf(ft,"%d ",&head);//输入出边顶点
//printf("Please enter another node for the edge:");
fscanf(ft,"%d ",&tail);//输入入边顶点
//printf("Please enter the weight:");
fscanf(ft,"%d ",&weight);//输入权重
EdgeNode* p=NULL;
if((p=(EdgeNode *)malloc(sizeof(EdgeNode)))==NULL)
return;
p->adj=head;//设置边界点
p->cost=weight;
p->next=G->vlist[tail].firstedge;//链入第tail号链表的前端
G->vlist[tail].firstedge=p;
EdgeNode* q=NULL;
if((q=(EdgeNode *)malloc(sizeof(EdgeNode)))==NULL)
return;
q->adj=tail;
q->cost=weight;
q->next=G->vlist[head].firstedge;
G->vlist[head].firstedge=q;
}
fclose(ft);
printf("Build successfully!\n");
}
邻接表建立算法,时间复杂度为o(n),空间占用:使用静态数组存储结点,使用动态链表存储边,所占的大小为 2x边数x sizeof(EdgeNode)+静态数组n*sizeof(EdgeNode)
作业要求2:
void AMTransfer(MTgraph* G1,const Adjgraph G2)//从邻接表转换为邻接矩阵
{
int j;
G1->e=G2.e;//边数传递
int count=G2.e;//记录边数
G1->n=G2.n;//结点数传递
EdgeNode*p=NULL;
int flag[size][size]={0};
for(int i=0;i<G2.n;i++)
{
p=G2.vlist[i].firstedge;
while(p!=NULL)
{
j=p->adj;
if(flag[i][j]!=0)
{
p=p->next;
continue;
}
flag[i][j]++;
flag[j][i]++;
G1->edge[j][i]=p->cost;
G1->edge[i][j]=p->cost;
count--;
if(count<0) return;
p=p->next;
}
}
}
邻接表转换为邻接矩阵
void MATransfer(Adjgraph* G2,const MTgraph G1)//从邻接矩阵转换为邻接表
{
G2->e=G1.e;//边数传递
G2->n=G1.n;//结点数传递
for(int i=0;i<G1.n;i++)
for(int j=i;j<G1.n;j++)
if(G1.edge[i][j]!=0)
{
EdgeNode* p=NULL;
if((p=(EdgeNode *)malloc(sizeof(EdgeNode)))==NULL)
return;
p->adj=i;//设置边界点
p->cost=G1.edge[i][j];
p->next=G2->vlist[j].firstedge;//链入第tail号链表的前端
G2->vlist[j].firstedge=p;
EdgeNode* q=NULL;
if((q=(EdgeNode *)malloc(sizeof(EdgeNode)))==NULL)
return;
q->adj=j;
q->cost=G1.edge[i][j];
q->next=G2->vlist[i].firstedge;
G2->vlist[i].firstedge=q;
}
}
邻接矩阵转换为邻接表
作业要求3
在上述两种存储结构上,分别实现无向图(或有向图)的深度优先搜索(递归和非递归)和广度优先搜索算法。并以适当的方式存储和展示相应的搜索结果,包括:深度优先或广度优先生成森林(或生成树)、深度优先或广度优先序列和深度优先或广度优先编号。并分析搜索算法的时间复杂度和空间复杂度 。
void DFSTA_X(Adjgraph G,int i,Tree *T)//循环实现邻接表深度优先算法
{
int temp=0;int flag=0;int t=i;
int S[size];//设置一个栈(最大为顶点数)
for(int i=0;i<size;i++)
S[i]=-1;
int top=0;//设置栈顶
Tree*tp=createNew();
Tree*ST[size];
for(int i=0;i<size;i++)
ST[i]=NULL;
int Top=0;
ST[Top]=tp;
S[top]=i;//将该结点进栈
visit[i]=1;
T->v=G.vlist[i].v;
tp=T;
EdgeNode*p=NULL;
int first=0;
printf("%d ",G.vlist[i].v);
while(top!=-1)
{
temp=-1;
p=G.vlist[t].firstedge;
while(p!=NULL)
{
if(!visit[p->adj])
{
temp=p->adj;
if(flag==1)
{
top++;
S[top]=t;
tp->rchild=createNew();
tp=tp->rchild;
tp->v=G.vlist[temp].v;
}
break;
}
p=p->next;
}
if(temp==-1)
{
t=S[top];top--;
tp=ST[Top];Top--;
flag=1;
}
else{
printf("%d ",G.vlist[temp].v);
top++;Top++;
S[top]=temp;
visit[temp]=1;
t=temp;
ST[Top]=tp;
if(flag!=1)
{
tp->lchild=createNew();
tp=tp->lchild;
tp->v=G.vlist[temp].v;
}
flag=0;
}
}
}
void DFSTA(Adjgraph G,int i,Tree *T)//邻接表深度优先算法递归单元
{
EdgeNode* p;
visit[i]=1;//对方访问过的节点进行标记
sub[i]=count++;//进行编号
p=G.vlist[i].firstedge;//取一个边表的头指针
printf("%d ",G.vlist[i].v);//访问该节点
T->v=G.vlist[i].v;
Tree* tp=createNew();
int flag=1;
while(p!=NULL)
{
if(!visit[p->adj])
{
if(flag==1)
{
T->lchild=tp;
DFSTA(G,p->adj,tp);
flag=0;
}
else
{
tp->rchild=createNew();
tp=tp->rchild;
DFSTA(G,p->adj,tp);
}
}
p=p->next;
}
}
void DFSTB_X(MTgraph G,int i,Tree* T)//循环实现邻接矩阵深度优先算法
{
int temp=0;int flag=0;
int S[size];//设置一个栈(最大为顶点数)
for(int i=0;i<size;i++)
S[i]=-1;
int top=0;//设置栈顶
Tree*tp=createNew();
Tree*ST[size];
for(int i=0;i<size;i++)
ST[i]=NULL;
int Top=0;
ST[Top]=tp;
S[top]=i;//将该结点进栈
visit[i]=1;
T->v=G.v[i];
tp=T;
int m;
printf("%d ",G.v[i]);
while(top!=-1)
{
for(m=0;m<G.n;m++)
{
if(G.edge[i][m]>0&&visit[m]!=1)
{
if(flag==1)
{
top++;
S[top]=i;
tp->rchild=createNew();
tp=tp->rchild;
tp->v=G.v[m];
}
break;
}
}
if(m==G.n)
{
flag=1;
i=S[top];
S[top]=-1;
top--;
tp=ST[Top];Top--;
}
else
{
printf("%d ",G.v[m]);
top++;Top++;
S[top]=m;
visit[m]=1;
i=m;
ST[Top]=tp;
if(flag!=1)
{
tp->lchild=createNew();
tp=tp->lchild;
tp->v=G.v[m];
}
flag=0;
}
}
}
void DFSTB(MTgraph G,int i,Tree*T)//邻接矩阵深度优先算法递归单元
{
int j;
printf("%d ",G.v[i]);
visit[i]=1;
sub[i]=count++;
int flag=1;
T->v=G.v[i];
Tree*tp=createNew();
for(j=0;j<G.n;j++)
{
if((G.edge[i][j]>0)&&(!visit[j]))
{
if(flag==1)
{
T->lchild=tp;
DFSTB(G,j,tp);
flag=0;
}
else
{
tp->rchild=createNew();
tp=tp->rchild;
DFSTB(G,j,tp);
}
}
}
}
void DFSTAmain(Adjgraph G,Tree* T)//邻接表深度优先算法
{
int flag=0;
Tree* tp=createNew();
for(int j=0;j<G.n;j++)
visit[j]=0;
for(int i=0;i<G.n;i++)
{
if(!visit[i])
{
if(flag==0)
{
T->lchild=tp;
DFSTA(G,i,tp);
flag=1;
}
else
{
tp->rchild=createNew();
tp=tp->rchild;
DFSTA(G,i,tp);
}
}
}
printf("\n");
}
void DFSTAmain_X(Adjgraph G,Tree *T)//邻接表深度优先算法(循环)
{
int flag=0;
Tree* tp=createNew();
for(int j=0;j<G.n;j++)
visit[j]=0;
for(int i=0;i<G.n;i++)
{
if(!visit[i])
{
if(flag==0)
{
T->lchild=tp;
DFSTA_X(G,i,tp);
flag=1;
}
else
{
while(tp->rchild!=NULL)tp=tp->rchild;
tp->rchild=createNew();
tp=tp->rchild;
DFSTA_X(G,i,tp);
}
}
}
printf("\n");
}
void DFSTBmain(MTgraph G,Tree* T)//邻接矩阵深度优先算法
{
int flag=0;
Tree*tp=createNew();
for(int j=0;j<G.n;j++)
visit[j]=0;
for(int i=0;i<G.n;i++)
{
if(!visit[i])
{
if(flag==0)
{
T->lchild=tp;
DFSTB(G,i,tp);
flag=1;
}
else
{
tp->rchild=createNew();
tp=tp->rchild;
DFSTB(G,i,tp);
}
}
}
printf("\n");
}
void DFSTBmain_X(MTgraph G,Tree*T)//邻接矩阵深度优先算法(递归)
{
int flag=0;
Tree*tp=createNew();
for(int j=0;j<G.n;j++)
visit[j]=0;
for(int i=0;i<G.n;i++)
{
if(!visit[i])
{
if(flag==0)
{
T->lchild=tp;
DFSTB_X(G,i,tp);
flag=1;
}
else
{
while(tp->rchild!=NULL)tp=tp->rchild;
tp->rchild=createNew();
tp=tp->rchild;
DFSTB_X(G,i,tp);
}
}
}
printf("\n");
}
void BFSTA(Adjgraph G,int i)//邻接表广度优先算法单元
{
int j;EdgeNode*p=NULL;
initial(&Q);
printf("%d ",G.vlist[i].v);
visit[i]=1;
inque(i,&Q);
while(Q.head!=Q.tail)
{
j=ouque(&Q);
p=G.vlist[j].firstedge;
while(p!=NULL)
{
if(!visit[p->adj])
{
printf("%d ",G.vlist[p->adj].v);
visit[p->adj]=1;
inque(p->adj,&Q);
}
p=p->next;
}
}
}
void BFSTB(MTgraph G,int i)//邻接矩阵广度优先算法单元
{
int j,k;queue Q;initial(&Q);
printf("%d ",G.v[i]);
visit[i]=1;
inque(i,&Q);
while(Q.head!=Q.tail)
{
j=ouque(&Q);
for(k=0;k<G.n;k++)
{
if(G.edge[j][k]>0&&(!visit[k]))
{
printf("%d ",G.v[k]);
visit[k]=1;
inque(k,&Q);
}
}
}
}
void BFSTAmain(Adjgraph G)//邻接表广度优先算法
{
for(int i =0; i<G.n;i++)
{
visit[i]=0;
}
for(int i=0;i<G.n;i++)
{
if(!visit[i])
BFSTA(G,i);//从顶点i出发的第一次搜索
}
printf("\n");
}
void BFSTBmain(MTgraph G)//邻接矩阵广度优先算法
{
for(int i =0; i<G.n;i++)
{
visit[i]=0;
}
for(int i=0;i<G.n;i++)
{
if(!visit[i])
BFSTB(G,i);//从顶点i出发的第一次搜索
}
printf("\n");
}
在该过程中实现了生成树,通过遍历生成树会得到与遍历相似的结果。时间复杂度为o(n2)。分别是在递归单元外有n在递归单元内有n的遍历,导致最后为o(n2)的复杂度。没递归一次调用一次栈,栈中的元素最多的时候(即空间复杂度)为n。
作业要求4:
对于无向图,采用“邻接表”存储结构,设计和实现计算每个顶点度的算
法,并分析其时间复杂度。
遍历所有结点的next值,最坏的情况为o(n2)的时间复杂度。
void Dev2(Adjgraph G,DEV* dev2)//邻接表的度计算
{
EdgeNode*p=NULL;
for(int i=0;i<G.n;i++)
{
dev2->v[i]=G.vlist[i].v;
p=G.vlist[i].firstedge;
while(p!=NULL)
{
dev2->dev[i]++;
p=p->next;
}
}
}
测试用例
20 15 6 7 3 8 5 9 7 11 12 4 5 13 11 4 2 14 5 9 12 4 9 11 3 6 2 3 9 10 14 13 2 5 1 2 4 0 2 7 4 3 2 19 3 7 5 11
前两个值第一个代表顶点第二个代表边的数量
测试结果如下:
Build successfully!
Build successfully!
please enter your choice:1
1 2 3 4 12 15 6 5 13 9 8 7 10 11 14 16 17 18 19 20
1 2 3 4 12 15 6 5 13 9 8 7 10 11 14 16 17 18 19 20
1 2 3 4 12 15 6 5 13 9 8 7 10 11 14 16 17 18 19 20
1 2 3 4 12 15 6 5 13 9 8 7 10 11 14 16 17 18 19 20
please enter your choice:2
1 5 6 8 7 9 2 3 4 10
1 5 6 8 7 9 2 3 4 10
1 5 6 8 7 9 2 3 4 10
1 5 6 8 7 9 2 3 4 10
please enter your choice:3
1 2 3 4 12 15 5 8 6 13 7 9 10 11 14 16 17 18 19 20
please enter your choice:4
1 5 6 8 9 7 2 3 4 10
please enter your choice:5
点的名称为:1 度为:0
点的名称为:2 度为:0
点的名称为:3 度为:1
点的名称为:4 度为:2
点的名称为:5 度为:3
点的名称为:6 度为:3
点的名称为:7 度为:1
点的名称为:8 度为:2
点的名称为:9 度为:1
点的名称为:10 度为:0
点的名称为:11 度为:0
点的名称为:12 度为:4
点的名称为:13 度为:1
点的名称为:14 度为:0
点的名称为:15 度为:2
点的名称为:16 度为:0
点的名称为:17 度为:0
点的名称为:18 度为:0
点的名称为:19 度为:0
点的名称为:20 度为:0
完整代码请看代码文件。