数据结构-图

数据结构-图

数据结构-图(错题)

  1. 具有n个顶点的有向图最多有n(n-1)条边,(每个顶点可与其余n-1个顶点相连)

  2. n个顶点的连通图用邻接矩阵表示时,该矩阵至少有2(n-1)个非零元素

  3. 有向完全图共有(n)(n-1)条边,无向完全图共有(n)(n-1)/2条边

  4. 强连通图:对于图中任意两个顶点,均有路径可以到达

    邻接矩阵


    1. 邻接矩阵储存结构
    java 复制代码
    typedef struct{
       char vex[100];//顶点表
       int arcs[100][100];//储存邻接矩阵
       int vexnum,arcnum;//vex顶点,arc边
    }AMGraph;
    1. 邻接矩阵创建无向网
    java 复制代码
    int create(AMGraph &G){
        cin>>G.vexnum>>G.arcnum;//输入顶点和边
        for(int i=0;i<n;i++)cin>>G.vexs[i];//输入顶点信息
        for(int i=0;i<n;i++){
            for(int j=0;j<n;j++){
                G.arcs[i][j]=1000000;//初始化
            }
        }
        for(int k=0;k<G.arcnum;k++){
            int v1,v2;cin>>v1>>v2;
            int i=Locate(G,v1),j=Locate(G,v2);//确定v1,v2在图中的下标
            G.arcs[i][j]=G.arcs[j][i]=w;//w权值
        }
        return 1;
    }

    邻接表的创建


    1. 邻接表储存结构
    java 复制代码
    typedef struct Arcnode{
       //边节点
        int adjvex;//该边所指向顶点的位置
        struct ArcNode *nextarc;//指向下一条边的指针
        int info;//和边相关的信息(权值)
    }ArcNode;
    typedef struct VNode{
        //顶点信息
        int data;
        ArcNode *first//第一条边
    }Vnode,AdjList[100];
    typedef struct{
        AdjList vertices;//记录每个顶点信息
        int vexnum,recnum;//定点数和边数
    }ALGraph;

    配上一张图方便大家理解


    2. 用邻接表储存无向图

    java 复制代码
    int create(ALGraph &G){
        cin>>G.vexnum>>G.arcnum;
        for(int i=0;i<G.vexnum;i++){
            cin>>G.vertices[i].data;
            G.vertices[i].first=NULL;//输入每个顶点并且对其初始化
        }
        for(int k=;k<G.arcnum;k++){
            int v1,v2;cin>>v1>>v2;
            int i=Locate(G,v1),int j=Locate(G,v2);
            p1=new ArcNode;//邻接表的结点需要生成
            p1->adjvex=j;//该顶点所指向下标
            p1->nextarc=G.vertices[i].first;G.vertices[i].first=p1;//j顶点插入i的邻接表中
            p2=ewn ArcNode;
            p2->adjvex=i;
            p2->nextarc=G.vertices[j].first;G.vertices[j].first=p2;//i顶点插入j的邻接表中
            //无向图是这样的
        }
    }

    深度优先遍历


    1. 采用邻接矩阵表示的深度优先搜索

      算法描述:

    java 复制代码
    bool visited[MVNum];//访问标志数组
    void DFS_Am(Graph G,itn v){
        cout<<v;Visited[v]=true;
        for(int w=0;w<G.vexnum;w++){
            if(G.arcs[v][w]!=0&&(!visited[w])){
                DFS_Am(G,w);
            }
        }
    }
    1. 采用邻接表表示图的深度优先搜索
java 复制代码
void DFS_AL(ALGraph G,int v){
    cout<<v;visit[v]=true;
    p=G.vertices[v].first;//输出后指向第一个边节点
    while(p!=NULL){
        w=p->adjvex;
        if(!visited[w])DFS_AL(G,w);
        p=p->nextarc;//p指向下一个结点
    }
}

广度优先遍历


算法描述:

