编译过程中遇到的各种问题(持续更新)

我在用gcc编译时出现的错误如下,用ai解决这些问题之后,编译居然成功了
但是给我的米板4刷进去之后并不能开机……

二编:我换了个内核进行编译,还想集成kernelsu,可是一直都不成功,气得我鬼火冒

三编:换了魅蓝note6的内核,编译进行地异常顺利,刷进去之后也开机了,可是kernelsu并没有成功集成。。。

NR_CPUS配置错误

可能出现的报错:

1
include/trace/events/sched.h:875:2: error: #error "Unsupported NR_CPUS for lb tracepoint."

解决方法:

1
2
3
4
5
6
# 编辑内核配置
make menuconfig

# 进入"General setup" -> "Maximum number of CPUs"
# 将值设置为一个较小的数字(如8或16)
# 保存配置并退出

或者编辑内核配置文件

1
2
3
4
5
# 编辑.config文件
vi .config

# 找到并修改CONFIG_NR_CPUS
CONFIG_NR_CPUS=8

函数cpuid_feature_extract_field参数不匹配

可能出现的报错:

1
./arch/arm64/include/asm/kvm_mmu.h:309:17: error: too few arguments to function 'cpuid_feature_extract_field'

解决方法:

编辑文件./arch/arm64/include/asm/kvm_mmu.h,找到第309行附近的代码:

1
return (cpuid_feature_extract_field(reg, ID_AA64MMFR1_VMIDBITS_SHIFT) == 2) ? 16 : 8;

修改为:

1
return (cpuid_feature_extract_field(reg, ID_AA64MMFR1_VMIDBITS_SHIFT, 0) == 2) ? 16 : 8;\

注意:第三个参数的具体值需要根据cpuid_feature_extract_field函数的定义来确定,可能需要查看相关头文件

devfreq_simple_ondemand_data结构体类型不完整

可能出现的报错:

1
2
3
include/linux/mmc/host.h:331:54: error: field 'ondemand_gov_data' has incomplete type
331 | struct devfreq_simple_ondemand_data ondemand_gov_data;
| ^~~~~~~~~~~~~~~~~

解决方法:

1
2
3
4
5
6
# 编辑内核配置
make menuconfig

# 导航到以下路径并启用选项:
# Device Drivers -> Generic Driver Options -> Devfreq drivers -> Generic Dynamic Voltage and Frequency Scaling (DVFS) support
# 然后启用 "Simple Ondemand" governor

或者编辑内核配置文件

1
2
3
4
5
6
# 启用相关配置
echo "CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND=y" >> .config
echo "CONFIG_PM_DEVFREQ=y" >> .config

# 重新生成配置
make oldconfig

变量phdr重复声明

可能出现的报错:

1
2
3
4
5
6
7
drivers/soc/qcom/smem.c: In function 'qcom_smem_alloc_private':
drivers/soc/qcom/smem.c:305:39: error: redeclaration of 'phdr' with no linkage
305 | struct smem_partition_header *phdr;
| ^~~~
drivers/soc/qcom/smem.c:303:39: note: previous declaration of 'phdr' with type 'struct smem_partition_header *'
303 | struct smem_partition_header *phdr;
| ^~~~

解决方法:

1
2
3
4
5
6
# 编辑文件 drivers/soc/qcom/smem.c
vi drivers/soc/qcom/smem.c

# 找到函数 qcom_smem_alloc_private
# 删除第305行的重复声明:
# struct smem_partition_header *phdr;

或者用sed命令修复

1
2
# 删除第305行的重复声明
sed -i '305d' drivers/soc/qcom/smem.c

DTC链接错误

可能出现的报错:

