数据结构与算法期末复习

图的创建

邻接距阵

思路

结构体中:
有一维顶点数组,保存顶点值
有二维边数组,即距阵(初始化为0–表示不连通)
有int 类型的顶点数,边数
创建顶点数组:
一层for循环遍历储存
创建边数组:
先初始化二维数组为0;
根据传入的两个顶点值,在一维顶点表中找到对应的下标、
两层循环,将二维矩阵有的变为1

代码
#include<stdio.h>
#define MVNum 100

typedef struct {
	//顶点表
	char vexs[MVNum];
	//边表
	int arcs[MVNum][MVNum];
	//顶点数和边数
	int vexnum,arcnum;
}MGraph;

void CreatMGraph(MGraph &G);
void PrintMGgraph(MGraph G);

int main()
{
	MGraph G;
	CreatMGraph(G);
	PrintMGgraph(G);
	return 0;
}

//在顶点数组中寻找char 所对应的下标
int locate(MGraph G,char v)
{
	for(int i=0;i<G.vexnum;i++)
	{
		if(G.vexs[i]==v)
		{
			return i;
		}
	}
	
	return -1;
}
void CreatMGraph(MGraph &G)
{
	char v1,v2;
	
	//输入顶点数与边数
	printf("请输入顶点数与边数:\n");
	scanf("%d%d",&G.vexnum,&G.arcnum);
	getchar();
	//输入顶点数组
	printf("请输入顶点数组:\n");
	for(int i=0;i<G.vexnum;i++)
	{
		scanf("%c",&G.vexs[i]);
		
	}
	
	//初始化边数组
	
	for(int i=0;i<G.vexnum;i++)
	{
		for(int j=0;j<G.vexnum;j++)
		{
			G.arcs[i][j]=0;
		}
	}
	
	//输入边数组
	printf("请输入边数组:\n");
	for(int k=0;k<G.arcnum;k++)
	{
		getchar();
		scanf("%c%c",&v1,&v2);
		
		int i=locate(G,v1);
		int j=locate(G,v2);
		
		G.arcs[i][j]=1;
		G.arcs[j][i]=1;
		
	}
	
	
	
}

void PrintMGgraph(MGraph G)
{
	for(int i=0;i<G.vexnum;i++)
	{
		printf("%c->",G.vexs[i]);
		
		for(int j=0;j<G.vexnum;j++)
		{
			if(G.arcs[i][j])
			printf("%c ",G.vexs[j]);
		}
		
		printf("\n");
		
	}
}



邻接表

思路

1.两个结构体
2.储存顶点的Vnode
3.储存每个小结点的arcnode

代码
#include <stdio.h>
#include <stdlib.h>
#define MVNum 100                                 //最大顶点数
typedef struct ArcNode{                        //表结点
    int adjvex;                                    //邻接点的位置
    struct ArcNode *nextarc;      //指向下一个表结点的指针
}ArcNode;
  
typedef struct VNode{
   char data;                                    //顶点信息
   ArcNode *firstarc;         //指向第一个表结点的指针
}VNode, AdjList[MVNum];                 //AdjList表示邻接表类型

typedef struct{
    AdjList vertices;              //头结点数组
    int vexnum, arcnum;     //图的当前顶点数和边数
}ALGraph;


void CreatMGraph(ALGraph &G);/* 创建图 */
void printGraph(ALGraph G);/*输出图 */
int main()
{
    ALGraph G;
    CreatMGraph(G);
    printGraph(G);
    return 0;
}

void printGraph(ALGraph G)
{
    int i;
    ArcNode *p;
    for(i=0;i<G.vexnum;i++)
    {
       printf("%c:",G.vertices[i].data);
       for(p=G.vertices[i].firstarc;p;p=p->nextarc)
           printf(" %c",G.vertices[p->adjvex].data);
       printf("\n");
    }
}

/* 请在这里填写答案 */

