树莓派改装计划
​ 一直以来我都将一块树莓派作为我的服务器来使用,但是夏天到了,散热成了新的难题。既不想让风扇一直转(吵人),又想让 CPU 温度到达一定程度的时候启动,这确实有些棘手。查阅了相关达人的经验之后,我决定用继电器来解决这个问题。 思路 由于树莓派的控制脚针 GPIO 的电流并不足以带动风扇,所以使用继电器来间接控制风扇。pin2、pin4 直接连接到电源,不受 CPU 控制,这里的电流足够,而继电器的控制端接 pin12,以此来达到间接控制风扇的目的。 经历 电路 说干就干,在淘宝上不到四块钱买了一个继电器,非常便宜,这里注意要买 5V 电压的。 然后把电路接上,就像这样。此时的控制电路IN接的是Pin12也就是BCM控制方式的18端口。 程序 获取树莓派 CPU 温度非常简单,最终用 Python 编写。首先需要安装 GPIO 控制包。 sudo apt install rpi.gpio import RPi.GPIO as GPIO import time GPIO.setmode(GPIO.BCM) GPIO.setwarnings(False) def cpu_temp(): with open("/sys/class/thermal/thermal_zone0/temp", 'r') as f: return float(f.read())/1000 GPIO.setup(18,GPIO.IN) is_close = True while True: temp = cpu_temp() if is_close: if temp > 50.0: print(f"temp={temp}, open the fan") GPIO.setup(18,GPIO.OUT) is_close = False # 如果已经在开启着 else: if temp < 45.
2021-07-25    
二叉树查找
介绍 二叉树是树的一种特殊情况,规定一个根节点只能有两个孩子节点。如果再规定,左子数中的所有元素都要小于父亲节点的元素,右子树中所有的元素都要大于父亲节点的元素,这样的二叉树就是二叉查找树。找到一个元素的时间复杂度就是 O(logN)。 二叉树的定义是一个递归定义。 定义 我们定义它的数据结构。 /* 二叉查找树的ADT实现 */ #include<stdio.h> #include<stdlib.h> #define ElementType int typedef struct TreeNode *Position; typedef Position SearchTree; SearchTree MakeEmpty( SearchTree T ); Position Find( ElementType X, SearchTree T ); Position FindMin( SearchTree T ); Position FindMax( SearchTree T ); SearchTree Insert( ElementType X, SearchTree T ); SearchTree Delete( ElementType X, SearchTree T ); ElementType Ertrieve( Position P ); struct TreeNode { ElementType Element; SearchTree Left; SearchTree Right; }; 值得注意的是删除(Delete)函数的实现。
2021-07-12    
介绍 栈是一种特殊的表,规定它只能从栈顶插入数据(Push),也仅仅只能从栈顶取出数据(Pop),也就是先进后出(FILO)。它在程序设计中非常重要,例如函数的调用使用的就是栈结构。 栈也同样有两种实现,一种是数组实现,另一种是链表实现。 一般来说,大部分情况下使用数组实现。我们只将很少的数据放入栈中。 数组实现 数组实现的好处是时间复杂度底,仅仅操作一个数组,但是我们在最开始定义栈的时候,必须指定一个固定大小,这导致它失去的灵活性。为了防止栈溢出,我们总是定义一个稍微大一点的数组,但是它也造成的空间的浪费。 定义 /* 栈的数组实现 相比于链表实现,数组实现更为常用。 虽然它有缺点,就是数组的大小是固定的,也就意味着栈的大小是固定的, 所以每次创建栈的时候都要预留一些空间,这样会造成空间的浪费,但是相比于时间开销,这还是划算的。 */ #define ElementType int #include <stdio.h> #include<stdlib.h> typedef struct StackRecord *PtrToStack; typedef PtrToStack Stack; // 栈为空时,栈顶元素的数组下标,这里定义为-1 #define EmptyTOS (-1) // 规定最小的栈的大小 #define MinStack (5) int IsEmpty(Stack s); int IsFull(Stack); Stack CreateStack(int MaxElements); void MakeEmpty(Stack); void DisposeStack(Stack); ElementType Top(Stack); void Push(ElementType, Stack); int Pop(Stack); struct StackRecord { // 栈顶的数组下标,栈为空是,它为-1 int TopOfStack; // 栈的大小,也就是数组的大小 int Capacity; ElementType *Array; }; 函数实现
2021-07-12    
栈的应用括号匹配
介绍 栈可以做一些有意思的应用,例如括号的匹配。在编写 C 程序中,编译器可以检测括号是否匹配,以及哪里匹配错误。这可以轻松的使用栈来实现。 实现 当读取到左括号的时候入栈(Push),当读取到右括号的时候,将弹出栈顶元素进行比较,检测是否是匹配的符号。如果全部匹配并且栈为空,则括号匹配,否则不匹配。 代码 代码使用数组栈,定义最大栈容量为 20。 /* 字符匹配程序,利用数组栈实现。 匹配 ( [ { 这三种字符 */ // 引入栈的头文件 #include "squenceStack.h" #include<string.h> // 定义最大栈长度 #define MAX 20 int main(void) { // 创建一个栈 Stack stack; stack = CreateStack(MAX); char input[20]; printf("请输入一串字符,以回车结束:"); scanf("%s", input); printf("你输入了 %s,长度为len=%d\n", input, strlen(input)); int i = 0; for (i = 0; input[i] != '\0'; i++) { int iswrong = 0; //如果是左括号,则入栈 if (input[i] == '(' || input[i] == '[' || input[i] == '{') { Push(input[i], stack); } else { switch (input[i]) { case ')': // 如果匹配,并且出栈成功(未到栈底) if (Top(stack) == '(' && Pop(stack) == 1) ; // 否则出错 else iswrong = 1; break; case ']': if (Top(stack) == '[' && Pop(stack) == 1) ; else iswrong = 1; break; case '}' : if (Top(stack) == '{' && Pop(stack) == 1) ; else iswrong = 1; break; // 其他字符则跳过 default: break; } } /* 如果任何错误发生,则退出循环 */ if (iswrong == 1) { break; } } // 如果字符读取完毕,并且栈为空,则符号匹配 if (input[i] == '\0' && IsEmpty(stack)) { printf("符号匹配!\n"); } else { printf("匹配错误!\n"); } return 0; }
2021-07-12    
LibreOffice设置为中文字体
前言 在 Manjaro 或者 Archlinux 中安装完 LibreOffice 之后,发现无法将其设置为中文字体。参考 Wiki 发现,还需要安装中文字体包,libreoffice-fresh-zh-cn 方法 首先安装字体包 sudo pacman -Sy libreoffice-fresh-zh-cn 之后打开 LibreOffice,依次点击Tools->Options->Language Settings->Languages点击切换到简体中文 重启软件即可!
2021-07-09    
vscode在编译c\c++时报错“The PrelaunchTask ‘g++‘ terminated with exit code 1“
​## 原因 我这里是因为之前在 Linux 的项目完整的复制到了 Windows 下面,所以gcc和gdb的路径配置错误,只需要修改当前目录下.vscode中的配置文件中的路径地址即可。 操作 修改gcc和gdb的路径即可。
2021-06-16    
表的应用--多项式计算
数组实现 介绍 数组实现较为简单直接。数组下标代表的多项式的次方数,例如定义一个数组Array,那么Array[0]就代表次方为 0 的项的系数,以此类推。所以我们发现,由于数组是连续的,所以对于稀疏多项式来说,它所浪费的空间较大。 定义 #include<stdio.h> #include<stdlib.h> #define MaxDegree 20 #define Max(a, b) ((a)>(b)? (a): (b)) typedef struct Polynomial { int CoeffArray[ MaxDegree+1 ]; // 最高次方数,主要用于循环次数的确定 int HighPower; } *Polynomial; void ZeroPolynomial(Polynomial); void addPolynomial(Polynomial, Polynomial, Polynomial); void MultPolynomal(Polynomial, Polynomial, Polynomial); 我们定义了数组所能承担的最大次方数,那就是MaxDegree,因为还有一个次方数为 0 的项(也就是常数项),所以我们定义的数组CoeffArray需要MaxDegree+1个空间。 函数 我们定义了三个函数,分别是ZeroPolynomial用于将多项式置零,也就是所有项的系数置零,也就是将数组中的所有元素置零。 void ZeroPolynomial(Polynomial Poly) { /* 注意这里的循环次数,由于数组有MaxDegree+1个元素, 所以这里要循环MaxDegree+1次 */ for(int i = 0; i<= MaxDegree; i++) { Poly->CoeffArray[i] = 0; } Poly->HighPower = 0; } addPolynomial函数将两个多项式相加。也就是合并同类项,将相同次方的项的系数相加,也就是将相同数组下标的值相加。
2021-06-10    
表的实现和应用
概念 表是数据结构中最基本也是重要的结构。表是存储一列有顺序的数据的容器。这很类似于数组的概念,但是数组仅仅是一种数据结构,不包括对于数据的各类操作。 表分为顺序表和链表。顺序表是在内存中连续的一组空间构成,而链表可以由不相邻的空间构成。由于顺序表比较简单,所以我们重点实现链表。 链表 我们首先定义基本的结构体和操作原型。使用 ADT 模型。 #define ElementType int #include <stdlib.h> #include <stdio.h> struct Node; typedef struct Node *PtrToNode; typedef PtrToNode List; typedef PtrToNode Position; // 各类方法原型 List MakeEmpty( List L ); int IsEmpty( List L ); int IsLast( Position P, List L ); Position Find( ElementType X, List L ); void Delete( ElementType X, List L ); Position FindPrevious(ElementType X, List L); void Insert( ElementType X, List L, Position P); void DeleteList( List L ); Position Header( List L ); Position First( List L ); Position Advance( Position P ); ElementType Retrieve( Position P ); // 结构体 struct Node { ElementType Element; Position Next; }; 这里为了方便,我们定义 ElementType 类型为int类型,故而需要加上 #define ElementType int。
2021-06-04    
failed to resolve: maybe a missing crate front_of_house ?failed to resolve: use of undeclared crate
前言 在学习 Rust 时,官方文档 的 7.3 节的例子中(创建模块和引用),出现了以下错误: 解决方法 方法也很简单,如果是使用 cargo new –lib name 创建的模块的话,默认在 src/lib.rs 中的第一行会添加: #[cfg(test)] 只要注释掉这一行即可。即 //#[cfg(test)]
2021-04-22    
OSC9th操作系统概念第二章编程题
题目描述 2.3 节描述了一个程序,以将一个文件内容复制到另一个目标文件。这个程序首先提示用户输入源文件名和目标文件名。利用 windows 或 POSIX 的 API,编写这个程序。确保包括所有必要的错误检查以及源文件是否存在。 程序 #include <stdio.h> #include <stdlib.h> #include <fcntl.h> int main(void) { char sourceName[100]; char objName[100]; int fd1, fd2; printf("请输入源文件的名字:"); scanf("%s", sourceName); /*读文件*/ fd1 = open(sourceName, O_RDONLY); /*错误时返回-1*/ if (fd1 == -1){ /*print a system error message*/ perror(sourceName); return EXIT_FAILURE; } printf("请输入目标文件名:"); scanf("%s", objName); char buf[128]; /*写文件 O_WRONLY 写入 O_CREAT 如果不存在则创建改文件 */ fd2 = open(objName, O_WRONLY|O_CREAT); /*read系统调用,正常情况下返回读取的字符位数,错误时返回-1, 读取到文件结尾时返回0*/ while (read(fd1, buf, 1) != 0){ write(fd2, buf, 1); } close(fd1); close(fd2); return 0; } 系统调用 本题使用了多个系统调用
2021-03-15