1
2
3
4
/usr/bin/ld: scripts/dtc/dtc-parser.tab.o:(.bss+0x10): multiple definition of `yylloc'; scripts/dtc/dtc-lexer.lex.o:(.bss+0x0): first defined here
collect2: error: ld returned 1 exit status
make[3]: *** [scripts/Makefile.host:100:scripts/dtc/dtc] 错误 1
make[2]: *** [../scripts/Makefile.build:489:scripts/dtc] 错误 2

解决方式:
在内核源码根目录中找到Makefile文件
然后搜索找到HOSTCFLAGS项,添加HOSTCFLAGS += -fcommon
重新运行./build.sh

编译VDSO时出现的汇编语法错误

可能出现的报错:

1
2
3
../arch/arm64/kernel/vdso/gettimeofday.S:223:24: error: too many positional arguments
clock_gettime_return, shift=1
^

解决方式:
找到/arch/arm64/kernel/vdso/gettimeofday.S文件
然后修改此文件中第223、246和267行的宏调用方式:

1
2
3
4
5
# 原代码
clock_gettime_return, shift=1

# 应修改为
clock_gettime_return shift=1

然后重新运行./build.sh

ld无法辨认aarch64linux仿真模式

可能出现的报错:

1
2
/usr/bin/ld: 无法辨认的仿真模式: aarch64linux
支持的仿真: elf_x86_64 elf32_x86_64 elf_i386 elf_iamcu elf_l1om elf_k1om i386pep i386pe

解决方式:
移除/bin/ld以确保使用的是/bin/ld.lld

编译EFI stub时的绝对符号引用

可能出现的报错:

1
2
3
4
5
6
7
drivers/firmware/efi/libstub/lib-sort.stub.o: absolute symbol references not allowed in the EFI stub
make[5]: *** [../drivers/firmware/efi/libstub/Makefile:72:drivers/firmware/efi/libstub/lib-sort.stub.o] 错误 1
make[4]: *** [../scripts/Makefile.build:656:drivers/firmware/efi/libstub] 错误 2
make[3]: *** [../scripts/Makefile.build:656:drivers/firmware/efi] 错误 2
make[2]: *** [../scripts/Makefile.build:656:drivers/firmware] 错误 2
make[1]: *** [/home/abc/android_kernel_meizu_m1721/Makefile:1168:drivers] 错误 2
make[1]: *** 正在等待未完成的任务....

解决方式:
修改build.sh,添加禁用efi功能的代码:

1
2
3
4
5
6
7
8
9
10
11
make ${args} m1721_defconfig

# 在编译默认配置代码之后添加禁用 EFI 相关选项
echo "禁用 EFI 相关配置..."
./scripts/config --file out/.config --disable EFI
./scripts/config --file out/.config --disable EFI_STUB
./scripts/config --file out/.config --disable EFI_RUNTIME_WRAPPERS
./scripts/config --file out/.config --disable EFI_CAPSULE_LOADER
./scripts/config --file out/.config --disable EFI_TEST

make ${args}

Git分支版本管理

main分支和dev分支

  • main 分支用于存放稳定且可发布的代码,每次提交(或合并)到main分支时,都应该使用tag标记正式版本。

  • dev 分支作为开发集成分支,所有的新功能、改进和Bug修复都在这个分支上进行。这个分支上的代码可以不稳定,但应该保持可编译/可运行的状态。

日常工作流

日常开发
  • 所有的开发工作都在dev分支上进行:
1
2
3
4
git checkout dev
# 编写代码,多次提交
git add .
git commit -m "添加功能X"
  • 如果某个功能比较复杂,也可以从 dev 创建临时功能分支(例如 feature/login),开发完成后再合并回 dev
1
2
3
4
5
git checkout -b feature/login dev
# 开发...
git checkout dev
git merge --no-ff feature/login # 保留合并记录
git branch -d feature/login
定期同步远程仓库
  • 建议经常将分支推送到 GitHub/GitLab 等远程仓库,以防本地丢失:
1
git push origin main dev
发布版本
  • 当 dev 分支累积了足够的功能,并经过测试达到可发布状态时,将其合并到 main 并打上版本标签:
1
2
3
4
git checkout main
git merge --no-ff dev # 确保合并历史清晰
git tag -a v1.0.0 -m "版本1.0.0正式发布"
git push origin main --tags
  • 发布后,如果 main 有新的提交(比如通过热修复产生的提交),需要将这些变更同步回 dev
1
2
3
git checkout dev
git merge main # 将 main 的更新合并到 dev
git push origin dev

紧急热修复流程

如果线上版本(main)发现严重 Bug,需要立即修复,不能等待 dev 的常规发布周期。此时可以从 main 创建热修复分支:

1
2
3
4
git checkout main
git checkout -b hotfix/v1.0.1
# 修复 Bug,提交
git commit -m "修复紧急Bug"

修复完成后,将热修复分支合并回 main 和 dev

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 合并到 main 并打标签
git checkout main
git merge --no-ff hotfix/v1.0.1
git tag -a v1.0.1 -m "紧急修复版本"

# 合并到 dev,确保开发分支也包含修复
git checkout dev
git merge --no-ff hotfix/v1.0.1

# 删除临时分支
git branch -d hotfix/v1.0.1

# 推送到远程
git push origin main --tags
git push origin dev

多设备并行开发流程

在多设备并行开发时,一个设备完成开发并合并到远程仓库后,另一个设备上未完成的功能分支会出现“落后”的情况。你需要将远程的最新变更(比如 dev 分支的更新)同步到本地,并将当前功能分支基于最新代码进行调整。

先同步主开发分支(dev

在尚未完成开发的设备上,首先更新本地 dev 分支,使其与远程保持一致。

1
2
3
4
5
# 切换到 dev 分支
git checkout dev

# 拉取远程最新代码(推荐使用 rebase 保持历史线性)
git pull --rebase origin dev
将功能分支基于最新的 dev 进行变基(rebase)

切换到你的功能分支(假设叫 feature/xxx),并将它“移植”到最新的 dev 之上:

1
2
git checkout feature/xxx
git rebase dev

如果出现冲突,Git 会暂停并提示你解决。

  • 解决冲突后,执行 git add . 然后 git rebase --continue

  • 如果想放弃变基,可以用 git rebase --abort

现在你的功能分支已经基于最新的 dev 代码,可以继续开发、提交。完成后按正常流程合并回 dev 即可。

VS Code 配置 C/C++ 编程运行环境(保姆级教程)

在本教程中,将会安装 Visual Studio Code(后简称 VS Code),并在 VS Code 中安装 C/C++ 相关插件, 同时也将 VS Code 配置为使用 MinGW-W64 中的 GCC C/C++ 编译器(gcc/g++)和 GDB 调试器来创建在 Windows 上运行的程序。配置 VS Code 后,你将编写、编译、运行和调试大多数的 C/C++ 程序。

本教程所有参考内容均来自Documentation for Visual Studio Code

一、软件下载

  1. 下载 VS Code 安装工具

    官方下载链接:Visual Studio Code - Code Editing. Redefineda

    直接点“Download for Windows”就可以进行下载。

  2. 下载 MinGW-W64

    MinGW-W64 可以去MinGW-w64的官网下载,也就可以直接去 MinGW-W64 的 GitHub 上下载。由于在官网下载容易下错,所以我这里给一个 GitHub 的链接,也是在 VS Code 上提供的链接。(官方认证,绝对没错!)

    MinGW-W64下载链接:Releases · msys2/msys2-installer (github.com)

    进入链接后,可以看到历史版本的更替,截至本教程编写日期,最新版本为 2024-01-13 的版本,单击日期跳转至下载窗口。

    如下图所示,选择msys2-x86_64-20240113.exe(记住前缀是 msys2-x86_64 就行,后面是日期),点击后面的下载标志。

二、安装 VS Code

双击运行VSCodeUserSetup-x64-1.87.2.exe

如果出现如下弹窗,单击运行即可。

选择我同意此协议并单击下一步

这里提示 VS Code 的安装位置,我只有一个 C 盘(现在的固态硬盘可以选择不分区),所以选择默认默认路径,直接点击下一步。当然,你的电脑硬盘要是有分区的话,可以选择其他路径。

这一步是创建快捷方式的名字,可以输入其他名字,下面的选项如果不勾选,就会把快捷方式添加到开始菜单中。我选择默认,直接点下一步

默认只有最后两项被选中,我全部选上,单击下一步

最后再确认一下信息,确认之后直接安装即可。

大概一分钟左右就可以安装完成。

安装完成后,先暂时不运行 VS Code,把勾选去掉,点击完成

三、安装 MinGW-W64 及配置环境变量

双击msys2-x86_64-20240113.exe运行安装程序。

[!CAUTION]

请注意,MSYS2 需要 64 位 Windows 8.1 及以上版本。

此界面直接点击下一步

选择安装的路径,我这里选择默认,同学们可以根据自己的情况修改路径,之后点击下一步


版权声明:本文为CSDN博主「Grayson Zheng」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_42417071/article/details/137438374

关于学习

有点睡不着,心里很乱,写点东西

周五的时候去了开放实验,另一个同学已经上了两次课。但是上完课下来感觉老师没有给什么指导,只给了个代码和监测数据,然后通过ai什么的改一下算法什么的就可以了(比如将原来的随机森林算法改成梯度提升树算法),只是这两种算法我都没看懂。实际上老师给的那些代码我一直被看懂过,而最后要写一个实验报告,我也不知道怎么写(也许后面老师会发一个模板或者给一个论文让我们参考吧)。

升到大学以来我就有点难受。我一方面想挣脱高中时期的做题家思维,培养兴趣结交好友,另一方面我又想参加竞赛和科研,那样子毕业之后找工作会好一点。可是结果就是这两者我都没有,然后还在某个周末的晚上为看不见的未来担忧,而且第二天有早八。

这他喵就很难受。我真的想搞出事情来,很早很早的时候我就想成为一个所谓“小有名气的工程师”,有着1k星的github项目,然后在某个互联网公司就业。更早点,在我还在拿着小米2s刷机的时候,我还幻想过开发一款像lineage或者crdroid那样优秀的系统(其实应该叫ui更贴切点)。可是到大二了,以前在我身边的人竞赛的竞赛,进组的进组,只有我还在叫着“今晚老公不在家”。

我真的好想进步啊,真的好想。看到网上那些负能量的消息,我就想着我以后一定要挣好多好多钱,一定不能过这种生活。但是我又能怎么样呢,还在学的java,已经忘完的c语言,连自己的博客网站都是套别人的框架。我有时候真的感觉,就是这一把游戏已经没了,怎么玩都是输,还不如赶紧重开。

就连我现在写的东西也是,感觉越写到后面越偏题,然后就开始大段大段删,最后啥都没留。

我总感觉我得去看心理医生,后来想想也没必要,跟上个月比我这几天心情算挺好的了。

下周好像有大物和离散的期中考,也不知道能考成什么样。

写着写着困了,睡了,睡一觉就好了。

对了,明天降温,记得保暖。

关于做梦

最近我每天晚上都在做梦,有一部分还相当真实。

比如昨天晚上的梦,我梦到我的两只手肘部以下部分被砍掉了,后面被不知道谁带去医院接了假肢。说实话我当时一下就惊醒了,赶紧检查自己的小臂还在不在。

检查完睡下之后,我又做了一个不同的梦,梦里我看着我爸和一个陌生人互殴,然后那个陌生人拿着菜刀正一刀一刀往我爸的背上砍。可奇怪的是我对这种场景没有什么感觉,不会像往常做噩梦一样呼吸急促和心跳加快,可能是我意识到那个被砍的人是和我爸长得很像的人吧。

我的舍友都说我睡相差,会打呼噜还会说梦话,我也一直对这种事情感到非常抱歉。但还好他们对我睡觉这件事情不会很较真,虽然有时候起床会听到其中一个人对我说“你昨天晚上说了xxxx你知道吗“这样子的话。

据睡在我对面床铺的那个哥们说,去年刚玩ow的时候,我某天晚上睡着睡着就叫起”推车推车“的话。我不记得那天我干了什么(反正肯定有玩ow),但是就结果而言,我肯定是因为某一把没推车输的比赛说的梦话。挺奇异搞笑的。

好像还有一次,我梦游了,是在床上坐起来然后拉开床帘。这一次我倒是有点印象,不过具体原因就不知道了,也许也是因为做噩梦然后惊醒了吧。然后好像还把半夜上厕所的舍友吓到了。有点抽象。

好在无论是说梦话还是梦游,我整体的睡眠质量还是很好的。就是睡觉的时间还是不太够,可能以后我会早点睡觉吧(虽然不太可能)。

南邮数据结构作业 - 第四章

给出如下稀疏矩阵,请设计一种高效的转置算法,根据设计思想,采用C/C++语言实现,给出注释;并给出运行及结果截图。

  • 算法思想

假设三元组表按照行优先存储稀疏矩阵的非零元素,稀疏矩阵A进行转置后的结果存储到稀疏矩阵B中。
实现快速转置算法需要借助两个一维数组numsum,这两个数组的长度都为n(矩阵A的列数)

数组num存储矩阵每一列的非零元素个数,通过三元组表统计原矩阵每一列的非零元素个数,
数组的下标i就代表原矩阵的第i列,对应的元素num[i]就代表非零元素个数

数组sum的元素 sum[i] 统计稀疏矩阵A中列号从0i-1的非零元素总个数,
sum[i] 的值决定了原矩阵中第i列的第一个非零元素在三元组表中的位置

因此只需要对稀疏矩阵A的行三元组表进行一次扫描就可以快速转置

  • 代码实现

三元组和三元组表定义

稀疏矩阵可以转化为三元组表来压缩存储。三元组表记录稀疏矩阵中非零元素的三个特征:行坐标、列坐标和元素值。

1
2
3
4
5
6
7
8
9
10
11
typedef struct Term
{
int col, row; //行坐标row和列坐标col
elemtype value; //元素值
}term;

typedef struct SparseMatrix
{
int m, n, t; //原矩阵的行数m和列数n,t为非零元素个数
term table[maxsize]; //三元组表主体
}sparsematrix;

算法的代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
sparsematrix transpose(sparsematrix a)
{
int num[C] = { 0 }; //定义辅助数组num和sum,长度均为稀疏矩阵a的列数
int sum[C] = { 0 };

for (int i = 0; i < a.t; i++)
{
//数组num存储矩阵每一列的非零元素个数
//通过三元组表a统计原矩阵每一列的非零元素个数
//数组的下标i就代表原矩阵的第i列,对应的元素num[i]就代表非零元素个数
num[a.table[i].col]++;
}

for (int i = 1; i < C; i++)
{
//数组sum存储矩阵a中列号从0到i-1的所有非零元素的个数
//比如sum[3]就存储了列号从0到2的所有非零元素的个数
//sum[i]的值决定了原矩阵中第i列的第一个非零元素在三元组表中的位置
//比如sum[2]=4,说明第2列第一个非零元素在三元组表中的下标是4
sum[i] = sum[i - 1] + num[i - 1];
}

sparsematrix b;
b.m = C;
b.n = R;
b.t = 7;

for (int i = 0; i < a.t; i++)
{
int index = sum[a.table[i].col]++;
b.table[index].col = a.table[i].row;
b.table[index].row = a.table[i].col;
b.table[index].value = a.table[i].value;
}

return b;

}

main函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
#include <stdio.h>
#include <stdlib.h>
typedef int elemtype;
#define maxsize 100

#define C 6 //矩阵的行数R和列数C
#define R 6

int main()
{
sparsematrix s; //定义三元组表s

s.m = R; //设置行数和列数,非零元素个数为7
s.n = C;
s.t = 7;

int m[R][C] = { 0 }; //定义稀疏矩阵m并赋值
m[0][0] = -5;
m[0][1] = -2;
m[1][3] = -6;
m[3][1] = -3;
m[4][0] = -7;
m[4][3] = -4;
m[5][2] = -1;

int k = 0;
for (int i = 0; i < 6; i++) //将稀疏矩阵存储到三元组表中
{
for (int j = 0; j < 6; j++)
{
if (m[i][j] != 0)
{
s.table[k].row = i;
s.table[k].col = j;
s.table[k].value = m[i][j];
k++;
}
}
}

//输出转置前的三元组表
printf("转置前:\n");
for (int i = 0; i < s.t; i++)
{
printf("%d %d %d\n", s.table[i].row, s.table[i].col, s.table[i].value);
}

s = transpose(s);
printf("\n转置后:\n");
for (int i = 0; i < s.t; i++)
{
printf("%d %d %d\n", s.table[i].row, s.table[i].col, s.table[i].value);
}
}
  • 运行结果
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
转置前:
0 0 -5
0 1 -2
1 3 -6
3 1 -3
4 0 -7
4 3 -4
5 2 -1

转置后:
0 0 -5
0 4 -7
1 0 -2
1 3 -3
2 5 -1
3 1 -6
3 4 -4

E:\Buildings\c\数据结构与算法作业\第四章作业\x64\Debug\第四章作业.exe (进程 34352)已退出,代码为 0 (0x0)。
要在调试停止时自动关闭控制台,请启用“工具”->“选项”->“调试”->“调试停止时自动关闭控制台”。
按任意键关闭此窗口. . .

在多台电脑上提交和更新Hexo博客

前言

我现在有两台电脑,最初第一次装好hexo环境的电脑在宿舍,姑且叫这台电脑 “老电脑” 吧,代表最初拥有hexo环境的电脑,然后事情是这样的去到工位的电脑上想要更新博客总是要远程启动宿舍的电脑才行,于是想要在工位电脑也能更新,这里工位的电脑姑且叫做 “新电脑” 吧。

最初搞这个多设备同步属实折腾了好半天,看了很多博客也在知乎上参考了不少,但总是需要在不同博客之间相互参考最终才完美解决,所以想要把这几天的经历总结一下。

hexo同步原理

1. hexo博客目录结构说明

这是老电脑上的目录结构

文件夹 说明 是否需要上传Github
node_modules hexo需要的模块,就是一些基础的npm安装模块,比如一些美化插件,在执行npm install的时候会重新生成 N
themes 主题文件 Y
public hexo g命令执行后生成的静态页面文件 N
packages.json 记录了hexo需要的包的信息,之后换电脑了npm根据这个信息来安装hexo环境 Y
config.yml 全局配置文件 Y
.gitignore hexo生成的默认的.gitignore模块 Y
scaffolds 文章的模板 Y
.deploy_git hexo g自动生成的 N

2. 同步原理

主要思路是利用git分支来实现hexo的同步。

hexo生成的静态页面文件默认放在master分支上,这是由_config.yml配置文件所决定的

你可以在全局配置文件_config.yml中找到这么一段

1
2
3
4
5
6
# Deployment
## Docs: https://hexo.io/docs/one-command-deployment
deploy:
type: git
repo: git@github.com:username/username.github.io.git
branch: master

因此每当我们执行hexo d的时候,hexo都会帮我们把生成好的静态页面文件推到master分支上。

(我这里可能和你的不太一样,因为之前使用http推送经常由于网络问题推送上不去,所以我复制了username.github.io仓库的ssh链接,用ssh推送成功率更搞,所以我的链接形式是git@github.com:username/username.github.io.git这样的)

在我们第一次部署好博客的时候,github给我们创建的唯一一个分支就是master分支,同时也是默认分支。默认分支就意味着每次我们执行git clone 仓库地址或者git pull 仓库地址拉取的是默认分支的代码。

但是执行hexo d 对应的分支和默认分支是没有关系的,因为这是由配置文件决定的,配置文件写的哪个分支就是哪个分支。

因此,hexo生成的静态博客文件默认放在master分支上。hexo的源文件(部署环境文件)可以都放在source分支上(可以新创建一个source分支)。然后把source分支设置成默认分支。有小伙伴可能会担心默认分支的改变会不会影响到原来的网页的正常显示,其实如果是用GitHub Pages对博客进行托管的话也很简单,第一次搭建博客默认使用master分支作为页面。在下图所示的设置里可以找到。如果不小心搞错了只要把分支设置成静态页面对应的分支就好了。

把source分支设置成默认分支,用来存放源文件,master分支依然存放静态文件。在老电脑上,我们需要把必要的源文件push到source分支。换新电脑时,直接git clone 仓库地址此时会从source分支下载源文件,剩下的就是安装hexo环境,在新电脑上就可以重新生成静态页面了,并且因为配置文件clone下来,deploy配置依旧是master分支,所以在新电脑上执行hexo d还是会把更新过后的静态文件推送到master分支上。

由于master分支和source分支实际上是相互独立的两个普通的分支,所以我们源文件和静态页面的更新也是相互独立的,故而需要手动分别执行git add . git commit git push来更新源文件,然后执行hexo d更新静态页面。

老电脑上的具体操作

这里直接引用我看的一篇博客的步骤:

1. Github准备

先创建一个分支hexo

将其设置为默认分支

2. 打包将要推送到Github上的原始文件

(1)clone该仓库到本地(clone的是hexo默认分支)

1
git clone git@github.com:username/username.github.io.git

(2)下载的文件夹里仅留下.git 文件夹,其他的文件都删除

(3)找见我们hexo原位置,将hexo文件夹内除.deploy_git 以外都复制到clone下来的文件夹中

注意:1.现在clone下来的文件夹内应该有个.gitignore文件,用来忽略一些不需要的文件,表示这些类型文件不需要git。如果没有,右键新建,内容如下:

1
2
3
4
5
6
7
.DS_Store
Thumbs.db
db.json
*.log
node_modules/
public/
.deploy*/

2.如果已经clone过主题文件,那么需要把theme主题文件夹里的 .git 也删除。因为git不能嵌套上传,最好是显示隐藏文件,检查一下有没有,否则上传的时候会出错,导致你的主题文件无法上传,这样你的配置在别的电脑上就用不了了。

3.将clone并修改以后的文件夹推送到远程库

1
2
3
git add .
git commit –m add_branch
git push

此时已经成功将整个网站推送到了远程库的默认分支hexo

补充:后续写文章、修改配置后的保存推送操作

至此,网站部署至master分支,整个网站备份至hexo分支。当网站的配置或文章修改后都要将远程仓库更新。首先,依次执行

1
2
3
git add .
git commit -m ChangeFiles(更新信息内容可改)
git push (或者git push origin hexo)

保证hexo分支版本最新。然后执行

1
hexo d -g

(在此之前,有时可能需要执行hexo clean),完成后就会发现,最新改动已经更新到master分支了,两个分支互不干扰!

新电脑上的操作

  • 将新电脑的生成的ssh key添加到GitHub账户上

  • 在新电脑上克隆username.github.io仓库的source分支(就是存放源码的分支)到本地,此时本地git仓库处于source分支,可以执行git branch -v查看。

  • 在新电脑的username.github.io文件夹下执行npm install hexonpm installnpm install hexo-deployer-git(记得,不需要hexo init这条指令)

  • 最后执行hexo g、hexo s、hexo d等命令即可提交成功

上面步骤中,npm install其实就是读取了packages.json里面的信息,自动安装依赖,有的小伙伴可能只执行npm install就行了,不过按照上面的三步是最稳妥的。

这里提一嘴,当新电脑上的操作成功之后,其实对于新电脑还是老电脑其实都无所谓了,任何一台电脑包括老电脑只要安装了NodeJs环境,就都可以按照在新电脑上的操作完整地复刻出一个hexo环境,你甚至可以把老电脑原有的hexo工程删掉再执行上面这几步一样可以快速构建hexo环境,可以看到步骤非常简单。

此外,为了保证同步,推荐先git pull合并更新再进行博客的编写。

参考链接

利用Hexo在多台电脑上提交和更新github pages博客 - 简书 (jianshu.com)

hexo源码上传到GitHub-以防多台电脑操作/重装系统/要将hexo移动到其他磁盘 - 巧莓兔 - 博客园 (cnblogs.com)

Hexo博客备份 - 简书 (jianshu.com)

使用hexo,如果换了电脑怎么更新博客? - 知乎 (zhihu.com)


版权声明:本文为CSDN博主「Kakaluotuo」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:Hexo在多台电脑上提交和更新_hexo两个设备-CSDN博客

南邮数据结构作业 - 第三章

用递归和非递归算法分别求解汉诺塔问题

这里首先声明,作者只理解了递归算法,非递归算法是用ai生成的

  • 汉诺塔问题的递归算法

先分成两种情况:
1.如果这个塔只含有一个盘子,则直接将盘子移动到目标盘
2.如果这个塔含有n个盘子,那么将问题从“将最大的盘子n通过辅助柱移动到目标柱”
转化为“将次大的盘子n-1通过辅助柱移动到目标柱”
然后对于情况二,算法步骤为:

将n-1个盘子从起始柱移动到辅助柱

将最大的盘子从起始柱移动到目标柱

将n-1个盘子从辅助柱移动到目标柱

  • 递归算法的代码实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
void hanoi1(int n, char from, char to, char dest) {
// 情况1:如果只有一个盘子,直接移动
if (n == 1) {
printf("盘子 1 从 %c 移动到 %c\n", from, to);
return;
}

// 情况2的递归步骤:
// 1. 将n-1个盘子从起始柱移动到辅助柱
hanoi1(n - 1, from, dest, to);

// 2. 将最大的盘子从起始柱移动到目标柱
printf("盘子 %d 从 %c 移动到 %c\n", n, from, to);

// 3. 将n-1个盘子从辅助柱移动到目标柱
hanoi1(n - 1, dest, to, from);

}
  • 汉诺塔问题的非递归算法

汉诺塔问题的非递归算法需要借助堆栈来实现
用三个堆栈代表三个柱子,然后根据盘子数量的奇偶性来决定盘子第一步的移动方向
偶数个盘子:起始柱->辅助柱, 起始柱->目标柱, 辅助柱->目标柱
奇数个盘子:起始柱->目标柱, 起始柱->辅助柱, 目标柱->辅助柱

  • 非递归算法的代码实现

定义堆栈

1
2
3
4
5
6
typedef int elemtype;
typedef struct stack{
elemtype* element;
int top;
int maxsize;
} Stack;

堆栈初始化

1
2
3
4
5
6
7
Stack* createStack(int maxsize) {
Stack* stack = (Stack*)malloc(sizeof(Stack));
stack->element = (int*)malloc(sizeof(int) * maxsize);
stack->top = -1;
stack->maxsize = maxsize;
return stack;
}

移动盘子的辅助函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
void moveDisk(Stack* stacks[], int fromIdx, int toIdx, char fromChar, char toChar, char auxChar) {
char poleNames[3] = { fromChar, auxChar, toChar };

// 检查从fromIdx移动到toIdx是否合法
if (stacks[fromIdx]->top >= 0 &&
(stacks[toIdx]->top < 0 ||
stacks[fromIdx]->element[stacks[fromIdx]->top] < stacks[toIdx]->element[stacks[toIdx]->top])) {

int disk = stacks[fromIdx]->element[stacks[fromIdx]->top--];
stacks[toIdx]->element[++stacks[toIdx]->top] = disk;
printf("将盘子 %d 从 %c 移动到 %c\n", disk, poleNames[fromIdx], poleNames[toIdx]);
}
// 检查从toIdx移动到fromIdx是否合法
else if (stacks[toIdx]->top >= 0 &&
(stacks[fromIdx]->top < 0 ||
stacks[toIdx]->element[stacks[toIdx]->top] < stacks[fromIdx]->element[stacks[fromIdx]->top])) {

int disk = stacks[toIdx]->element[stacks[toIdx]->top--];
stacks[fromIdx]->element[++stacks[fromIdx]->top] = disk;
printf("将盘子 %d 从 %c 移动到 %c\n", disk, poleNames[toIdx], poleNames[fromIdx]);
}

}

非递归算法实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
void hanoi2(int n, char from, char to, char aux) {
if (n <= 0) return;

// 使用三个堆栈来表示三个柱子
Stack* stacks[3];
stacks[0] = createStack(n); // 起始柱A
stacks[1] = createStack(n); // 辅助柱B
stacks[2] = createStack(n); // 目标柱C

// 初始化起始柱,最大的盘子在底部
for (int i = n; i >= 1; i--) {
stacks[0]->element[++stacks[0]->top] = i;
}

// 总移动次数
int totalMoves = (1 << n) - 1; // 2^n - 1

// 根据盘子数量的奇偶性决定第一步的移动方向
char src = 0, dest, temp;

if (n % 2 == 0) {
// 偶数个盘子:A->B, A->C, B->C
dest = 1;
temp = 2;
}
else {
// 奇数个盘子:A->C, A->B, C->B
dest = 2;
temp = 1;
}

for (int move = 1; move <= totalMoves; move++) {
if (move % 3 == 1) {
// 在src和dest之间移动
moveDisk(stacks, src, dest, from, to, aux);
}
else if (move % 3 == 2) {
// 在src和temp之间移动
moveDisk(stacks, src, temp, from, to, aux);
}
else {
// 在dest和temp之间移动
moveDisk(stacks, dest, temp, from, to, aux);
}
}

}

main函数

1
2
3
4
5
6
7
8
9
10
11
12
13
int main() {
int n;

printf("请输入汉诺塔的盘子数量:");
scanf_s("%d", &n);

printf("汉诺塔的移动步骤:\n");
hanoi1(n, 'A', 'C', 'B'); // 递归算法:A是起始柱,C是目标柱,B是辅助柱
//hanoi2(n, 'A', 'C', 'B'); // 非递归算法:A是起始柱,C是目标柱,B是辅助柱

return 0;

}
  • 运行结果(递归算法和非递归算法的结果相同)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
请输入汉诺塔的盘子数量:4
汉诺塔的移动步骤:
盘子 1 从 A 移动到 B
盘子 2 从 A 移动到 C
盘子 1 从 B 移动到 C
盘子 3 从 A 移动到 B
盘子 1 从 C 移动到 A
盘子 2 从 C 移动到 B
盘子 1 从 A 移动到 B
盘子 4 从 A 移动到 C
盘子 1 从 B 移动到 C
盘子 2 从 B 移动到 A
盘子 1 从 C 移动到 A
盘子 3 从 B 移动到 C
盘子 1 从 A 移动到 B
盘子 2 从 A 移动到 C
盘子 1 从 B 移动到 C

E:\Buildings\c\数据结构与算法作业\第三章作业\x64\Debug\第三章作业.exe (进程 36636)已退出,代码为 0 (0x0)。
要在调试停止时自动关闭控制台,请启用“工具”->“选项”->“调试”->“调试停止时自动关闭控制台”。
按任意键关闭此窗口. . .

test

meow~

test

meow~