int locate(ALGraph G,char v)//求顶点v的下标
{
	for(int i=0;i<G.vexnum;i++)
	{
		if(v==G.vertices[i].data)
		{
			return i;
		}
	}
	
	return -1;
}
void CreatMGraph(ALGraph &G)//创建图G
{
	//输入顶点数与边数
	scanf("%d %d",&G.vexnum,&G.arcnum);
	getchar();
	
	//输入顶点表
	for(int i=0;i<G.vexnum;i++)
	{
		scanf("%c",&G.vertices[i].data);
		
		//初始化表
		G.vertices[i].firstarc=NULL;
		
	}
	
	char a,b;
	ArcNode *s;
	//输入邻接表
	for(int k=0;k<G.arcnum;k++)
	{
		getchar();
		scanf("%c%c",&a,&b);
		int i=locate(G,a);
		int j=locate(G,b);
		
		s=(ArcNode *)malloc(sizeof(ArcNode));
		s->adjvex=j;
		s->nextarc=G.vertices[i].firstarc;
		G.vertices[i].firstarc=s;
		
		s=(ArcNode *)malloc(sizeof(ArcNode));
		s->adjvex=i;
		s->nextarc=G.vertices[j].firstarc;
		G.vertices[j].firstarc=s;		
		
	}

	
	
}

图的遍历

深度优先遍历

思路:
1.找到一个顶点开始访问
2.访问这个顶点可以访问的下一个顶点继续访问
3.重复以上直至访问完毕

注意:
设置visited[]数组来存放每个结点的访问情况,初始值为0,表示未被访问

代码:

int DFSCount(int v)
{
  static int count=1;
  int w;
  visited[v]=1; //访问当前结点
  for(w=0;w<max_matrix;w++)
	if(!visited[w] && matrix[v][w]!=0)
	  { 
	     count++;
	     DFSCount(w);
	  }
   return count;
}

广度优先遍历

思路:
类似二叉树的层次遍历
开辟一个队列来入队出队模拟访问过程

注意:
设置visited[]数组来存放每个结点的访问情况,初始值为0,表示未被访问
简便方法处理队列,使用一维数组代替队列,记录队首队尾指针

代码
int BFS(ALGraph G,int v)  //以顶点v开始进行广度优先遍历
{
  int u;
  ArcNode *p;
  SqQueue Q;  //创建辅助队列
  InitQueue(Q);  //初始化辅助队列
  printf("广度优先遍历序列:%c ",G.vertices[v].data);
  visited[v]=1;  //访问顶点v
  EnQueue(Q,v);  //顶点v入队

  while(!QueueEmpty(Q))  //队列为空时结束循环
  {
     DeQueue(Q,u) ;  //顶点u出队
     p=G.vertices[u].firstarc;
     while(p)
     {
	   if(!visited[p->adjvex] )  //若存在边且顶点w未访问
      {
          printf("%c ",G.vertices[p->adjvex].data);
          visited[p->adjvex]=1;  //访问顶点w
          EnQueue(Q,p->adjvex);  //顶点w入队
      }
      p=p->nextarc;
  }
  }
  printf("\n\n");

  return 0;
}

最小生成树

实现原理:

选取原图中权值之和最小的n-1条边,使得n个顶点恰好连通
n个顶点+n-1条边

实现算法

prim算法
思路–找点法
1.任意从一个顶点u开始,将u加入集合,表示已经访问
2.选择这个顶点所连边中最小的边,另一端顶点放入集合,表示已经访问
3.重复2,直到所有顶点访问完毕
代码
1.0---表示已经访问
2.parent[k]----表示k节点的最小边的前驱节点
void prim(MGraph g,int v)  //从顶点V0出发,按普里姆算法构造联通网G的最小生成树
{
      int Vlength[MAXV];//记录权值
      int i, j, k;
      int parent[MAXV];//记录边的起始节点
      int min;
      for(i=0;i<g.vexnum;i++)
      {
           Vlength[i]=g.edges[v][i];
           parent[i]=v;
      }
      Vlength[v]=0;//标记已经访问这个下标对应的节点
      for(i=1;i<g.vexnum;i++)
      {
           min=INF;
           for(j=0;j<g.vexnum;j++)
           {
               if(Vlength[j]!=0&&Vlength[j]<min)
               {
                   min=Vlength[j];
                   k=j;
               }
           }
           
           printf("结点<%s~~~~~~~%s)    边的权值为: %d\n",g.vexs[parent[k]],g.vexs[k],min);
           
           Vlength[k]=0;//标记已经访问k节点
		   //从k节点开始继续寻找
           for(j=0;j<g.vexnum;j++)
           {
               if(Vlength[j]!=0 && g.edges[k][j]<Vlength[j])
               {
                   Vlength[j]=g.edges[k][j];
                   parent[j]=k;
               }
           }
      }


}

