C语言基础(二十七)

news2024/9/27 9:23:58

1、位字段(Bit-fields)也是一种数据结构,允许在结构体(struct)或联合体(union)中定义其成员占用特定的位数。对于需要精确控制内存布局或处理硬件寄存器映射等场景非常有用。位字段使得开发者能够定义小于一个字节的变量,从而更有效地利用内存空间。位字段的声明方式是在结构体或联合体的成员后面加上冒号和该成员所占的位数。

测试代码:

#include <stdio.h>  
// 温馨提示:本程序不能在实际的硬件环境中运行,仅做示例。
// 位字段 
// 硬件寄存器结构体  
struct hardware_registers {  
    unsigned int control: 1;  // 控制位  
    unsigned int mode: 2;     // 模式选择位
    unsigned int speed: 3;    // 速度控制位
    unsigned int : 0;         // 填充位,不占用空间  
    unsigned int status: 1;   // 状态位,只读  

    // 其他寄存器...  
    // unsigned int another_register: 8;  
};  
  
// 硬件寄存器地址(硬件的物理地址,代码无法直接运行,0x12345678不是一个有效的硬件地址。)   
volatile struct hardware_registers *hardware = (volatile struct hardware_registers *)0x12345678;  
  
// 写入硬件寄存器的函数  
void write_hardware_register(void) {  
    // 设置控制位为1,模式为2(从0开始计数),速度为4(同样从0开始)  
    hardware->control = 1;  
    hardware->mode = 2;  
    hardware->speed = 4;  
    // 检查写入是否成功(需要读取状态寄存器)  
    // check_hardware_status();  
}  
  
// 读取硬件状态并打印的函数  
void read_hardware_status(void) {  
    // 读取状态位 
    if (hardware->status) {  
        printf("Hardware is in active state.\n");  
    } else {  
        printf("Hardware is in inactive state.\n");  
    }  
}  
  
int main() {  
    // 写入硬件寄存器  
    write_hardware_register();  
  
    // 读取并打印硬件状态  
    read_hardware_status();  
  
    return 0;  
}  
 

.........................................................................................................................................................   

2、邻接表通过为每个顶点维护一个链表来存储与该顶点相邻的所有顶点,从而高效地存储和访问图中的边。 

测试代码:

#include "date.h" 
#include <stdio.h>  
#include <stdlib.h>   
#define MAX_VERTICES 100  
// AdjListNode 表示邻接表中的一个节点,包含目标顶点和指向下一个节点的指针。 
typedef struct AdjListNode {  
    int dest;  
    struct AdjListNode* next;  
} AdjListNode;  
// AdjList 包含一个指向邻接表头部的指针。 
typedef struct AdjList {  
    struct AdjListNode* head; 
} AdjList;  
//  Graph是一个结构体(struct),表示图论中的图。
// 结构体通常会包含顶点的数组(或指针数组)以及某种形式表示边(比如:邻接矩阵、邻接表等)。

// Graph 包含顶点数和一个指向邻接表数组的指针。
typedef struct Graph {  
    int V;  
    struct AdjList* array;  
} Graph;  
  
// 函数声明 
void addEdge(Graph* graph, int src, int dest);  
void printGraph(Graph* graph);  
void DFS(Graph* graph, int v, int visited[]);  
void BFS(Graph* graph, int s);  
  
