【C语言进阶教程】数据结构与算法(7.图 8.常见算法 9.项目实践)

第七章 图 (Graph)

图是一种复杂的数据结构,广泛应用于计算机科学各个领域,如社交网络、通信网络、导航系统等。理解图的基本概念和相关算法,可以帮助我们解决许多现实世界的问题。

7.1 图的基本概念和术语
  • 图(Graph):由顶点(Vertex)和边(Edge)组成的集合。其中,顶点表示数据元素,边表示顶点之间的关系。
  • 有向图(Directed Graph):边有方向性的图,表示从一个顶点指向另一个顶点的关系。
  • 无向图(Undirected Graph):边无方向性的图,表示两个顶点之间的双向关系。
  • 加权图(Weighted Graph):边带有权重的图,权重通常表示连接两顶点的代价或距离。
  • 路径(Path):从一个顶点出发经过多个顶点到达另一个顶点的序列。
  • 环(Cycle):路径的起始顶点和终止顶点相同。
  • 连通图(Connected Graph):任意两个顶点之间都有路径相连的图。
  • 稠密图与稀疏图:稠密图的边数接近最大可能数;稀疏图的边数远小于可以存在的最大数。
7.2 图的表示方法
  • 邻接矩阵(Adjacency Matrix):使用一个二维数组表示图的连接关系,其中 matrix[i][j] 表示顶点 i 和顶点 j 之间的边。

    • 易于实现和理解,但对于稀疏图占用较多空间。
  • 邻接表(Adjacency List):使用数组加链表(或向量)来存储每个顶点的邻接顶点。

    • 空间效率高,尤其适合稀疏图。
7.3 深度优先搜索 (DFS)

深度优先搜索是一种遍历图的方法,尽可能地深入访问节点。

  • 思想:优先访问未访问过的邻接顶点,直至无法前进再回溯。
  • 应用
    • 检测环
    • 拓扑排序
void DFS(Graph *graph, int vertex, bool visited[]) {
   
    visited[vertex] = true;
    printf("Visited %d\n", vertex);
    for (int v: graph->adj[vertex]) {
   
        if (!visited[v]) {
   
            DFS(graph, v, visited);
        }
    }
}
7.4 广度优先搜索 (BFS)

广度优先搜索遍历当前顶点的所有邻接顶点后,再逐层深入。

  • 思想:使用队列存储中间节点,从而按层次遍历。
  • 应用
    • 最短路径搜索(无权图)
    • 分层图处理
void BFS(Graph *graph, int start) {
   
    bool *visited = (bool *)malloc(graph->numVertices * sizeof(bool));
    memset(visited, false, graph->numVertices);
    Queue *queue = createQueue();
    enqueue(queue, start);
    visited[start] = true;
    while (!isEmpty(queue)) {
   
        int vertex = dequeue(queue);
        printf("Visited %d\n", vertex);
        for (int v: graph->adj[vertex]) {
   
            if (!visited[v]) {
   
                visited[v] = true;
                enqueue(queue, v);
            }
        }
    }
}
7.5 最短路径算法
  • Dijkstra算法:求解非负权重单源最短路径。

    • 使用优先队列实现可以提高效率。
  • Floyd-Warshall算法:适用于任意权重图求解多源最短路径。

    • 借助动态规划更新距离矩阵。
7.6 最小生成树

最小生成树是一种无向图中包含所有顶点的最小权重树。

  • Prim算法:从一个节点开始逐步扩展生成树。

    • 适合稠密图。
  • Kruskal算法:按边权重递增顺序选择边构成生成树。

    • 适合稀疏图,采用并查集实现有助于提高效率。

通过本章的学习,您将能够掌握图的基本概念、表示方法以及常用算法的实现和应用,为解决各种图相关的实际问题奠定坚实基础。

第八章 常见算法

在本章节中,我们将介绍一些常用的算法,包括排序算法、搜索算法,以及递归与回溯方法。这些算法不仅在计算机科学中具有广泛的应用,也是编程面试中常见的考核知识点。

8.1 排序算法

排序算法用于将一组无序元素排列为有序序列。在不同场景下选择合适的排序算法可以显著提高程序的效率。

8.1.1 冒泡排序 (Bubble Sort)

冒泡排序是一种简单但效率较低的排序算法。它通过多次遍历需要排序的列表,逐步将较小的元素移动到前面。

  • 特点
    • 时间复杂度为 (O(n^2))
    • 对小规模数据较易实现
    • 在几乎有序的数据上表现较好
void bubbleSort(int arr[], int n) {
   
    for (int i = 0; i < n-1; i++) {
   
        for (int j = 0; j < n-i-1; j++) {
   
            if (arr[j] > arr[j+1]) {
   
                int temp = arr[j];
                arr[j] = arr[j+1];
                arr[j+1] = temp;
            }
        }
    }
}
8.1.2 选择排序 (Selection Sort)

选择排序通过不断地选择剩余元素中的最小(或最大)元素并将其放置到正确的位置来进行排序。

  • 特点
    • 时间复杂度为 (O(n^2))
    • 相对较少的交换操作
    • 不稳定
void selectionSort(int arr[], int n) {
   
    for (int i = 0; i < n-1; i++) {
   
        int min_idx = i;
        for (int j = i+1; j < n; j++) {
   
            if (arr[j] < arr[min_idx])
                min_idx = j;
        }
        int temp = arr[min_idx];
        arr[min_idx] = arr[i];
        arr[i] = temp;
    }
}
8.1.3 插入排序 (Insertion Sort)

插入排序通过构建有序序列,对未排序的数据,在已排序序列中从后向前扫描,找到相应位置插入。

  • 特点
    • 时间复杂度为 (O(n^2))(但在数据接近排序的情况下效率高)
    • 稳定
    • 适用于小数据集或输入数据接近排序时
void insertionSort(int arr[], int n) {
   
    for (int i = 1; i < n; i++) {
   
        int key = arr[i];
        int j = i - 1;
        while (j >= 0 && arr[j] > key) {
   
            arr[j + 1] = arr[j];
            j = j - 1;
        }
        arr[j + 1] = key;
    }
}
8.1.4 归并排序 (Merge Sort)

归并排序是一种分治算法,通过递归将数组分为两个子数组,并将排序后的子数组合并。

  • 特点
    • 时间复杂度为 (O(n \log n))
    • 稳定
    • 适合排序大型数据集
void merge(int arr[], int l, int m, int r) {
   
    int n1 = m - l + 1;
    int n2 = r - m;
    int L[n1], R[n2];
    for (int i = 0; i < n1; i++)
        L[i] = arr[l + i];
    for (int j = 0; j < n2; j++)
        R[j] = arr[m + 1 + j];
    int i = 0, j = 0, k = l;
    while (i < n1 && j < n2) {
   
        if (L[i] <= R[j]) {
   
            arr[k] = L[i];
            i++;
        } else {
   
            arr[k] = R[j];
            j++
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值