kruskal算法
思路–找边法
1.找到最小权值的边
2.将此边的后驱节点划分到与前驱节点的同一连通分量中
3.找后驱节点所处的与其在不同连通分量的并且权值最小的边,
4.重复2,3,直到所有顶点都处于同一连通分量
代码
1.vset[]--判断两个点是否连通
2.E[]--- 从小到大储存边,数据类型是结构体:边起始点,边终止点,边权值
typedef struct node
{
    int u;                                                 //边的起始顶点
    int v;                                                 //边的终止顶点
    int w;                                                 //边的权值
}Edge;

void sort(MGraph G,Edge E[])
{
    Edge t;
    int i,j;
    for(i=0;i<G.arcnum-1;i++)
       for(j=0;j<G.arcnum-i-1;j++)
        if(E[j].w>E[j+1].w)
    {
        t=E[j];
        E[j]=E[j+1];
        E[j+1]=t;
    }
}

void kruskal(MGraph G)
{
    int i,j,sn1,sn2,k;
    int vset[MAXV];                                    //辅助数组。判定两个顶点是否连通
    Edge E[MAXV];                                       //存放全部的边
    k=0;                                               //E数组的下标从0開始
    for (i=0;i<G.vexnum;i++)
    {
        for (j=0;j<=i;j++)
        {
            if (G.edges[i][j]!=0 && G.edges[i][j]!=INF)
            {
                E[k].u=i;
                E[k].v=j;
                E[k].w=G.edges[i][j];
                k++;
            }
        }
    }
    sort(G,E);                            //堆排序,按权值从小到大排列
    for (i=0;i<G.vexnum;i++)                                    //初始化辅助数组
    {
        vset[i]=i;             //所在集合
    }
    k=1;                                                   //生成的边数,最后要刚好为总边数
    j=0;                                                   //E中的下标
    while (k<G.vexnum)
    {
        sn1=vset[E[j].u];
        sn2=vset[E[j].v];                                  //得到两顶点属于的集合编号
        if (sn1!=sn2)                                      //不在同一集合编号内的话,把边增加最小生成树
        {
            printf("边:%s ---> %s, 权值:%d\n",G.vexs[E[j].u],G.vexs[E[j].v],E[j].w);
            k++;
            vset[E[j].v]=sn1;
        }
        j++;
    }
}

最短路径

原理解释

图中,两个节点中的所有路径中权值最小的一条路径

Dijaksta算法

思路
代码
 Vertex FindMinDist( MGraph Graph, int dist[], int collected[] )
    //dist[]某顶点到其他顶点的权值,collected[]-false--表示这个顶点还没有找到最短路径
    { 
	/* 返回未被收录顶点中dist最小者 */
        Vertex MinV, V;
        int MinDist = INFINITY;

        for (V=0; V<Graph.Nv; V++) {
            if ( collected[V]==FALSE && dist[V]<MinDist) {
                /* 若V未被收录,且dist[V]更小 */
                MinDist = dist[V]; /* 更新最小距离 */
                MinV = V; /* 更新对应顶点 */
            }
        }
        
        
        if (MinDist < INFINITY) /* 若找到最小dist */
            return MinV; /* 返回对应的顶点下标 */
        else return ERROR;  /* 若这样的顶点不存在,返回错误标记 */
    }

    bool Dijkstra( MGraph Graph, int dist[],  Vertex S )
    {
        int collected[MAX_VERTEX_NUM];
        Vertex V, W;

        /* 初始化:此处默认邻接矩阵中不存在的边用INFINITY表示 */
        for ( V=0; V<Graph.Nv; V++ ) {
            dist[V] = Graph.arcs[S][V];
            collected[V] = FALSE;
        }
        dist[S]=0;
        collected[S] =TRUE;
        
        while(1)
        {
        V=FindMinDist(Graph,dist,collected);//找到与s相连接的权值最短的点
        if(V==ERROR)
            break;
        collected[V] =TRUE;//标记此点已经找到
        for(W=0;W<Graph.Nv;W++)
            if(Graph.arcs[V][W]<INFINITY && collected[W]==FALSE && dist[V]+Graph.arcs[V][W]<dist[W])
               dist[W]=dist[V]+Graph.arcs[V][W];
        }
        
        return OK; /* 算法执行完毕,返回正确标记 */
    }

拓扑排序

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值