// newAdjListNode 函数:创建一个新的邻接表节点,其中 dest 参数表示目标顶点。
// 使用动态内存分配分配一个新的节点,并将目标顶点赋值给新节点的 dest 字段,
// 并将 next 字段设为 NULL。最后返回新节点的指针。
// 函数定义开始,接收一个整型参数dest,返回一个指向AdjListNode类型的指针  
AdjListNode* newAdjListNode(int dest) {  
    // 使用malloc函数动态分配内存给一个新的AdjListNode结构体实例  
    // sizeof(AdjListNode)计算AdjListNode结构体所需的总字节数  
    // (AdjListNode*)类型转换,将void*类型的malloc返回值转换为AdjListNode*类型  
    // 分配的内存地址被存储在newNode指针中  
    AdjListNode* newNode = (AdjListNode*) malloc(sizeof(AdjListNode));  

    // 将传入的dest参数赋值给新节点的dest成员变量  
    // dest成员变量通常用于存储与该节点相关联的顶点或边的信息  
    newNode->dest = dest;  
  
    // 初始化新节点的next指针为NULL  
    // next指针用于指向链表中的下一个节点,初始时为NULL表示链表结束  
    newNode->next = NULL;  
  
    // 返回新创建的节点指针  
    return newNode;  
} 
// createGraph 函数:创建一个新的图,其中 vertices 参数表示图中顶点的数量。
// 首先分配一个 Graph 结构体的空间,然后设置顶点的数量。
// 然后再分配一个邻接表数组的空间,并对每个邻接表头部进行初始化。
// 最后返回创建的图的指针。
// vertices 作为参数,表示图中顶点的数量。函数返回一个指向 Graph 类型的指针。 
Graph* createGraph(int vertices) {  
    // 为 Graph 结构体分配内存,并将返回的指针存储在 graph 变量中。(Graph*) 类型转换,将 void* 转换(Graph*) 指针类型。 
    Graph* graph = (Graph*) malloc(sizeof(Graph)); 
    
	// 将图的顶点数(vertices)存储在 graph 结构的 V 成员中。 
    graph->V = vertices;  
    // 为AdjList 类型的数组分配内存,数组的大小与图的顶点数相同。
	// 每个 AdjList 元素(为一个链表头,每个链表包含从该顶点出发的所有边的目标顶点)对应于图中的一个顶点。 
    graph->array = (AdjList*) malloc(vertices * sizeof(AdjList));  
    // 遍历邻接表数组,将每个 AdjList 的 head 成员初始化为 NULL。
	// 创建图时,没有任何边存在(每个顶点的邻接链表都是空的)。
    for (int i = 0; i < vertices; ++i) 
    
        graph->array[i].head = NULL;  
  
    return graph;  
}
// addEdge 函数:向图中添加一条边,从顶点 src 到 dest。
// 首先创建一个新的邻接表节点,然后将该节点插入到 src 对应的邻接表中,
// 由于图是无向图,需要在 dest 对应的邻接表中插入一条边从 dest 指向 src。
void addEdge(Graph* graph, int src, int dest) {  
    // 将 dest 成员设置为给定的参数值,然后返回指向该节点的指针,创建一个新节点,
    // 该节点的 dest 成员被设置为当前边的目标顶点 dest。
    AdjListNode* newNode = newAdjListNode(dest);  
    // 将新节点的 next 指针设置为源顶点 src 当前邻接链表的头节点。
	// 将源顶点 src 的邻接链表头指针 head 更新为新节点,从而将该新节点添加到链表的开头。
	// 表示从源顶点 src 到目标顶点 dest 有一条边。
    newNode->next = graph->array[src].head;  
    graph->array[src].head = newNode;  
  
    // 将新节点添加到目标顶点 dest 的邻接链表中。
	// 表示从目标顶点 dest 到源顶点 src 也有一条边,无向图的特性。 
    newNode = newAdjListNode(src);  
    newNode->next = graph->array[dest].head;  
    graph->array[dest].head = newNode;  
}
//  DFS 函数:深度优先搜索。
// 从给定的起始顶点 v 开始,递归地遍历与它相邻的顶点,直到没有未访问的相邻顶点。
// 递归函数将递归访问每个相邻顶点,并用 visited 数组跟踪已访问的顶点。
void DFS(Graph* graph, int v, int visited[]) {  
    // 将整数数组 visited 中索引为 v 的元素设置为 1,表示顶点 v 已经被访问过。
    visited[v] = 1;  
    // 打印当前正在访问的顶点 v 的值
    printf("%d", v);  
    // 获取图中顶点 v 的邻接链表的头节点,并将其地址存储在指针 temp 中。 
    AdjListNode* temp = graph->array[v].head;  
    //  while 循环遍历顶点 v 的所有邻接顶点。
	// 循环继续执行,直到 temp 变为 NULL,遍历完所有邻接顶点。 
    while (temp) {  
        // 获取当前邻接链表节点 temp 的目标顶点 next。
        int next = temp->dest;  
        // 检查该顶点是否已经被访问过(即 visited[next] 是否为 0)。
        if (!visited[next])  
        // 如果 next 顶点尚未被访问,则递归调用 DFS 函数,以 next 为新的起始顶点继续搜索。 
            DFS(graph, next, visited);  
        // 将 temp 更新为当前节点的下一个节点,以下一次循环迭代中处理。
		// 确保能够遍历完顶点 v 的所有邻接顶点。
            temp = temp->next;  
    } 
	// 当 temp 变为 NULL 时,while 循环结束,表示顶点 v 的所有邻接顶点都已经被检查并已经被递归访问过。 
}  
// BFS 函数:广度优先搜索。
// 从给定的起始顶点 s 开始,利用队列依次访问和处理与起始顶点相邻的顶点,直到队列为空。
// while循环,函数将访问起始顶点的相邻顶点,并将们添加到队列中,同时使用 visited 数组跟踪已访问的顶点。 
void BFS(Graph* graph, int s) {  
     // 声明整数数组 visited,其大小为图的顶点数 graph->V。用于跟踪哪些顶点已经被访问过。
    int visited[graph->V];  
    // 循环遍历 visited 数组,将所有元素初始化为 0,表示开始时没有顶点被访问过。
    for (int i = 0; i < graph->V; i++)  
        visited[i] = 1;  
    // 声明整数数组 queue 作为队列,用于存储待访问的顶点。
	// 声明两个整数 front 和 rear 分别作为队列的前端和尾端索引,初始时都设为 0。
    int queue[graph->V], front = 0, rear = 0;  
    // 将起始顶点 s 标记为已访问(将 visited[s] 设置为 1)。
	// 将起始顶点 s 加入队列的尾部(通过增加 rear 索引并将 s 赋值给 queue[rear])。
    visited[s] = 1;  
    queue[rear++] = s;  
    // 循环持续进行,直到队列为空(即 front 等于 rear)。
	// 在队列不为空的情况下,执行循环体内的代码。
    while (front < rear) { 
	    // 从队列的前端取出一个顶点 s(通过增加 front 索引并读取 queue[front] 的值),并打印出来。表示顶点 s 已经被访问。 
        s = queue[front++];
		  
        printf("%d", s);  
        // 对于每个邻接顶点,如果未被访问(即 visited[temp->dest] 为 0),则将其标记为已访问,并将其加入队列的尾部。
		// 通过遍历 s 的邻接链表(由 graph->array[s].head 指向)实现,其中 temp 是指向邻接链表节点的指针。
        AdjListNode* temp = graph->array[s].head;  
        while (temp) {  
            if (!visited[temp->dest]) {  
                visited[temp->dest] = 1;  
                queue[rear++] = temp->dest;  
            }  
            temp = temp->next;  
        }  
    }  
}

