【不看会后悔系列】排序之——文件归并【史上最全详解】~
文章目录
- 前言
- 一、何为文件归并?
- 二、文件归并思路分析
- 三、创造多数据文件
- 四、前置准备——堆排序
- 五、两个文件写入到第三个文件
- 六、读 N 个数据返回给文件,并返回读到数据的个数
- 七、文件归并
- 八、文件归并完整代码总结
- 1. 运行代码
- 2. 运行截图
- 总结
前言
学习了归并排序了之后,我们来了解一下文件是怎么归并的。、
要看归并排序请戳我~
一、何为文件归并?
文件归并外排序(External Sorting with Merge)是一种专门处理大规模数据的排序算法,适用于数据量大到无法一次全部加载到内存的情况。主要用于处理硬盘等外部存储设备上的数据
,而不是内存中的数据。
外排序的核心思想:
-
排序阶段(分割数据):由于数据量过大,无法一次性全部放入内存,所以将数据分块处理。每次读取内存能够容纳的一部分数据,对这部分数据进行排序,然后将排序后的数据存储到临时文件中。重复这个过程,直到所有数据都被处理并生成多个有序的临时文件。
-
归并阶段(合并文件):将之前生成的多个有序临时文件按一定方式归并成一个大的有序文件。归并排序的特点是不需要随机访问数据,只需按顺序读入数据进行归并,因此特别适合外排序。
步骤总结:
- Step 1: 分割数据并对每个分块排序(生成多个有序的临时文件)。
- Step 2: 将这些有序的临时文件逐步归并,直到所有数据整合成一个完整的有序文件。
外排序与内排序的区别:
- 外排序:处理无法完全加载到内存中的数据,使用“排序-归并”策略,依赖外部存储设备。
- 内排序:处理能完全加载到内存中的数据,常用排序算法如快速排序、堆排序等都属于内排序。
归并排序作为一种适用于顺序读取数据的算法,可以同时用于内存中的排序和外存储的排序,因此在外排序中也广泛应用。
二、文件归并思路分析
假设这是我们未排序的文件
-
分块排序:
- 读取内存能容纳的
n
个数据,进行排序。 - 将排序后的数据写入到
file1
。 - 再次读取
n
个数据,排序后写入到file2
。
- 读取内存能容纳的
-
初步归并:
- 通过归并排序的思想,同时从
file1
和file2
中按顺序读取数据。 - 比较
file1
和file2
的当前值,将较小的值依次写入到mfile
中。 - 继续此过程,直到
file1
和file2
的数据全部归并到mfile
中,生成一个新的有序文件。
- 通过归并排序的思想,同时从
-
文件重命名和清理:
- 删除
file1
和file2
,释放存储空间。 - 将
mfile
重命名为file1
,以便后续继续归并。
- 删除
-
继续处理新的数据:
- 继续读取
n
个新的数据进行排序,并将其写入到file2
。 - 再次执行归并操作,将
file1
和file2
归并成一个新的有序文件,存入mfile
。
- 继续读取
-
重复归并,直到结束:
- 重复步骤 2 和步骤 4,直到所有数据处理完毕。
- 最终归并后的有序文件存放在
file1
中,完成整个排序过程。
文件归并的特点:
- 每次只需在内存中处理一小部分数据,避免内存溢出问题。
- 使用归并排序保证了数据在外存储中按顺序处理,高效完成排序。
三、创造多数据文件
思路如下:
-
定义随机数个数
n
:int n = 1000000;
- 定义
n
为1000000
,表示需要在文件中生成 100 万个随机数。
- 定义
-
初始化随机数种子:
srand(time(0));
- 使用
srand(time(0))
来初始化随机数种子,确保每次运行时生成的随机数序列不同。
- 使用
-
定义文件名:
const char* file = "data.txt"; const char* file1 = "file1"; const char* file2 = "file2";
- 定义了三个文件路径,
data.txt
用于存储生成的随机数,file1
和file2
用于后续归并排序中的临时文件。
- 定义了三个文件路径,
-
打开文件
data.txt
(用于写入数据):FILE* fin = fopen(file, "w"); if (fin == NULL) {perror("fopen error");return; }
- 使用
fopen
以写入模式 (w
) 打开data.txt
,若打开失败,则输出错误信息并退出函数。
- 使用
-
生成并写入随机数:
for (int i = 0; i < n; i++) {int x = rand() + i;fprintf(fin, "%d\n", x); }
- 使用
for
循环生成n
个随机数,并通过fprintf
将它们逐行写入到data.txt
文件中。 rand()
用于生成随机数,并在每个随机数上加上当前循环索引i
,以增加随机数的分布多样性。
- 使用
-
关闭文件
data.txt
:fclose(fin);
- 随机数写入完成后,关闭
data.txt
文件。
- 随机数写入完成后,关闭
-
清空
file1
和file2
:FILE* f1 = fopen(file1, "w"); FILE* f2 = fopen(file2, "w"); if (f1 == NULL || f2 == NULL) {perror("fopen file1 or file2 fail!");return; }
- 分别以写模式打开
file1
和file2
文件。如果文件不存在,则会创建;如果文件存在,则清空内容。
- 分别以写模式打开
-
关闭
file1
和file2
:fclose(f1); fclose(f2);
- 清空完成后,关闭
file1
和file2
,准备后续排序时使用。
- 清空完成后,关闭
总结:
- 这个函数的核心任务是生成一个包含随机数的文件
data.txt
,并准备两个空的文件file1
和file2
,为接下来的外部归并排序操作做准备。 - 通过这种方式,数据先被分批处理、排序并写入
file1
和file2
,最后通过归并的方式组合成有序文件。
像这样就创建成功了
代码如下:
// 创建有 N 个数据的文件,并同时创建 file1 和 file2
void CreatNData()
{// 随机数造数据int n = 1000000;srand(time(0));const char* file = "data.txt";const char* file1 = "file1";const char* file2 = "file2";// 打开文件(写数据)FILE* fin = fopen(file, "w");// 判断文件是否打开成功if (fin == NULL){perror("fopen error");return;}// 循环开始写数据for (int i = 0; i < n; i++){int x = rand() + i;fprintf(fin, "%d\n", x);}// 关闭大文件fclose(fin);// 清空 file1 和 file2,以便后续使用FILE* f1 = fopen(file1, "w");FILE* f2 = fopen(file2, "w");if (f1 == NULL || f2 == NULL){perror("fopen file1 or file2 fail!");return;}// 关闭 file1 和 file2fclose(f1);fclose(f2);
}
四、前置准备——堆排序
后面拿n个数据读取到file1和file2中的时候需要排序,我们这里使用堆排序
J桑前面讲过好多次堆排序,这里就直接给代码啦~
需要看堆排序戳我~~~
//先把堆排拿过来备用
void Swap(int* p1, int* p2)
{int tmp = *p1;*p1 = *p2;*p2 = tmp;
}
void AdjustDown(int* a, int n, int parent)
{int child = parent * 2 + 1;while (child < n){// 选出左右孩⼦中⼤的那⼀个if (child + 1 < n && a[child + 1] > a[child]){++child;}if (a[child] > a[parent]){Swap(&a[child], &a[parent]);parent = child;child = parent * 2 + 1;}else{break;}}
}
void HeapSort(int* a, int n)
{// 建堆 -- 向下调整建堆 -- O(N)for (int i = (n - 1 - 1) / 2; i >= 0; --i){AdjustDown(a, n, i);}// O(N*logN)int end = n - 1;while (end > 0){Swap(&a[end], &a[0]);AdjustDown(a, end, 0);--end;}
}
五、两个文件写入到第三个文件
这段代码通过归并排序的思想,将 file1
和 file2
中的数据按序合并到 mfile
中。具体流程如下:
- 打开文件:以读取模式打开
file1
和file2
,以写入模式打开mfile
。 - 归并数据:通过循环从
file1
和file2
读取数据,比较大小后将较小的值写入mfile
。 - 处理剩余数据:当一个文件的数据读完后,将另一个文件剩下的数据依次写入
mfile
。 - 关闭文件:处理完成后,关闭所有文件。
这里简单解释一下 fscanf 的用法
fscanf发生错误时会返回EOF
,因此我们可以用EOF
来判断
代码如下:
// file1⽂件的数据和file2⽂件的数据归并到mfile⽂件中
void MergeFile(const char* file1, const char* file2, const char* mfile)
{//创立三个文件,以读的方式打开file1和file2,以写的方式打开mfileFILE* fout1 = fopen(file1, "r");if (fout1 == NULL){perror("fopen file1 fail!");exit(-1);}FILE* fout2 = fopen(file2, "r");if (fout2 == NULL){perror("fopen file2 fail!");exit(-1);}FILE* fin = fopen(mfile, "w");if (fin == NULL){perror("fopen mfile fail!");exit(-1);}// 这⾥跟内存中数组归并的思想完全类似,只是数据在硬盘⽂件中⽽已// 依次读取file1和file2的数据,谁的数据⼩,谁就往mfile⽂件中去写// file1和file2其中⼀个⽂件结束后,再把另⼀个⽂件未结束⽂件数据,// 依次写到mfile的后⾯int num1, num2;int ret1 = fscanf(fout1, "%d\n", &num1);int ret2 = fscanf(fout2, "%d\n", &num2);while (ret1 != EOF && ret2 != EOF){if (num1 < num2){fprintf(fin, "%d\n", num1);ret1 = fscanf(fout1, "%d\n", &num1);}else{fprintf(fin, "%d\n", num2);ret2 = fscanf(fout2, "%d\n", &num2);}}while (ret1 != EOF){fprintf(fin, "%d\n", num1);ret1 = fscanf(fout1, "%d\n", &num1);}while (ret2 != EOF){fprintf(fin, "%d\n", num2);ret2 = fscanf(fout2, "%d\n", &num2);}///打开文件后记得关闭fclose(fout1);fclose(fout2);fclose(fin);
}
六、读 N 个数据返回给文件,并返回读到数据的个数
这段代码的功能是从文件中读取 n
个数据,排序后再写入另一个文件,并返回实际读取到的数据个数。具体流程如下:
-
读取数据:
- 使用
fscanf
从文件fout
中读取整数,最多读取n
个数据,存储在数组a
中。 - 通过
i
记录实际读取到的数据个数,循环读取直到达到n
或文件结束。
- 使用
-
检查数据数量:
- 如果没有读取到任何数据,直接返回
0
,表示读取失败或文件为空。
- 如果没有读取到任何数据,直接返回
-
堆排序:
- 如果读取到了数据,调用
HeapSort
对数组a
中的i
个数据进行排序。
- 如果读取到了数据,调用
-
写入排序后的数据:
- 打开目标文件
file
,并将排序后的数据逐行写入。 - 文件写入完成后关闭文件。
- 打开目标文件
-
返回值:
- 返回实际读取并排序的数据个数
i
,用于后续处理。
- 返回实际读取并排序的数据个数
关键点:
- 数据读取使用
fscanf
,按行读取整数。我们构建父本的时候也是按行%d\n形式的
- 使用堆排序
HeapSort
对数据进行排序。 - 数据排序后写回到指定的
file
文件中。
代码如下:
// 返回读取到的数据个数,并排序,读 N 个数据返回给文件,并返回读到数据的个数
int ReadNNumSortToFile(FILE* fout, int* a, int n, const char* file)
{//数据读到 x 中int x = 0;// i 表示读到数据的个数int i = 0;while (i < n && fscanf(fout, "%d\n", &x) != EOF){a[i++] = x;}//如果一个数据都没读到,不用排序了,返回0if (i == 0){return i;}//读到的数据堆排序HeapSort(a, i);//把排序过的数组放回文件中去FILE* fin = fopen(file, "w");if (fin == NULL){perror("fopen file fail!");exit(-1);}for (int j = 0; j < i; j++){fprintf(fin, "%d\n", a[j]);}//记得关闭文件fclose(fin);return i;
}
七、文件归并
该函数的目的是通过外部归并排序,将大文件 file
按照块处理,逐块排序并归并,最终生成一个有序文件。
开始之前,我们先来了解两个函数:
remove:
rename:
用这两个函数就可以有效删除和重命名我们的文件,合理运用返回值增强代码健壮性,还可以当作判断条件
-
文件打开:
FILE* fout = fopen(file, "r");
- 以只读模式打开要排序的文件
file
,如果打开失败,程序退出。
- 以只读模式打开要排序的文件
-
定义临时文件:
const char* file1 = "file1"; const char* file2 = "file2"; const char* mfile = "mfile";
file1
和file2
用于存储分块后的数据,mfile
是临时文件,存储归并后的数据。
-
内存分配:
int* a = (int*)malloc(sizeof(int) * n);
- 为数组
a
分配大小为n
的内存空间,用于存储从文件中读取的数据。n
是每次读取数据的大小,取决于内存可用空间。
- 为数组
-
数据分块并排序:
int readCount1 = ReadNNumSortToFile(fout, a, n, file1); int readCount2 = ReadNNumSortToFile(fout, a, n, file2);
- 调用
ReadNNumSortToFile
函数,从file
中读取n
个数据,排序后分别写入file1
和file2
。 - 读取的结果存储在
readCount1
和readCount2
,如果两个文件都没有数据,直接退出函数。
- 调用
-
循环归并:
while (1)
- 进入循环,将
file1
和file2
中的数据归并到mfile
中。
- 进入循环,将
-
文件处理:
-
归并:
MergeFile(file1, file2, mfile);
- 调用
MergeFile
函数,将file1
和file2
的内容按顺序归并到mfile
。
- 调用
-
删除与重命名:
remove(file1); remove(file2); rename(mfile, file1);
- 删除
file1
和file2
,然后将mfile
重命名为file1
,为下一次归并做准备。
- 删除
-
-
继续读取数据并归并:
if (ReadNNumSortToFile(fout, a, n, file2) == 0) {break; }
- 再次读取
n
个数据排序并存储到file2
,如果无法再读取数据,说明归并结束,退出循环。
- 再次读取
-
结束处理:
fclose(fout); free(a);
- 关闭文件并释放内存。
核心思想:
- 通过逐块读取数据到内存进行排序,随后将多个排序好的块文件进行归并,最终得到一个有序的文件。每次归并后的文件会循环处理,直至所有数据排序完成。
也就是我们一开始画的这张图,是我们整个文件归并的大框架
代码实现:
// MergeSortFile的第⼆个是每次取多少个数据到内存中排序,然后写到⼀个⼩⽂件进⾏归并
// 这个n给多少取决于我们有多少合理的内存可以利⽤,相对⽽⾔n越⼤,更多数据到内存中排序后,
// 再⾛⽂件归并排序,整体程序会越快⼀些。
void MergeSortFile(const char* file, int n)
{// 以写的方式打开文件 fileFILE* fout = fopen(file, "r");if (fout == NULL){perror("fopen file fail!");exit(-1);}// 定义三个文件 file1, file2, mfileconst char* file1 = "file1";const char* file2 = "file2";const char* mfile = "mfile";// 分割成⼀段⼀段数据,内存排序后写到,⼩⽂件int* a = (int*)malloc(sizeof(int) * n);if (a == NULL){perror("malloc fail!");exit(-1);}int readCount1 = ReadNNumSortToFile(fout, a, n, file1);int readCount2 = ReadNNumSortToFile(fout, a, n, file2);if (readCount1 == 0 && readCount2 == 0) {fclose(fout);free(a);return; // 如果两个文件都没有数据,直接返回}//循环归并获取元素while (1){// file1和file2⽂件归并到mfile⽂件中MergeFile(file1, file2, mfile);//删除file1和file2if (remove(file1) != 0 || remove(file2) != 0){perror("Error deleting file");exit(-1);}//重命名mfile为file1if (rename(mfile, file1) != 0){perror("Error renaming file");exit(-1);}// 读取N个数据到file2,继续⾛归并// 如果⼀个数据都没读到,则归并结束了if (ReadNNumSortToFile(fout, a, n, file2) == 0){break;}}printf("%s 文件成功排序到%s\n", file, file1);// 别忘了关闭文件,释放a空间fclose(fout);free(a);
}
八、文件归并完整代码总结
1. 运行代码
到这里我们所有的框架都搭建完了,现在要做的就是将他们结合起来
完整代码实现:
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>// 创建有 N 个数据的文件,并同时创建 file1 和 file2
void CreatNData()
{// 随机数造数据int n = 1000000;srand(time(0));const char* file = "data.txt";const char* file1 = "file1";const char* file2 = "file2";// 打开文件(写数据)FILE* fin = fopen(file, "w");// 判断文件是否打开成功if (fin == NULL){perror("fopen error");return;}// 循环开始写数据for (int i = 0; i < n; i++){int x = rand() + i;fprintf(fin, "%d\n", x);}// 关闭大文件fclose(fin);// 清空 file1 和 file2,以便后续使用FILE* f1 = fopen(file1, "w");FILE* f2 = fopen(file2, "w");if (f1 == NULL || f2 == NULL){perror("fopen file1 or file2 fail!");return;}// 关闭 file1 和 file2fclose(f1);fclose(f2);
}//先把堆排拿过来备用
void Swap(int* p1, int* p2)
{int tmp = *p1;*p1 = *p2;*p2 = tmp;
}
void AdjustDown(int* a, int n, int parent)
{int child = parent * 2 + 1;while (child < n){// 选出左右孩⼦中⼤的那⼀个if (child + 1 < n && a[child + 1] > a[child]){++child;}if (a[child] > a[parent]){Swap(&a[child], &a[parent]);parent = child;child = parent * 2 + 1;}else{break;}}
}
void HeapSort(int* a, int n)
{// 建堆 -- 向下调整建堆 -- O(N)for (int i = (n - 1 - 1) / 2; i >= 0; --i){AdjustDown(a, n, i);}// O(N*logN)int end = n - 1;while (end > 0){Swap(&a[end], &a[0]);AdjustDown(a, end, 0);--end;}
}// file1⽂件的数据和file2⽂件的数据归并到mfile⽂件中
void MergeFile(const char* file1, const char* file2, const char* mfile)
{//创立三个文件,以读的方式打开file1和file2,以写的方式打开mfileFILE* fout1 = fopen(file1, "r");if (fout1 == NULL){perror("fopen file1 fail!");exit(-1);}FILE* fout2 = fopen(file2, "r");if (fout2 == NULL){perror("fopen file2 fail!");exit(-1);}FILE* fin = fopen(mfile, "w");if (fin == NULL){perror("fopen mfile fail!");exit(-1);}// 这⾥跟内存中数组归并的思想完全类似,只是数据在硬盘⽂件中⽽已// 依次读取file1和file2的数据,谁的数据⼩,谁就往mfile⽂件中去写// file1和file2其中⼀个⽂件结束后,再把另⼀个⽂件未结束⽂件数据,// 依次写到mfile的后⾯int num1, num2;int ret1 = fscanf(fout1, "%d\n", &num1);int ret2 = fscanf(fout2, "%d\n", &num2);while (ret1 != EOF && ret2 != EOF){if (num1 < num2){fprintf(fin, "%d\n", num1);ret1 = fscanf(fout1, "%d\n", &num1);}else{fprintf(fin, "%d\n", num2);ret2 = fscanf(fout2, "%d\n", &num2);}}while (ret1 != EOF){fprintf(fin, "%d\n", num1);ret1 = fscanf(fout1, "%d\n", &num1);}while (ret2 != EOF){fprintf(fin, "%d\n", num2);ret2 = fscanf(fout2, "%d\n", &num2);}///打开文件后记得关闭fclose(fout1);fclose(fout2);fclose(fin);
}// 返回读取到的数据个数,并排序,读 N 个数据返回给文件,并返回读到数据的个数
int ReadNNumSortToFile(FILE* fout, int* a, int n, const char* file)
{//数据读到 x 中int x = 0;// i 表示读到数据的个数int i = 0;while (i < n && fscanf(fout, "%d\n", &x) != EOF){a[i++] = x;}//如果一个数据都没读到,不用排序了,返回0if (i == 0){return i;}//读到的数据堆排序HeapSort(a, i);//把排序过的数组放回文件中去FILE* fin = fopen(file, "w");if (fin == NULL){perror("fopen file fail!");exit(-1);}for (int j = 0; j < i; j++){fprintf(fin, "%d\n", a[j]);}//记得关闭文件fclose(fin);return i;
}// MergeSortFile的第⼆个是每次取多少个数据到内存中排序,然后写到⼀个⼩⽂件进⾏归并
// 这个n给多少取决于我们有多少合理的内存可以利⽤,相对⽽⾔n越⼤,更多数据到内存中排序后,
// 再⾛⽂件归并排序,整体程序会越快⼀些。
void MergeSortFile(const char* file, int n)
{// 以写的方式打开文件 fileFILE* fout = fopen(file, "r");if (fout == NULL){perror("fopen file fail!");exit(-1);}// 定义三个文件 file1, file2, mfileconst char* file1 = "file1";const char* file2 = "file2";const char* mfile = "mfile";// 分割成⼀段⼀段数据,内存排序后写到,⼩⽂件int* a = (int*)malloc(sizeof(int) * n);if (a == NULL){perror("malloc fail!");exit(-1);}int readCount1 = ReadNNumSortToFile(fout, a, n, file1);int readCount2 = ReadNNumSortToFile(fout, a, n, file2);if (readCount1 == 0 && readCount2 == 0) {fclose(fout);free(a);return; // 如果两个文件都没有数据,直接返回}//循环归并获取元素while (1){// file1和file2⽂件归并到mfile⽂件中MergeFile(file1, file2, mfile);//删除file1和file2if (remove(file1) != 0 || remove(file2) != 0){perror("Error deleting file");exit(-1);}//重命名mfile为file1if (rename(mfile, file1) != 0){perror("Error renaming file");exit(-1);}// 读取N个数据到file2,继续⾛归并// 如果⼀个数据都没读到,则归并结束了if (ReadNNumSortToFile(fout, a, n, file2) == 0){break;}}printf("%s 文件成功排序到%s\n", file, file1);// 别忘了关闭文件,释放a空间fclose(fout);free(a);
}int main()
{//CreatNData();// 一次排100000个数据MergeSortFile("data.txt", 100000);return 0;
}
2. 运行截图
我们来运行一下吧~
先创建数据
来到我们文件中,可以看到我们初始数据,还有file1,fiel2都创建好了。
再来运行排序
打开我们的文件,可以看到在file1中数据排好了升序,代表文件归并成功~
数据太多了,J桑就不都给大家看啦~
总结
到这里,我们文件归并的内容就结束啦~
最重要的是要先搭建出文件归并的框架,像这样大事化小的思路,然后先把框架化为代码,再去补充其他需要用到的函数~
那么,就谢谢大家啦~
相关文章:
【不看会后悔系列】排序之——文件归并【史上最全详解】~
文章目录 前言一、何为文件归并?二、文件归并思路分析三、创造多数据文件四、前置准备——堆排序五、两个文件写入到第三个文件六、读 N 个数据返回给文件,并返回读到数据的个数七、文件归并八、文件归并完整代码总结1. 运行代码2. 运行截图 总结 前言 学习了归并排…...
安全点的应用场景及其原理详解
引言 在Java虚拟机(JVM)运行的过程中,有些时刻,系统需要暂停所有正在运行的线程,以执行某些全局操作或确保数据的一致性。这些暂停线程的时刻被称为**“安全点”**(Safepoint)。尽管安全点最广…...
计算机各专业2025毕业设计选题推荐【各专业 | 最新】
计算机各专业2025毕业设计选题推荐 Java、Python、Vue、PHP、小程序、安卓、大数据、爬虫、可视化、机器学习、深度学习 文末有联系方式~~~ 1.Java 基于Java的在线购物系统设计与实现Java开发的图书管理系统基于Spring Boot的社交媒体平台Java实现的移动健康应用在线学习平…...
【Python报错已解决】IndexError: index 0 is out of bounds for axis 1 with size 0
🎬 鸽芷咕:个人主页 🔥 个人专栏: 《C干货基地》《粉丝福利》 ⛺️生活的理想,就是为了理想的生活! 专栏介绍 在软件开发和日常使用中,BUG是不可避免的。本专栏致力于为广大开发者和技术爱好者提供一个关于BUG解决的经…...
SpringGateway(网关)微服务
一.启动nacos 1.查看linux的nacos是否启动 docker ps2.查看是否安装了nacos 前面是你的版本,后面的names是你自己的,我们下面要启动的就是这里的名字。 docker ps -a3.启动nacos并查看是否启动成功 二.创建网关项目 1.创建idea的maven项目 2.向pom.x…...
jQuery面试题:(第三天)
8.你在jQuery中使用过哪些插入节点的方法,它们的区别是什么? 答:append(),appendTo(),prepend(),prependTo(),after(),insertAfter() before(),insertBefore() 内添加 1.append()在文档内添加元素 2.appendTo()把匹配的元素添加到对象里 3.prepend()…...
聊聊国内首台重大技术装备(2)
上次,介绍了《首台(套)重大技术装备推广应用指导目录(2024年版)》中介绍的硅外延炉,湿法清洗机,氧化炉,见文章: 《聊聊国内首台重大技术装备(1)》…...
python 实现rayleigh quotient瑞利商算法
rayleigh quotient瑞利商算法介绍 瑞利商(Rayleigh Quotient)算法在多个领域,如线性代数、计算机视觉和机器学习等,都有重要的应用。瑞利商定义为函数 R ( A , x ) ( x H A x ) / ( x H x ) R(A, x) (x^H Ax) / (x^H x) R(A,x)…...
Java Web应用升级故障案例解析
在一次Java Web应用程序的优化升级过程中,从Tomcat 7.0.109版本升级至8.5.93版本后,尽管在预发布环境中验证无误,但在灰度环境中却发现了一个令人困惑的问题:新日志记录神秘“失踪”。本文深入探讨了这一问题的排查与解决过程&…...
Java类和对象、自定义包、static、代码块、方法重写
目录 1.类和对象 2.this指针 3.对象的构造和初始化 3.1默认初始化 3.2就地初始化 3.3构造初始化 3.4IDEA快速填充 3.5使用this简化 3.6初始化的总结 4.包的引入 4.1包的概念 4.2导入包中的类 4.3自定义包 5.static修饰 6.代码块的划分 7.方法重写 1.类和对象 使…...
【系统代码】招投标采购一体化管理系统,JAVA+vue
前言: 随着互联网和数字技术的不断发展,企业采购管理逐渐走向数字化和智能化。数字化采购平台作为企业采购管理的新模式,能够提高采购效率、降低采购成本、优化供应商合作效率,已成为企业实现效益提升的关键手段。系统获取在文末…...
基于yolov8深度学习的120种犬类检测与识别系统python源码+onnx模型+评估指标曲线+精美GUI界面目标检测狗类检测犬类识别系统
【算法介绍】 基于YOLOv8深度学习的120种犬类检测与识别系统是一款功能强大的工具,该系统利用YOLOv8深度学习框架,通过21583张图片的训练,实现了对120种犬类的精准检测与识别。 该系统基于Python与PyQt5开发,具有简洁的UI界面&a…...
UNI-APP_iOS开发技巧之:跳转到TestFlight或者App Store
有的时候我们的应用可能需要上TestFlight或者App Store,更新升级就需要跳到TestFlight里面。方法如下: 跳转到TestFlight: itms-beta://itunes.apple.com/app/你的AppID 跳转到AppStore: itms-apps://itunes.apple.com/app/你的AppIDhttps://airp…...
基于SSM+Vue技术的定制式音乐资讯平台
文未可获取一份本项目的java源码和数据库参考。 一、选题的背景与意义: 随着个人计算机的普及和互联网技术的日渐成熟,网络正逐渐成为人们获取信息及消费的主要渠道。然而在当前这个信息时代,网络中的信息种类和数量呈现爆炸性增长的趋势&a…...
Spring依赖注入和注解驱动详解和案例示范
在 Spring 框架中,依赖注入(Dependency Injection, DI)和注解驱动(Annotation-Driven)是其核心机制,它们为 Spring 应用提供了灵活性和可扩展性。依赖注入简化了对象间的依赖管理,而注解驱动则通…...
网络通信——OSPF协议(基础篇)
这里基础是因为没有讲解OSPF中的具体算法过程,以及其中很多小细节。后续会更新。 目录 一.OSPF的基础信息 二.认识OSPF中的Router ID 三.OSPF中的三张表 四.OSPF中的度量方法(计算开销值) 五. OSPF选举DR和BDR(就是这个区域…...
Kubernetes从零到精通(15-安全)
目录 一、Kubernetes API访问控制 1.传输安全(Transport Security) 2.认证(Authentication) 2.1 认证方式 2.2 ServiceAccount和普通用户的区别 2.3 ServiceAccount管理方式 自动ServiceAccount示例 手动ServiceAccount示例 3.鉴权 (Authorization) 3.1鉴权方式 3.2 …...
《蓝桥杯算法入门》(C/C++、Java、Python三个版本)24年10月出版
推荐:《算法竞赛》,算法竞赛大全书,网购:京东 天猫 当当 文章目录 《蓝桥杯算法入门》内容简介本书读者对象作者简介联系与交流《蓝桥杯算法入门 C/C》版目录 《蓝桥杯算法入门 Java》版目录 《蓝桥杯算法入门 Python》版目录 …...
Soar项目中添加一条新的SQL审核规则示例
soar是一个开源的SQL规则审核工具,是一个go语言项目,可以直接编译构建成一个可执行程序,而且是一个命令行工具,我们可以利用archey来调用soar进行sql规则审核以及sql的分析,包括执行计划的查看及sql建议等。 soar中已…...
RISC-V开发 linux下GCC编译自定义指令流程笔记
第一步:利用GCC提供了内嵌汇编的功能可以在C代码中直接内嵌汇编语言 第二步:利用RSIC-V的中的.insn模板进行自定义指令的插入 第三步:RISC-V开发环境的搭建 C语言插入汇编 GCC提供了内嵌汇编的功能可以在C代码中直接内嵌汇编语言语句方便了…...
java代码是如何与数据库通信的?
Java代码与数据库通信的过程主要通过Java Database Connectivity(JDBC)来实现。JDBC是Java与数据库之间的标准接口,提供了用于执行SQL语句和处理数据库结果的API。以下是Java代码与数据库通信的详细步骤: 一、导入JDBC库 在Java…...
gateway--网关
在微服务架构中,Gateway(网关)是一个至关重要的组件,它扮演着多种关键角色,包括路由、负载均衡、安全控制、监控和日志记录等。 Gateway网关的作用 统一访问入口: Gateway作为微服务的统一入口,…...
北京数字孪生工业互联网可视化技术,赋能新型工业化智能制造工厂
随着北京数字孪生工业互联网可视化技术的深入应用,新型工业化智能制造工厂正逐步迈向智能化、高效化的全新阶段。这项技术不仅实现了物理工厂与数字世界的精准映射,更通过大数据分析、人工智能算法等先进手段,为生产流程优化、资源配置合理化…...
土地规划与区域经济发展:筑基均衡未来的战略经纬
在新时代背景下,土地规划不仅是空间布局的艺术,更是推动区域经济均衡发展的关键引擎。土地资源的合理配置对于激发区域潜能、促进经济结构优化有着重要意义。本文将深入剖析土地规划如何成为促进区域经济均衡发展的强大动力。 一、土地规划与区域经济的…...
wsl(2) -- ubuntu24.04配置
1. 常用脚本及别名配置 修改的文件内容参考另一篇文章常用bash脚本。 修改~/.bashrc,在文件末尾追加以下内容。 # Add by user export MYTOOLS$HOME/tools export MYBINS$HOME/bin # 系统中其他地方已经添加过了,暂不清楚是哪里添加的 #export PATH$M…...
python快速搭建https服务器
本文介绍了在ubuntu操作系统上搭建https服务器的过程 在一台连接到网络的主机上搭建https服务器,假设该主机的ip地址为:10.98.69.174 创建证书example.crt和私钥example.key openssl req -newkey rsa:2048 -nodes -keyout example.key -x509 -days 365…...
网络原理3-应用层(HTTP/HTTPS)
目录 DNSHTTP/HTTPSHTTP协议报文HTTP的方法请求报头、响应报头(header)状态码构造HTTP请求HTTPS 应用层是我们日常开发中最常用的一层,因为其他层:传输层、网络层、数据链路层、物理层这些都是操作系统和硬件、驱动已经实现好的,我们只能使用…...
JVM(HotSpot):堆空间(Heap)以及常用相关工具介绍
文章目录 一、内存结构图二、堆的定义三、堆内存溢出四、堆内存排查工具 一、内存结构图 二、堆的定义 1、通过new关键字创建的对象,都会放到堆空间中。 2、它是线程共享的,堆中的对象都要考虑线程安全问题。 那有同学肯定会问,方法内通过n…...
【Python语言初识(六)】
一、网络编程入门 1.1、TCP/IP模型 实现网络通信的基础是网络通信协议,这些协议通常是由互联网工程任务组 (IETF)制定的。所谓“协议”就是通信计算机双方必须共同遵从的一组约定,例如怎样建立连接、怎样互相识别等,…...
使用root账号ssh登录虚拟机ubuntu
在C:\Users\Administrator\.ssh目录下的config中,添加ubuntu会在根目录中,建立一个root文件夹。在该文件夹中建一个.ssh目录。像免密登录ubuntu设置中,把公钥考进去。在vscode中打开文件夹中选择要打开的文件夹,就可以不需要在ubu…...
深圳网站建设培训班/seo推广系统
论理靠约架,打架靠群殴,无论说得如何冠冕堂皇,如何煽情,说白了,都是没有开化的野蛮人! 这些人谈民主,是当下最大的冷笑话。 那一大块还是一大坨的东西,别以为黄色就能冒充金子&#…...
武汉网站制作迈佳/免费好用的crm软件
最近购物节一波接一波,往常家里的孩子总嚷嚷着要买玩具,但这段时间却吵着要买球?到底是咋了?原来,最近有一档节目风靡全网,尤其是孩子们都成了“忠实粉丝”,收视率期期第一,它就是金…...
做网站的软件dw/免费建网站
PPP-C#conf tPPP-C(config)#vpdn enable //启用路由器的虚拟专用拨号网络---***d 由于ADSL的PPPoE应用是通过虚拟拨号来实现的所以在路由器中需要使用VPDN的功能PPP-C(config)#int e1/0 // 路由器内网接口PPP-C(config-if)#no shutPPP-C(config-if)#i…...
深圳58同城网站建设/网站搜什么关键词
转载自:Java开发人员最常犯的10个错误 一、把数组转成ArrayList 为了将数组转换为ArrayList,开发者经常会这样做:List<String> list Arrays.asList(arr);使用Arrays.asList()方法可以得到一个ArrayList,但是得到这个Array…...
网站开发 工具/企业培训内容
在短短的一分钟,X浪已经发送了2万条微博,苹X已经下载了4.7万次应用,某宝已经卖出了6万件商品,XX网发生了30万次访问,X度产生了90万次搜索查询——可以看到,在宽带化、移动互联网、物联网、社交网络、云计算…...
wordpress换服务器/深圳关键词排名seo
看完了“李智慧”老师的《大型网站技术架构-核心原理与案例分析》一书,让我对大型网站的技术架构所遇到的问题,所考虑到的内容,所用到的解决方案有了一个初步的认识。任何的大型网站都是从一个小网站发展而来的,淘宝、京东都不例外…...