zoukankan      html  css  js  c++  java
  • 一.概念

    无向图:G = (V ,  E)(Vertex顶点,Edge边)

    无向完全图:任意2个节点相连      Cn2条 = n(n-1) / 2

    连通图:任意两个节点之间有路径课通。

    极大连通子图:G` = (V` , E`)   V` € V , E` € E,  G` € G 

    极大连通分量:几个极大连通子图

    度:最大为n-1

    边:(v1,v5) (v5,v1) 依附于顶点v1,v5   是同一个意思

    有向图:G = <V , E>   <顶点,弧>   弧包括弧头和弧尾 

    有向完全图;任意两个顶点之间都要两条弧    An2   n(n-1)

    度:入度(被指向) , 出度(指出去)  二者相加为度

    n个顶点的无向图  ,边数多少可能为连通图,   n-1

    n个顶点的无向图  ,边数多少一定为连通图,  (n-1)(n-2)/2+1

    二.图的创建:

    1.邻接矩阵   无向图关于对角线对称  

    2.邻接接表

    边多用矩阵,边少用邻接链表

    矩阵唯一,链表不唯一(无序)

    代码:对于二维数组的申请,二维数组本质上是以为数组,所以我们申请一个长度为v*v的以为数组,通过下标来定位行和列。

    或者申请一个装着指针,长度为v的一维数组,再给每一个指针申请长度为v的int型数组。这样做可以实现二维数组的功能。但是,每一行的地址不是连续的,不是真正意义上的二维数组。

    typedef struct node
    {
        int nVertex;
        int nEdge;
        int *p;
    }Graph;
    Graph* create()
    {
        /*int **arr =(int**) malloc(sizeof(int*)*n);
        for(int i = 0 ; i < n; i++)
            arr[i] = (int*)malloc(sizeof(int)*n);
        for(int i = 0; i < n; i++)
            for(int j = 0; j < n; j++)
                arr[i][j] = 0;*/
        Graph* pGraph = (Graph*)malloc(sizeof(Graph));
        int v,e;
        printf("请输入图的顶点和边数
    ");
        scanf("%d%d",&v,&e);
        pGraph->nVertex = v;
        pGraph->nEdge = e;
        pGraph->p =(int*) malloc(sizeof(int)*v*v);
        memset(pGraph->p,0,sizeof(int)*v*v);
        int v1,v2;
        for(int i = 0; i < e;i++)
        {
            printf("请输入两个顶点确定一条边
    ");
            scanf("%d%d",&v1,&v2);
            if(v1>=1 && v2>=1 && v1<=v && v2<=v && v1!=v2 && pGraph->p[(v1-1)*v+v2-1] == 0)
            {
                pGraph->p[(v1-1)*v+(v2-1)] = 1;
                pGraph->p[(v2-1)*v+(v1-1)] = 1;
            }
            else
            {
                i--;
            }
        }
    
        return pGraph;
    }

    三.图的遍历:

    深度优先遍历DFS:

    测试数据:6 9   1 2 ; 1 3 ;1 4;2 3; 2 4;2 5;3 4;3 6;4 5;

    则矩阵为: 

          0  1  1  1  0  0
          1  0  1  1  1  0
          1  1  0  1  0  1
          1  1  1  0  1  0
          0  1  0  1  0  0
          0  0  1  0  0  0

    思路:假设从顶点1开始,

        第一行:v2为1且没有标记过,则跳转至第二行。

        第二行:v1标记过,v3为1且没被标记过,则跳至第三行。

        第三行:v1,v2为1但被标记过,v4为1且没被标记过,则跳转至第4行。

        第四行:v1,v2,v3为1但被标记过,v5为1且没被标记过,则跳转至第5行。

        第五行:v2,v4为1但被标记过。查看第五行是由第四行跳转来的,则返回原来位置继续查找。

        第四行:第四行没有能跳转的节点,则返回地三行的原来位置。

        第三行:v6为1且没被标记过,则跳转至第6行。

        第六行:v3为1但被标记过。则返回第三行的原来位置。

        第三行:没有节点跳转。则返回第二行原来位置。

        第二行:没有v4,v5为1且被标记过。则返回第一行原来的位置。

        第一行:v3,v4为1但被标记过。结束。

    所以要申请额外的标记数组:

    void DFS(Graph* pGraph,int n,int* arr)
    {
        printf("%d ",n);
        arr[n] = 1;
        for(int i = 1; i <= pGraph->nVertex; i++)
        {
            if(pGraph->p[(n-1)*pGraph->nVertex+i-1] == 1 && arr[i] == 0)
            {
                DFS(pGraph,i,arr);
            }
        }
    }
    void MyDFS(Graph* pGraph,int n)
    {
        int* arr = (int*)malloc(sizeof(int) * (pGraph->nVertex));
        memset(arr,0,sizeof(arr));
        DFS(pGraph,n,arr);
    }

    广度优先遍历BFS:

    思路:与树的BFS十分相似,需要借助辅助队列,

      假设从第一个节点开始,则将第一行为1的节点标记后,压入队列。然后再将队列中的第一个元素所在行,为1的节点标记后压入队列。

    void BFS(Graph* pGraph,int begin)
    {
        Queue* myqueue = Init();
        int* arr = (int*) malloc(sizeof(int)*pGraph->nVertex);
        memset(arr,0,sizeof(arr)*pGraph->nVertex);
        arr[begin-1] =1;
        Push(myqueue,begin);
        while(!IsEmpty(myqueue))
        {
            begin = Pop(myqueue);
            printf("%d ",begin);
            for(int i = 0; i < pGraph->nVertex; i++)
            {
                if(pGraph->p[(begin-1)*pGraph->nVertex + i] == 1 && arr[i] == 0 )
                {
                    arr[i] = 1;
                    Push(myqueue,i+1);
                }
            }
        }
    }
  • 相关阅读:
    第三方登录(QQ登录)开发流程详解
    网页优化方案
    linux中PHP链接MySQL主机127.0.0.1与localhost
    RSync实现文件备份同步
    网站攻击以及解决方案
    迎难而上,QPS提高22+倍
    新的一扇窗
    边缘计算开源平台
    高并发分布式计算-生产实践
    分布式UUID的生成
  • 原文地址:https://www.cnblogs.com/Lune-Qiu/p/9076338.html
Copyright © 2011-2022 走看看