// 释放链表中所有节点  
void freeAdjList(AdjList* adjList) {  
    // 指向AdjListNode类型的指针temp。用于临时存储链表中当前要释放的节点的地址。
    AdjListNode* temp;
	// 邻接表的头节点不为空(即链表中还有节点未被释放),循环继续执行。  
    while (adjList->head != NULL) {  
        // 将adjList->head(即当前链表的头节点)的地址赋值给temp。
		// temp指向当前要释放的节点。
        temp = adjList->head;  
        // adjList->head更新为adjList->head->next,让头节点指向下一个节点。 
        adjList->head = adjList->head->next;  
        // 释放temp所指向的内存 
        free(temp);  
    }  
}  
  
// 释放图占用的所有内存  
void freeGraph(Graph* graph) {  
    // 释放每个顶点的邻接表  
    for (int i = 0; i < graph->V; i++) {  
        freeAdjList(&graph->array[i]);  
    }  
  
    // 释放顶点数组  
    free(graph->array);  
  
    // 释放图结构本身  
    free(graph);  
}  
  
int main() {  
    int time = getTime();
    int V = 4; // 图的顶点数  
    Graph* graph = createGraph(V);  
  
    printf("Adding edges:\n");  
    addEdge(graph, 0, 1);  
    addEdge(graph, 0, 2);  
    addEdge(graph, 1, 2);  
    addEdge(graph, 2, 0); // 冗余,无向图已经通过addEdge添加了从0到2和从2到0的边。 
    addEdge(graph, 2, 3);  
    addEdge(graph, 3, 3); // 添加一个自环。 
	
  
    printf("\nGraph created. Following is Depth First Traversal (DFS):\n");  
    
    int* visited = (int*)malloc(V * sizeof(int));  
    if (visited == NULL) {  
        fprintf(stderr, "Memory allocation failed\n");  
        exit(EXIT_FAILURE);  
    }  

    for (int i = 0; i < V; i++)  
        if (visited[i] == 0)  
            DFS(graph, i, visited); // 从每个未访问的顶点开始DFS  
  
    // 重置visited数组进行BFS  
    for (int i = 0; i < V; i++)  
        visited[i] = 0;  
  
    printf("\nFollowing is Breadth First Traversal (BFS), starting from vertex 2:\n");  
    BFS(graph, 2); // 从顶点2开始BFS  
  
    // 清理分配的内存  
    freeGraph(graph);  
    
    return 0;  
}

