• C 语言中如何实现图结构?


    C语言

    🍅关注博主🎗️ 带你畅游技术世界,不错过每一次成长机会!
    📙C 语言百万年薪修炼课程 【https://dwz.mosong.cc/cyyjc】通俗易懂,深入浅出,匠心打磨,死磕细节,6年迭代,看过的人都说好。

    分割线

    分割线


    C 语言中如何实现图结构

    在 C 语言中,实现图结构是一项重要且具有挑战性的任务。图是一种复杂的数据结构,用于表示对象之间的关系。它由顶点(Vertex)和边(Edge)组成,可以分为有向图和无向图两种类型。

    一、图的基本概念

    1. 顶点(Vertex):图中的基本元素,表示一个独立的对象。
    2. 边(Edge):连接两个顶点的线段,表示顶点之间的关系。
    3. 有向图(Directed Graph):边具有方向,从一个顶点指向另一个顶点。
    4. 无向图(Undirected Graph):边没有方向,两个顶点之间的关系是相互的。

    二、图的表示方法

    在 C 语言中,常见的图表示方法有邻接矩阵(Adjacency Matrix)和邻接表(Adjacency List)。

    (一)邻接矩阵

    邻接矩阵是一个二维数组,用于表示图中顶点之间的连接关系。如果顶点 i 和顶点 j 之间有边相连,则矩阵中的 [i][j] 元素为 1(或边的权值);否则为 0。

    以下是使用邻接矩阵表示无向图的 C 语言示例代码:

    #include 
    #include 
    
    #define V 5  // 顶点数量
    
    // 打印邻接矩阵
    void printAdjMatrix(int adjMatrix[V][V]) {
        for (int i = 0; i < V; i++) {
            for (int j = 0; j < V; j++) {
                printf("%d ", adjMatrix[i][j]);
            }
            printf("\n");
        }
    }
    
    int main() {
        int adjMatrix[V][V] = {
            {0, 1, 0, 1, 0},
            {1, 0, 1, 0, 1},
            {0, 1, 0, 1, 0},
            {1, 0, 1, 0, 1},
            {0, 1, 0, 1, 0}
        };
    
        printf("邻接矩阵表示的无向图:\n");
        printAdjMatrix(adjMatrix);
    
        return 0;
    }
    '
    运行

    邻接矩阵的优点是直观、简单,判断两个顶点之间是否有边的时间复杂度为 O(1)。但对于稀疏图(边的数量相对较少),会浪费大量的存储空间。

    (二)邻接表

    邻接表是一种链表数组,每个数组元素是一个链表,链表中存储与该顶点相连的其他顶点。

    以下是使用邻接表表示无向图的 C 语言示例代码:

    #include 
    #include 
    
    // 图的顶点结构体
    typedef struct Vertex {
        int data;
        struct Vertex* next;
    } Vertex;
    
    // 创建新的顶点
    Vertex* createVertex(int data) {
        Vertex* newVertex = (Vertex*)malloc(sizeof(Vertex));
        newVertex->data = data;
        newVertex->next = NULL;
        return newVertex;
    }
    
    // 向邻接表中添加边
    void addEdge(Vertex* adjList[], int src, int dest) {
        Vertex* newNode = createVertex(dest);
        newNode->next = adjList[src];
        adjList[src] = newNode;
    
        newNode = createVertex(src);
        newNode->next = adjList[dest];
        adjList[dest] = newNode;
    }
    
    // 打印邻接表
    void printAdjList(Vertex* adjList[], int V) {
        for (int i = 0; i < V; i++) {
            Vertex* temp = adjList[i];
            printf("顶点 %d: ", i);
            while (temp) {
                printf("%d -> ", temp->data);
                temp = temp->next;
            }
            printf("NULL\n");
        }
    }
    
    int main() {
        int V = 5;  // 顶点数量
        Vertex* adjList[V];
    
        for (int i = 0; i < V; i++) {
            adjList[i] = NULL;
        }
    
        addEdge(adjList, 0, 1);
        addEdge(adjList, 0, 4);
        addEdge(adjList, 1, 2);
        addEdge(adjList, 1, 3);
        addEdge(adjList, 1, 4);
        addEdge(adjList, 2, 3);
        addEdge(adjList, 3, 4);
    
        printf("邻接表表示的无向图:\n");
        printAdjList(adjList, V);
    
        return 0;
    }
    '
    运行

    邻接表的优点是节省存储空间,适用于稀疏图。但查找两个顶点之间是否有边的时间复杂度相对较高。

    三、图的遍历

    图的遍历是指按照一定的顺序访问图中的所有顶点。常见的图遍历算法有深度优先搜索(Depth-First Search,DFS)和广度优先搜索(Breadth-First Search,BFS)。

    (一)深度优先搜索(DFS)

    深度优先搜索从起始顶点开始,沿着一条路径尽可能深地访问顶点,直到无法继续,然后回溯到上一个未完全探索的顶点,继续探索其他路径。

    以下是使用递归方式实现深度优先搜索的 C 语言示例代码:

    #include 
    #include 
    
    #define V 5  // 顶点数量
    
    // 邻接矩阵
    int adjMatrix[V][V] = {
        {0, 1, 0, 1, 0},
        {1, 0, 1, 0, 1},
        {0, 1, 0, 1, 0},
        {1, 0, 1, 0, 1},
        {0, 1, 0, 1, 0}
    };
    
    // 用于标记顶点是否已被访问
    int visited[V] = {0};
    
    // 深度优先搜索递归函数
    void DFS(int v) {
        visited[v] = 1;
        printf("%d ", v);
    
        for (int i = 0; i < V; i++) {
            if (adjMatrix[v][i] == 1 && visited[i] == 0) {
                DFS(i);
            }
        }
    }
    
    int main() {
        printf("深度优先搜索的结果: ");
        DFS(0);
    
        return 0;
    }
    '
    运行

    (二)广度优先搜索(BFS)

    广度优先搜索从起始顶点开始,先访问其所有相邻顶点,然后依次访问这些相邻顶点的相邻顶点,依此类推。

    以下是使用队列实现广度优先搜索的 C 语言示例代码:

    #include 
    #include 
    
    #define V 5  // 顶点数量
    
    // 邻接矩阵
    int adjMatrix[V][V] = {
        {0, 1, 0, 1, 0},
        {1, 0, 1, 0, 1},
        {0, 1, 0, 1, 0},
        {1, 0, 1, 0, 1},
        {0, 1, 0, 1, 0}
    };
    
    // 用于标记顶点是否已被访问
    int visited[V] = {0};
    
    // 队列结构体
    typedef struct Queue {
        int* items;
        int front;
        int rear;
    } Queue;
    
    // 创建队列
    Queue* createQueue(int size) {
        Queue* queue = (Queue*)malloc(sizeof(Queue));
        queue->items = (int*)malloc(size * sizeof(int));
        queue->front = -1;
        queue->rear = -1;
        return queue;
    }
    
    // 判断队列是否为空
    int isEmpty(Queue* queue) {
        return queue->front == -1;
    }
    
    // 判断队列是否已满
    int isFull(Queue* queue, int size) {
        return (queue->rear + 1) % size == queue->front;
    }
    
    // 入队
    void enqueue(Queue* queue, int item) {
        if (isFull(queue, V)) {
            printf("队列已满\n");
            return;
        }
    
        if (isEmpty(queue)) {
            queue->front = 0;
        }
    
        queue->rear = (queue->rear + 1) % V;
        queue->items[queue->rear] = item;
    }
    
    // 出队
    int dequeue(Queue* queue) {
        int item;
        if (isEmpty(queue)) {
            printf("队列为空\n");
            return -1;
        }
    
        item = queue->items[queue->front];
        if (queue->front == queue->rear) {
            queue->front = -1;
            queue->rear = -1;
        } else {
            queue->front = (queue->front + 1) % V;
        }
        return item;
    }
    
    // 广度优先搜索函数
    void BFS(int start) {
        Queue* queue = createQueue(V);
    
        visited[start] = 1;
        printf("%d ", start);
        enqueue(queue, start);
    
        while (!isEmpty(queue)) {
            int current = dequeue(queue);
    
            for (int i = 0; i < V; i++) {
                if (adjMatrix[current][i] == 1 && visited[i] == 0) {
                    visited[i] = 1;
                    printf("%d ", i);
                    enqueue(queue, i);
                }
            }
        }
    
        free(queue->items);
        free(queue);
    }
    
    int main() {
        printf("广度优先搜索的结果: ");
        BFS(0);
    
        return 0;
    }
    '
    运行

    四、图的应用

    图在计算机科学中有广泛的应用,以下是一些常见的应用场景:

    (一)网络路由

    在计算机网络中,图可以用于表示网络拓扑结构,通过图算法找到最优的路由路径。

    (二)社交网络分析

    分析社交网络中人与人之间的关系,例如找出朋友关系中的社群结构。

    (三)任务调度

    在操作系统中,安排任务的执行顺序和资源分配。

    (四)地图导航

    地图可以被看作是一个图,通过图算法找到最短路径或最优路径。

    五、总结

    在 C 语言中实现图结构需要对图的基本概念有清晰的理解,选择合适的表示方法(邻接矩阵或邻接表),并掌握图的遍历算法(深度优先搜索和广度优先搜索)。根据具体的应用场景和图的特点,选择最优的实现方式和算法,以提高程序的效率和性能。


    分割线

    🎉相关推荐

    分割线



  • 相关阅读:
    tinyxml2开源库使用
    企业架构LNMP学习笔记51
    【Qt】控件探幽——QComboBox
    【Docker】ubuntu20.04 X86机器搭建NVIDIA ARM64 TX2的Docker镜像
    static和const关键字的区别
    如何安全高效地进行分公司文件下发?
    容器化|自建 MySQL 集群迁移到 Kubernetes
    双亲委派模型
    记录一次排查OOM记录 mac电脑
    关系数据库事务中的对象锁定
  • 原文地址:https://blog.csdn.net/zenson_g/article/details/140344056