java 复制代码
void BFS(Graph G,int v){
    cout<<v;visited[v]=true;
    Initqueue(Q);//初始化辅助队列?
    Enqueue(Q,v);//将顶点v入队
    while(!QueueEmpty(Q)){
        //如果队列不空
        DeQueue(Q,u);//队头元素出队
        for(w=FirstAdjvex(G,u);w>0;w=NextAdjvex(G,u,w));
        //依次检查u的所有邻接点w,
        if(!visited[w]){
            cout<<w;visited[w]=true;//w没有被访问过,那么输出并入队
            Enqueue(G,w);
         //每次将该顶点所有相邻的结点入队,BFS没有用到递归,而是当队列为空时结束循环,函数结束
        }
    }
}

prim算法构建最小生成树


算法描述:

java 复制代码
struct{
    int adjvex;//最小边在u中那个顶点
    int lowcost;//最小边上的权值
}closedge[100];

void prim(Graph G,int u){
    //无向网以邻接矩阵存储,从顶点y出发构造g的最小生成树t,输出t的各条边
    k=LocateVex(G,u);//找出顶点u的图中的下表
    //对v------u的每个顶点进行初始化
    for(int j=0;j<G.vexnum;j++){
        if(j!=k)closedge[j]={u,arcs[k][j]};//没看太懂
    }
    closedge[k].lowcost=0;//最小边权值初始化为0
    for(int i=1;i<G.vexnum;i++){
        //选择其余n-1个结点,生成n-1条边
        
    }
}

kruskal算法构建最小生成树


算法描述:

java 复制代码
void kruskal(Graph G){
    sort(Edge);//将数组edge中的元素按权值从小到大排序
    for(int i=0;i<G.vexnum;i++){
        Vexset[i]=i;//辅助数组vexset初始化,表示各个顶点自成一个联通分量
    }
    for(int i=0;i<G.arcnum;i++){
        //依次查看数组edge的边
       v1=Locatevex(G,Edge[i].head);//v1为边的初始点head的下标
       v2=LocateVex(G,Edge[i].Tail);//v2为边的终点tail的下标
       vs1=Vexset[v1];
       vs2=Vexset[v2];//获取v1,v2的联通分量
       if(vs1!=vs2){
           //联通分量不相同,那说明没有相连
           cout<<Edge[i].head<<Edge[i].tail;
           for(int j=0;j<G.vexnum;j++){
               if(vexset[i]==vs2)Vexset[j]=vs1;//将所有以前为vs1的联通分量都改为VS2,合并完成
           }
       }
    }
}

kruskal算法是对边进行考虑,因此适用于稀疏图

如果对于流程不太理解的画可以参照这个视频王道最小生成树,

最短路


最短路问题一般有两种:一种是求从某个原点到其中各点的最短路,一种是求每一对顶点之间的最短路径

  1. 单源最短路问题:求v0到G中其余各个顶点的最短路径。迪杰斯特拉(Dijkstra),他是按照路径长度递增的次序产生最短路径的算法,称为迪杰斯特拉算法。

算法描述:

java 复制代码
void Dijkstra(AMGraph G,int v0){
    for(int v=0;v<G.vexnum;v++){
        s[v]=false;//s数组确定最短路径长度
        D[v]=G.arcs[v0][v];//D数组记录v0到v的权值
        if(D[v]<100000)path[v]=v0;//如果有弧,就将v的前驱置为v0
        else path[v]=-1;//没有,就置为-1
    }
    s[v0]=ture;
    D[v0]=0;//原点到原点的距离为0,而且标记v0已经被访问过
    //初始化结束,开始主循环,每次求得v0到某个顶点的最短路径
    for(int i=1;i<G.vexnum;i++){//对其余n-1个顶点,依次进行考虑
        min=MAXInt;
        for(int w=0;w<G.vexnum;w++){
            if(!s[w]&&D[w]<min){
              v=w;
              min=D[w];
            }
            S[v]=true;//这个节点的最短路找到了,更新一下
        }
        for(int w=0;w<G.vexnum;w++){
            //看能不能以这个顶点为过渡,找到另一个顶点的最短路径
            if(!s[w]&&D[v]+G.arcs[v][w]<D[w]){
                D[w]=D[v]+G.arcs[v][w];//找到了,更新一下
                Path[w]=v;//更新一下前驱结点
            }
        }
    }
}