运行结果如下:

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2089439.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

leedCode - - - 动态规划

目录 1.斐波那契数列&#xff08;LeetCode 509&#xff09; 2.零钱兑换&#xff08; LeetCode 322 &#xff09; 3.爬楼梯&#xff08; LeetCode 70 &#xff09; 4.不同路径&#xff08; LeetCode 62 &#xff09; 5.最长递增子序列&#xff08;LeetCode 300&#xff09; …

LLM(三):基于ChatGPT构建一个问答系统

以电商客服助手为例&#xff0c;通过链式调用语言模型&#xff0c;结合多个Prompt实现复杂的问答与推理功能。 一&#xff0c;基础知识了解 1.1 语言模型 大语言模型&#xff08;LLM&#xff09;是通过预测下一个词的监督学习方式进行训练的。具体来说&#xff0c;首先准备一…

SCP拷贝失败解决办法

1. 现象&#xff1a; 今天在提交代码的时候&#xff0c;提示hooks文件不存在&#xff0c;需要下载。 我之前用scp -p -P 1111 xxxxgerrit.xxxx:hooks/commit-msg$(gitdir)/hooks/ 就能下载&#xff0c; 但是更新系统后下载失败&#xff0c;显示 subsystem request failed …

哪个牌子的电容笔好用又实惠?西圣、绿联、摩米士电容笔实测大比拼

​现在市面上的电容笔很多&#xff0c;在选择时会让人感到很纠结。那么多的选择&#xff0c;究竟哪个牌子的电容笔好用又实惠呢&#xff1f;一款优质的电容笔应考虑握持舒适度、笔尖材质、电池续航能力以及书写流畅度等因素。作为一位多年的数码爱好者&#xff0c;我今天将针对…

Elasticsearch 再次开源

作者&#xff1a;来自 Elastic Shay Banon [D.N.A] Elasticsearch 和 Kibana 可以再次被称为开源了。很难表达这句话让我有多高兴。我真的激动得跳了起来。Elastic 的所有人都是这样的。开源已经融入我的 DNA&#xff0c;也融入了 Elastic 的 DNA。能够再次将 Elasticsearch 称…

Linux驱动(一):环境搭建及介绍

目录 前言一、硬件配置及SDK包1.硬件核心芯片2.瑞芯微原厂SDK包 二、环境镜像文件的获取1.镜像文件的组成及启动流程2.获取环境所需的镜像文件2.1 uboot.img2.2 boot.img2.3 rootfs.img2.4 整体编译 三、镜像文件烧录 前言 自用自用自用&#xff0c;晚上睡觉前复盘用。当然&…

免费批量Excel文件合并、拆分软件

软件介绍 下载地址&#xff1a;https://pan.quark.cn/s/ae860a4e2ccb 1.多个XLS或XLSX格式EXCEL文件合并&#xff0c;合并后可使用数据透视表进行相关操作。 2.自动合并多个EXCEL文件的第一个工作表&#xff0c;并汇总成一张表&#xff0c;可根据所有列标题需要指定需要的列。 …

pdf压缩到指定大小,分享2024年最新7款pdf压缩免费版

pdf是一种全球广泛使用的文件格式&#xff0c;它可以在不损失质量或文本对齐的情况下安全传输文档。然而&#xff0c;许多文件共享应用和网站对于可以上传或分享的pdf文件大小设定了限制。在这种情况下&#xff0c;您可能需要一款可以帮助您减小pdf文件大小的软件。pdf压缩免费…

《汇编语言》第11章——实验11编写子程序

编写一个子程序&#xff0c;包含任意字符&#xff0c;以0结尾的字符串中的小写字母变成大写字母&#xff0c;描述如下。 名称&#xff1a;letterc 功能&#xff1a;将以0结尾的字符串中的小写字母变成大写字母 参数&#xff1a;ds:si指向的字符串首地址 assume cs:codesg d…

本地部署 Google Gemma 开源模型

Google Gemma 是 Google AI 团队开发的基于Transformer的轻量级大语言模型&#xff0c;Gemma 模型已开源并在各种硬件平台上保持良好性能&#xff0c;记录下本地部署过程并在多种情景下使用情况。 一、环境配置 1、下载并安装Ollama 在 Windows 上下载 Ollama &#xff0c;选…

