一些题目 - wolai 笔记

1.无向图连通分量

问题

求邻接表存储结构的无向图的连通分量的个数,并输出每个连通分量的顶点集

算法思想

  • 用深度优先搜索,先从任意一个顶点开始进行深度优先搜索;
  • 输出每一个遍历到的结点,搜索完后,连通分量个数增加1;
  • 然后再从没有遍历过的顶点找一个出来进行DFS, 搜索完成后,连通分量个数加一;
  • 直到所有的顶点都被遍历过。

代码

深度优先搜索
// 标记数组
bool visited[MAX_VERTEX] = { false };
void DFS(ALGraph* ALG, VertexType v)
{
    // 访问标记
    visited[v] = true;
    printf("->%d", v);
    // 获得头结点地址
    ArcNode* pArcNode = ALG->vertices[v].firstArc;
    int neighborVertex = 0;
    // 重复取邻居结点
    while (pArcNode != NULL)
    {
        neighborVertex = pArcNode->adjvex;
        // 重复取邻居结点,其存在弧结点
        if (visited[neighborVertex] != true)
            DFS(ALG, neighborVertex);
        // 取下一个弧结点
        pArcNode = pArcNode->next;
    }
}
搜索连通分量
bool searchConnectedComponentGraph(ALGraph* ALG)
{
    // 连通分量个数
    int count = 0;
    for (int i = 1; i <= ALG->vexNum; i++)
    {
        if (visited[i] != true)
        {
            DFS(ALG, i);
            count++;    // 连通分量个数加一
            printf("\n");
        }
    }
    printf("count:%d\n", count);
    return true;
}

测试

2.最短距离为K的路径

问题

求出无向连通图中距离顶点V0的最短距离长度为K的所有结点

算法思想

  • 给顶点信息增加一个层信息,初始为0层;
  • 使用BFS访问队列顶部元素的邻居结点;
  • 邻居结点的层数等于出队列顶点层数加一;
  • 当邻居结点层数等于k时,输出邻居结点,并不将邻居节点压入队列中;
  • 若邻居结点层数不等于k,则将邻居结点压入队列中;
  • 循环遍历。

代码

void computeShortestPathNodes(ALGraph* ALG, VertexType v0, int k)
{
    // 初始化队列
    Queue Q;
    initQueue(Q);
    visited[v0] = true;
    // 给顶点增加层信息
    QueueElemType elem;
    elem.vex = v0;
    elem.level = 0;
    enQueue(Q, elem);
    while (!emptyQueue(Q))
    {
        QueueElemType tmp;
        deQueue(Q, tmp);
        int level = tmp.level;
        ArcNode* pArcNode = ALG->vertices[tmp.vex].firstArc;
        // 访问邻居结点
        while (pArcNode != NULL)
        {
            if (visited[pArcNode->adjvex] == false)
            {
                visited[pArcNode->adjvex] = true;
                // 将邻居结点加入队列
                // 若层信息等于k,则输出结点,跳过后序循环
                tmp.vex = pArcNode->adjvex;
                tmp.level = level + 1;
                if (tmp.level == k)
                {
                    printf("%d  ", tmp.vex);
                    continue;
                }
                enQueue(Q, tmp);
            }
            pArcNode = pArcNode->next;
        }
    }
}

3.图的根

问题

在有向图G中,如果rG中的每个节点都有路径可达,则称结点rG的根结点,判断图G是否有根,若有,打印所有的根结点

算法思想

  • 设置一个全局变量,用来记录DFS访问结点的个数;
  • DFS访问过结点的个数为顶点数,则此顶点为根,将根打印即可。

代码

int nodeCount = 0;
// 深度优先遍历所有根结点
void DFSRoot(ALGraph ALG, VertexType v)
{
    visited[v] = true;
    // 访问结点数量加一
    nodeCount++;
    ArcNode* pArcNode = ALG.vertices[v].firstArc;
    while (pArcNode != NULL)
    {
        if (visited[pArcNode->adjvex] != true)
            DFSRoot(ALG, pArcNode->adjvex);
        pArcNode = pArcNode->next;
    }
}
int graphRootDFS(ALGraph ALG)
{
    // 初始标记数组
    for (int v = 1; v <= ALG.vexNum; v++)
    {
        visited[v] = false;
    }
    // 依次访问每一个节点,查找是否是根结点
    for (int i = 1; i <= ALG.vexNum; i++)
    {
        DFSRoot(ALG, i);
        // 如果等于顶点数目,则是根结点
        if (nodeCount == ALG.vexNum)
            printf("root: %d\n", i);
        // 将访问数组、全局计数变量清除
        for (int v = 1; v <= ALG.vexNum; v++)
        {
            visited[v] = false;
        }
        nodeCount = 0;
    }
}

