数据结构与算法--图的存储与遍历

回顾

  • 线索化二叉树:在某种次序遍历过程中创建线索,将空指针指向遍历序列中的前驱或后继结点。
  • 线索二叉树:经过线索化处理的二叉树。
  • 哈夫曼树(最优二叉树):带权路径长度WPL最小的二叉树。

提要

  • 图的定义和表示。
  • 图的相关概念。
  • 图的存储结构与实现。
  • 图的遍历方法。

图的定义和表示

G由顶点集合V和边集合E组成,记为G = (V, E)

  • V是顶点元素的有限集合,

  • E是顶点间关系——边的有限集合。

  • (边是顶点的无序对或有序对)
    在这里插入图片描述

  • 无向图:边没有方向,由顶点的无序对组成。

    • 在这里插入图片描述

    • 由没有方向的边构成的图。

    • 无向图中的边由顶点的无序对组成。(用圆括号表示)

    • 邻接点:无向图中,若存在一条边(Vi, Vj),则称Vi和Vj互为邻接点。

    • 右图中的边是无方向的,

    • 即 (V1, V2) 和 (V2, V1)

    • 表示同一条边。

    • 在这里插入图片描述

  • 有向图:边有方向,由顶点的有序对组成,称为弧。

    • 在这里插入图片描述

    • 由有方向的边构成的图。

    • 弧:有向图中的边由顶点的有序对组成,也称作弧。(用尖括号表示)

    • 有向图中,顶点的有序对<Vi, Vj>表示从Vi指向Vj的一条有向边,其中Vi是起点,Vj是终点。

    • 右图中的边是有方向的,

    • <V1, V2> 和 <V2, V1>

    • 表示两条不同的边。

    • 在这里插入图片描述

图的表示

  • 邻接矩阵:使用二维数组表示,其中matrix[i][j]表示顶点i到顶点j的边的信息。
  • 邻接表:使用链式存储结构,包含顶点表和边表。
  • 在这里插入图片描述
完全图和子图

子图:对于图G=(V,E)和图G´=(V´,E´),若存在V´  V且E´  E,则称图G´是图G的子图。
在这里插入图片描述
在这里插入图片描述

顶点的度

无向图中,顶点的度指与每个顶点相连的边数。
有向图中,顶点的度分成入度与出度。
入度:以该顶点为终点的弧的数目
出度:以该顶点为起点的弧的数目
在这里插入图片描述

路径与回路

在这里插入图片描述
在这里插入图片描述

连通图

在这里插入图片描述
在这里插入图片描述

邻接矩阵

在这里插入图片描述

有向图和无向图的邻接矩阵表示方法。
在这里插入图片描述

权和网

在这里插入图片描述
在这里插入图片描述

邻接表

  • 顶点表:存放图中每个顶点的信息及指向边表的头指针。由顶点表和边表组成,是链式存储结构。

  • 在这里插入图片描述

  • 在这里插入图片描述

  • 顶点表:存放图中每个顶点的信息以及指向该顶点边表的头指针。顶点表通常采用顺序存储结构。

    • 顶点表的结点结构:
    • 顶点域data存放顶点信息,head为边表头指针。
    • 在这里插入图片描述
    • 在这里插入图片描述
  • 边表:为图中每个顶点建立的单链表,存放相邻接的邻接点。

    • 边表的结点结构:在这里插入图片描述

    • 邻接点域adjVex存放邻接点在顶点表中的序号,next为指向下一个邻接点的指针。

    • 在这里插入图片描述
      在这里插入图片描述

示例

在这里插入图片描述
在这里插入图片描述

  • 逆邻接表:结构与邻接表完全相同,只是边表中每个结点存放的是每条弧的弧尾顶点。
  • 在这里插入图片描述

深度优先遍历 (DFS)

遍历过程:

  1. 从任一顶点出发,访问此顶点。
  2. 选择一个未访问的邻接点,再从w出发进行深度优先遍历(递归),直至图中所有和v连通的顶点都被访问过为止;
  3. 访问所有连通顶点后,若存在未访问顶点,重复以上步骤。直至图中所有顶点都被访问为止。
    在这里插入图片描述
    示例:深度优先遍历无向图在这里插入图片描述
    示例:深度优先遍历有向图
    在这里插入图片描述

广度优先遍历 (BFS)

遍历过程:

  1. 从任一顶点出发,访问此顶点。
  2. 访问所有未访问的邻接点,然后是它们的邻接点,依此类推。
  3. 若存在未访问顶点,则另选图中一个未被访问的顶点作起点,重复以上步骤。
    在这里插入图片描述
    示例:广度优先遍历无向图
    在这里插入图片描述
    示例:广度优先遍历有向图
    在这里插入图片描述

广度优先遍历过程

使用队列完成广度优先遍历。
在这里插入图片描述

总结

  • 图的结构特点。
  • 图与线性表和树的区别。
  • 图的两种存储结构:邻接矩阵和邻接表。
  • 图的两种遍历方法:深度优先和广度优先。

以下是代码示例,展示如何使用C++实现图的邻接矩阵和邻接表存储结构,以及深度优先遍历和广度优先遍历的算法。

邻接矩阵存储结构

#include <iostream>
#include <vector>

const int MAX_V = 100;  // 假设顶点数不超过100

void dfs(int v, std::vector<std::vector<int>>& graph, std::vector<bool>& visited) {
    visited[v] = true;
    std::cout << v << " ";  // 访问顶点

    // 遍历所有邻接顶点
    for (int i = 0; i < graph[v].size(); ++i) {
        int nextV = graph[v][i];
        if (!visited[nextV]) {
            dfs(nextV, graph, visited);
        }
    }
}

int main() {
    std::vector<std::vector<int>> graph = {
        {1, 2},
        {0, 3},
        {0, 4},
        {0},
        {1}
    };
    std::vector<bool> visited(MAX_V, false);

    dfs(0, graph, visited);  // 从顶点0开始深度优先遍历
    return 0;
}

邻接表存储结构

struct AdjListNode {
    int dest;
    AdjListNode* next;
};

struct AdjList {
    AdjListNode* head;
};

struct Graph {
    int numVertices;
    AdjList* arrays;
};

void addEdge(Graph* graph, int src, int dest) {
    AdjListNode* newNode = new AdjListNode{dest, graph->arrays[src].head};
    graph->arrays[src].head = newNode;
}

void dfs(Graph* graph, int v, std::vector<bool>& visited) {
    visited[v] = true;
    std::cout << v << " ";  // 访问顶点

    AdjListNode* node = graph->arrays[v].head;
    while (node) {
        int nextV = node->dest;
        if (!visited[nextV]) {
            dfs(graph, nextV, visited);
        }
        node = node->next;
    }
}

// 广度优先遍历使用队列的示例
void bfs(Graph* graph, int start, std::vector<bool>& visited) {
    std::queue<int> queue;
    visited[start] = true;
    queue.push(start);

    while (!queue.empty()) {
        int v = queue.front();
        queue.pop();
        std::cout << v << " ";  // 访问顶点

        AdjListNode* node = graph->arrays[v].head;
        while (node) {
            int nextV = node->dest;
            if (!visited[nextV]) {
                visited[nextV] = true;
                queue.push(nextV);
            }
            node = node->next;
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值