什么牌子的可视耳勺最好用?力荐四款热门品牌!

可视挖耳勺近几年越来越火爆&#xff0c;各种款式层出不穷&#xff0c;在可视挖耳勺的挑选上&#xff0c;我需要提醒大家一定要避雷劣质可视挖耳勺产品&#xff0c;劣质可视挖耳勺产品普遍不做核心性能的反复调教&#xff0c;成像清晰度低、耳勺出现发烫、性能不稳定等问题是时…

web渗透:CSRF漏洞(跨站请求伪造)

目录 CSRF漏洞 深入研究 CSRF攻击常见于哪些类型的网站&#xff1f; 如何通过HTTP Referer头来防范CSRF攻击&#xff1f; 为什么设置Cookie的SameSite属性对预防CSRF有帮助&#xff1f; 导图 CSRF漏洞 CSRF&#xff08;Cross-Site Request Forgery&#xff0c;跨站请求伪…

MySQL——事务与存储过程(一)事务管理(4)事务的隔离级别

数据库是多线程并发访问的&#xff0c;所以很容易出现多个线程同时开启事务的情况&#xff0c;这样就会出现脏读、重复读以及幻读的情况&#xff0c;为了避免这种情况的发生&#xff0c;就需要为事务设置隔离级别。在 MySQL 中&#xff0c;事务有4种隔离级别&#xff0c;接下来…

Linux安装Docker与基本指令

1、什么是Docker Dokcer是一种开源平台&#xff0c;主要用于创建、部署和管理容器化应用程序&#xff0c;它通过将应用程序以及所有的依赖打包到一个轻量级的、可移植的容器中&#xff0c;使得应用可以在任何环境中一致的运行! 1.1、Docker的优点 一致性和可移植性 跨环境一致…

删除微信重复文件的简易工具

去我的个人博客观看&#xff0c;观感更佳哦&#xff0c;&#x1f619;&#x1f619; 前言 !!!!温馨提示&#xff1a;假如你是小白&#xff0c;啥都不懂&#xff0c;请直接跳到文章的最后!!! 原本我是没想写这篇文章&#xff0c;契机是某一天我突然打开微信的存储空间占用才发…

5款手机版的影视解说文案生成器,无须下载更方便!

在这个自媒体的红利时期&#xff0c;影视解说创作占据了内容创作的很大一部分。而影视解说文案则是帮助观众更好地理解和欣赏影视作品的重要点。随着手机的普及&#xff0c;越来越多的人希望能够在手机上方便地生成影视解说文案创作。今天&#xff0c;我们就来介绍5款手机版的影…

Shared memory bank conflicts

共享内存和bank: 在CUDA架构中&#xff0c;共享内存是一个非常快速的内存类型&#xff0c;它位于每个线程块内部并为该线程块内的所有线程提供服务。为了实现高吞吐量的访问&#xff0c;共享内存被划分为多个独立的存储区域&#xff0c;称为“banks”。每个bank可以在单个时钟…

创新微MinewSemi推出基于Nordic nRF54系列芯片 SoC 低功耗蓝牙5.4模组

在物联网技术飞速发展的今天&#xff0c;创新微MinewSemi隆重推出基于Nordic最新nRF54系列芯片SoC的ME54BS01和ME54BS02全新低功耗蓝牙5.4模组。这两款模组的问世&#xff0c;标志着我们在推动物联网设备智能化、高效化道路上的迈出了坚实的一步&#xff0c;展示了对未来技术的…

回归预测|基于卷积神经网络-鲸鱼优化-最小二乘支持向量机的数据回归预测Matlab程序 CNN-WOA-LSSVM

回归预测|基于卷积神经网络-鲸鱼优化-最小二乘支持向量机的数据回归预测Matlab程序 CNN-WOA-LSSVM 文章目录 一、基本原理1. 数据预处理2. 特征提取&#xff08;CNN&#xff09;3. 参数优化&#xff08;WOA&#xff09;4. 模型训练&#xff08;LSSVM&#xff09;5. 模型评估和优…

World of Warcraft [CLASSIC][80][Grandel] Mount with 310% speed

310%速度的坐骑【被感染的始祖幼龙】 永恒之眼&#xff08;3个&#xff09; 纳克萨玛斯&#xff08;9个&#xff09; 10人副本&#xff0c; 白马 &#xff08;DPS N&#xff09;黑马&#xff08;DPS N&#xff09;绿马&#xff08;T N DPS&#xff09;红马&#xff08;T …