4.BFS改进

问题

图的D遍历类似于BFS,不同之处在于使用栈代替BFS中的队列,入队操作改为入栈操作,即当作一个顶点的所有邻接点被搜索之后,下一个搜索出发点应该是最近入栈(栈顶)的顶点。用邻接表做储存结构,编写D遍历算法。

算法思想

BFS中的队列换为栈即可。

代码

从某顶点开始D遍历
void DBFS(ALGraph* ALG, VertexType v)
{
    Stack S;
    initStack(S);
    // 压入栈时,要标记,防止重复
    visited[v] = true;
    push(S, v);
    // 栈不为空,循环出栈
    while (!emptyStack(S))
    {
        StackType elem;
        pop(S, elem);
        printf("->%d ", elem);
        ArcNode* pArcNode = ALG->vertices[elem].firstArc;
        while (pArcNode != NULL)
        {
            if (visited[pArcNode->adjvex] != true)
            {
                visited[pArcNode->adjvex] = true;
                push(S, pArcNode->adjvex);
            }
            pArcNode = pArcNode->next;
        }
    }
}
D遍历
void DBFSTraverse(ALGraph* ALG)
{
    for (int i = 1; i <= ALG->vexNum; i++)
    {
        visited[i] = false;
    }
    for (int i = 1; i <= ALG->vexNum; i++)
    {
        if (visited[i] != true)
        {
            DBFS(ALG, i);
            printf("\n");
        }
    }
}

5.图G顶点编号

问题

G=(V, E)是一个以邻接表存储的有向无环图,编写一个给图G中每一个顶点赋一个整型序号的算法,并满足以下条件:从顶点i到顶点j有一条弧,则应使i<j。

算法思想

  • 有向无环”,优先考虑拓扑排序
  • DFS逆拓扑排序实现,需要辅助数组或栈
  • BFS 拓扑排序,不需要辅助空间

代码

访问标记数组和全局变量
// 数据标记,大于0,则给相应顶点赋了序号
int visitNum[MAX_VERTEX] = { 0 };
int globalCount = 100;  // 很大的数,给顶点赋值
从一个顶点DFS遍历,在顶点退出时,给顶点序号
void DFSSort(ALGraph* ALG, VertexType v)
{
    visitNum[v] = 1;
    ArcNode* pArcNode = ALG->vertices[v].firstArc;
    while (pArcNode != NULL)
    {
        if (visitNum[pArcNode->adjvex] == 0)
            DFSSort(ALG, pArcNode->adjvex);
        pArcNode = pArcNode->next;
    }
    visitNum[v] = globalCount--;
}
分别遍历每一个,并打印序号
void orderVertexTopo(ALGraph* ALG)
{
    for (int i = 1; i <= ALG->vexNum; i++)
    {
        visitNum[i] = 0;
    }
    for (int i = 1; i <= ALG->vexNum; i++)
    {
        if (visitNum[i] == 0)
            DFSSort(ALG, i); 
    }
    for (int i = 1; i <= ALG->vexNum; i++)
    {
        printf("%d ", visitNum[i]);
    }
    printf("\n");
}

6.逆邻接表拓扑排序

问题

在逆邻接表上实现拓扑排序算法

算法思想

逆邻接表的DFS与邻接表的BFS拓扑排序的结果时一样的
邻接表的DFS与逆邻接表的DFS是逆序的
邻接表的DFS与邻接表的BFS是逆序的

代码

标记、数组定义
bool visited[MAX_VERTEX] = { false };
VertexType path[MAX_VERTEX];
int pathLength = 0;
从某一顶点拓扑排序
void invALGDFS(ALGraph* ALG, VertexType v)
{
    visited[v] = true;
    ArcNode* pArcNode = ALG->vertices[v].first;
    while (pArcNode != NULL)
    {
        if (visited[pArcNode->adjvex] != true)
            invALGDFS(ALG, pArcNode->adjvex);
        pArcNode = pArcNode->next;
    }
    // 退出时,将顶点存到数组中
    path[pathLength++] = v;
}
全部顶点拓扑排序
void invALGTopoSort(ALGraph* ALG)
{
    // 标记数组为false
    for (int i = 1; i <= ALG->vexnum; i++)
    {
        visited[i] = false;
    }
    // 逆邻接表DFS拓扑排序
    for (int i = 1; i <= ALG->vexnum; i++)
    {
        if (visited[i] != true)
            invALGDFS(ALG, i);
    }
    for (int i = 0; i < pathLength; i++)
    {
        printf("%d ", path[i]);
    }
    printf("\n");
}

测试




Comment