举个例子

  1. 初始化,初始化各个顶点到v1的距离,
  2. 找到一个距离v0最近的过渡结点,用这个节点遍历所有节点,看看通过这个过渡节点能不能求出比原先v0到这个节点更短的路径,并更新
  3. 为什么不能处理负权值问题呢,因为找到一个最短路,就会立即更新,比如1-->2(权值为5),2-->3(权值为-4),3-->4(权值为3)、那么根据dijkstra算法的流程,他就会先找到3-->4这条边,然后用4这个顶点去更新其他值,就导致了判断错误。

floyd算法求最短路


floyd算法用于求每一对顶点之间的最短路方法

floyd算法可以处理负权边,但是不能处理负权回路

算法描述:

java 复制代码
void Floyd(Graph G){
    for(int i=0;i<G.vexnum;i++){
        for(int j=0;j<G.vexnum;j++){
            D[i][j]=G.arcs[i][j];//记录一下初值
            if(D[i][j]<MAXint&&i!=j)path[i][j]=i;
            else path[i][j]=-1;//有通路就赋值,没有通路就赋值为-1
        }
    }
    //初始化完毕,接下来开始寻找最短路并变更路径
    for(int k=0;k<G.vexnum;k++){
        for(int i=0;i<G.vexnum;i++){
            for(int j=0;j<G.vexnum;j++){
                //k作为中转点
                if(D[i][k]+D[k][j]<D[i][j]){
                    D[i][j]=D[i][k]+D[k][j];
                    path[i][j]=path[k][j];//更改j的前驱为j
                }
            }
        }
    }
}

拓扑排序


  1. 拓扑排序的过程:

1):有向图中选一个无前驱的顶点并且输出它

2):从图中删除该顶点和所有以它为尾的弧

3):重复以上步骤,直到不存在无前驱的顶点

4):若经历了以上步骤,顶点并没有输出完毕,那么说明图中存在环

算法描述:

java 复制代码
int TopoSort(Graph G,int topo[]){
    //有向图G采用邻接表作为储存结构
    FindIndegree(G,indegree);//该函数求出各点入度并储存在该数组中
    InitStack(s);//初始化栈空间
    for(int i=0;i<G.vexnum;i++){
        //对于入度为零的点先入队
        if(!indegree[i])push(S,i);
    }
    int m=0;//对于要输出的顶点计数
    while(!StackEmpty(S)){
        //栈不空继续循环
        pop(S,i);//使栈顶顶点出栈
        topo[m++]=i;
        p=G.vertices[i].first;//p等于关于顶点i的邻接表的第一个邻接点
    }
    while(p!=NULL){
        k=p->adjvex;//k为顶点下标
        --indegree[k];
        if(indegree[k]==0)push(S,k);//入度为零的点继续入栈
        p=p->nextarc;//p指向下一个邻接点,类似于广度优先遍历,先把单个顶点的所有邻接点入栈
    }
    if(m<G.vexnum)return -1;//说明存在负环
    else return 1;
    
}
相关推荐
Ljubim.te15 分钟前
软件设计师——数据结构
数据结构·笔记
_GR1 小时前
每日OJ题_牛客_牛牛冲钻五_模拟_C++_Java
java·数据结构·c++·算法·动态规划
无限大.1 小时前
c语言实例
c语言·数据结构·算法
@haihi2 小时前
冒泡排序,插入排序,快速排序,选择排序
数据结构·算法·排序算法
coduck_S12004zbj2 小时前
csp-j模拟五补题报告
c++·算法·图论
丢掉幻想准备斗争2 小时前
数据结构(栈和队列的实现)
数据结构
zengy53 小时前
Effective C++中文版学习记录(三)
数据结构·c++·学习·stl
良月澪二5 小时前
CSP-S 2021 T1廊桥分配
算法·图论
&梧桐树夏6 小时前
【算法系列-链表】删除链表的倒数第N个结点
数据结构·算法·链表
QuantumStack6 小时前
【C++ 真题】B2037 奇偶数判断
数据结构·c++·算法