├── Algorithm ├── Dijkstra算法(迪杰斯特拉).md ├── KMP算法介绍.md ├── Kruskal算法介绍.md └── 自动机-字符串算法.md ├── Articles ├── C中文件操作复习.md ├── Engineering a Compiler读书笔记(1)---编译概述.md ├── Github下载加速.md ├── Matlab操作(1):基础的矩阵操作及运算.md ├── Octave基础知识——矩阵操作及运算.md ├── c语言中extern的使用.md ├── haskell一些内置函数的实现和扩展(1).md ├── python实现弹幕雨(简化版).md ├── 《C Prime Plus》读书笔记(14):各种特殊数据形式总结struct,union,enum.md ├── 不用公式学线代, 纯纯纯几何视角下的线性代数.md ├── 写给github新人,如何下载并运行一个Github项目.md ├── 字符串到底是什么?.md ├── 数据结构(严蔚敏)读书笔记 (1)---绪论.md ├── 数据结构(严蔚敏)读书笔记 (2)---线性表.md ├── 数据结构(严蔚敏)读书笔记 (3)---栈和队列.md ├── 数据结构(严蔚敏)读书笔记(4)---串(KMP).md ├── 文本文件和二进制文件的区别.md ├── 浮点数详解(IEEE 754标准).md ├── 美赛部分python代码-情感分析源码(中文).md ├── 解决git push报错 hint Updates were rejected because the tip of your current branch is behind和各种其它小报错.md └── 详解C中的系统调用open,close,read,write.md ├── Daily ├── .keep └── 【23-01-01】菊厂入职前的一些小复习 ├── README.md └── images ├── 20200912154046124.png ├── 20200912154125121.png ├── 20200914103548705.png ├── 2020091411260018.png ├── 20200914112632730.png ├── 20200914112736163.png └── 20200917105757461.png /Algorithm/Dijkstra算法(迪杰斯特拉).md: -------------------------------------------------------------------------------- 1 | 2 | # 算法描述 3 | 4 | |描述: 5 | 6 | Dijkstra(迪杰斯特拉)算法是典型的单源最短路径算法,用于计算一个节点到其他所有节点的最短路径。主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止。由for循环可知,其时间复杂度是O(n^2)。 7 | 8 | 9 | 10 | |原理: 11 | 12 | 在已知图的邻接矩阵 net.vexs[i ] [j](无向网,含权值的图)的条件下,通过遍历已知图的所有路径,用 dis[i] 数组来记录到i点的最短路径,然后在循环中不断判断更替。首先,将所有点的集合分为俩部分,一边是已经遍历过的,另外一边是没有遍历过的,分别用mark[i]=1、mark[i]=0来表示。**层层扩散,实时比较和更新最短路径** 13 | 14 | 15 | 16 | |代码通解: 17 | 18 | ​ 在下面代码中,先将赋予初始值dis[i]=INF(无穷大)、mark[i]=0(未标记),而后单独将源点(x)所联通的路径权值 net.arcs[x] [i]赋予dis[i]( 28 | 29 | #define INF 100//INF为比图中任何权值都大的数 30 | #define maxSize 7 //图的顶点数 31 | #define number 12 //图的边数 32 | using namespace std; 33 | typedef struct {//图的定义 34 | int edges[maxSize][maxSize];//邻接矩阵的定义 35 | int n, e; //分别为顶点数和边数 36 | }MGraph; 37 | 38 | 39 | /*迪杰斯特拉算法代码,函数结束时dist[]存放了v点到其余各顶点的最短路径长度,path[]中保存从V到各顶点的最短路径*/ 40 | #define MAXSIZE 20 41 | #define PLACENUM 12 42 | #define INF 9999 // 此处定义999为无穷大 43 | 44 | struct 45 | { 46 | int vexnum,arcnum; //节点数和边数 47 | int vexs[MAXSIZE]; // 节点名 48 | int arcs[MAXSIZE][MAXSIZE]; //俩个节点之间的值 49 | } net; 50 | /*补充的结构体net,2019.7.3*/ 51 | 52 | void Dijkstra(int x,int y) // x为源点,y为终点 53 | { 54 | int i,j,k; 55 | int min; 56 | int u; //下一个放入集合p的点 57 | int dis[net.vexnum]; // 最短路径 58 | int mark[net.vexnum]; // 被mark的便是已经遍历,未被mark的便是未遍历 59 | /*首先进行最短路径初始化*/ 60 | for(i=0; idis[i]) //判断未遍历点 且 被赋值的最短路径(dis[i]dis[u]+net.arcs[u][i]) // !mark[i]判断不去走回头路, 91 | /*dis[i]>dis[u]+net.arcs[u][i]有俩个用途:①若u链接的是x源点没有赋值最短路径的点,那么这里可以赋值②若是赋值过的点,那么可以判断是上一个dis[i](此时是被赋值过的)是不是真正的最短路径,即修正。*/ 92 | 93 | { 94 | dis[i] = dis[u] + net.arcs[u][i]; //若A->C比A->B->C更长那么A->B->C则是到C的最短路径,下图将解释。 95 | 96 | } 97 | } 98 | } 99 | printf("最短路径值为: %d",dis[y]); 100 | } 101 | ``` 102 | 103 | -------------------------------------------------------------------------------- /Algorithm/KMP算法介绍.md: -------------------------------------------------------------------------------- 1 | 2 | - [一.【什么是】KMP](#一什么是kmp) 3 | - [二.【为什么】可以移位?](#二为什么可以移位) 4 | - [1.从公式推导来说](#1从公式推导来说) 5 | - [2.从直观来说](#2从直观来说) 6 | - [三.【怎么实现】](#三怎么实现) 7 | - [3.对移位规则的实现:Next[]](#3对移位规则的实现next) 8 | - [4.【一句话总结】实现KMP的算法流程:判异同 和 移位找前缀](#4一句话总结实现kmp的算法流程判异同-和-移位找前缀) 9 | - [1.KMP实现: Si,Tj位判异同,相等时S,T同进位,相异时T移位进行前缀匹配,看能否最终匹配全部字符串](#font-colorred1kmp实现-sitj位判异同相等时st同进位相异时t移位进行前缀匹配看能否最终匹配全部字符串) 10 | - [2.构建Next[]:找Next[j+1],就是Tj,Tk判异同,看能否扩充T[1, j]任一子前缀 (移位找子前缀)](#font-colorred2构建next找nextj1就是tjtk判异同看能否扩充t1-j任一子前缀-移位找子前缀) 11 | - [5.具体代码实现和解释](#5具体代码实现和解释) 12 | - [附:修正后的Next代码](#附修正后的next代码) 13 | 14 | 15 | # 一.【什么是】KMP 16 | **KMP是利用公共前后缀进行移位匹配的匹配算法。在失配时固定主串指针i (i无需回溯),依据Next[]将模式串向后移动与匹配指针对齐** 17 | 18 | 对比朴素暴力匹配法O(nm),KPM匹配更高效O(n+m) 19 | 20 | 21 | 22 | 23 | 实现过程: 24 | ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200928145916596.gif#pic_center) 25 |

26 | 27 | ------- 28 | # 二.【为什么】可以移位? 29 | 30 | 31 | ## 1.从公式推导来说 32 | 33 | 34 | ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200928134405124.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2ExMzM1MjkxMjYzMg==,size_16,color_FFFFFF,t_70#pic_center) 35 |

36 | 37 | ## 2.从直观来说 38 | 39 | >为了方便叙述,声明了几个名词 40 | >把模板T在指针j之前字符构成的子串,姑且先称之为“已配对模式子串”,把已配对模式子串的开头前k-1项,和j前k-1项,称为模板j前子串的“前缀”和“后缀” 41 | 42 | 已知主串Si的前x项已经和“已配对模式子串”完全相等, 在第i项时Tj与Si相异, 现在考虑移位问题。 43 | 44 | 既然i前面部分已完全相等,Si的前x项中每个位置都已经和“已配对模板子串”的对应位置一一对应了(此时“已配对模板子串”的“前后缀”,也是Si前的前x项的前后缀 ),如果一个一个移位的话大多情况下都是在“已配对模式子串”开头部分就已经无法对应,但是有一种特殊情况除外 --- 当“前缀”等于“后缀” 时,将“已配对模式子串”的“前缀” 直接 移到主串S的“后缀”对应位置,以此达到了快速移位,减少无意义匹配的目的 45 | 46 | ==综上所述:移位的k只与模式T自身相关(与模式T的公共前后缀相关)== 47 | 48 |

49 | 50 | ------- 51 | 52 | # 三.【怎么实现】 53 | 54 | ## 3.对移位规则的实现:Next[] 55 | 56 | **模式T的移位是为了前后缀匹配** 57 | 58 | ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200928142331942.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2ExMzM1MjkxMjYzMg==,size_16,color_FFFFFF,t_70#pic_center) 59 | 60 |

61 | 62 | ------- 63 | 64 | ## 4.【一句话总结】实现KMP的算法流程:判异同 和 移位找前缀 65 | 66 | 就干两件事情:**判异同** 和 **移位找前缀** 67 | 68 | 因为构建Next数组本质上也是使用KPM匹配(主串和模式都为原模式T),所以为了更普适Next的实现,调整了一下KPM和Next数组的实现流程图 69 | 70 | ### 1.KMP实现: Si,Tj位判异同,相等时S,T同进位,相异时T移位进行前缀匹配,看能否最终匹配全部字符串 71 | ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200928145224852.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2ExMzM1MjkxMjYzMg==,size_16,color_FFFFFF,t_70#pic_center) 72 | 73 | ### 2.构建Next[]:找Next[j+1],就是Tj,Tk判异同,看能否扩充T[1, j]任一子前缀 (移位找子前缀) 74 | 75 | 找Next[j+1],就是Tj,Tk判异同,相等时返回原前缀长+1(等效于扩充了前缀),相异时移位往前找T[1, j]所有子前缀,最终获得每个j上的Next[j]值 76 | tip:扩充前缀(即前缀后一位Tk与Tj相等) 77 | 78 | ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200928145231785.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2ExMzM1MjkxMjYzMg==,size_16,color_FFFFFF,t_70#pic_center) 79 | 80 | 81 |

82 | 83 | ------- 84 | 85 | ## 5.具体代码实现和解释 86 | ```cpp 87 | #include 88 | using namespace std; 89 | 90 | void get_next(string T, int next[]){ // T中T[0]储存的是T的字符串长度 91 | int i = 1, j = 0; // i为T中指针,j为next数组下标 92 | Next[1] = 0; 93 | 94 | while(i < T[0]){ // j即保存了Ti配位的位置,也通过 j-1 保存了最大公共子串的字符数 95 | if(j == 0 || T[i] == T[j]) {i++;j++;Next[i] = j;} 96 | else j = Next[j]; 97 | } 98 | 99 | 100 | 101 | } 102 | 103 | 104 | int KMP(string S, string T, int pos){ // T中T[0]储存的是T的字符串长度 105 | int i = pos; int j = 1; 106 | while(i <= S.length && j <= S.length){ 107 | if(j==0 || T[j] == S[i]) {++i; ++j;} 108 | else j = next[j]; 109 | } 110 | if(j > T[0]) return i - T[0]; 111 | else return 0; 112 | 113 | } 114 | 115 | int main(){ 116 | 117 | 118 | 119 | return 0; 120 | } 121 | 122 | ``` 123 | 124 | ## 附:修正后的Next代码 125 | ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200928160840666.png?#pic_center) 126 | 127 | ```cpp 128 | #include 129 | using namespace std; 130 | 131 | int* getNext2(int Next[], string T){ 132 | int j = 0; Next[1] = 0; 133 | int i = 1; 134 | while(i < string.length()){ 135 | if(j = 0 || T[i] == T[j]) { 136 | j++; i++; 137 | if(T[i] != T[j]) Next[i] = j; 138 | else next[i] = next[j]; // 等于前一位 139 | } 140 | else j = Next[j]; 141 | 142 | } 143 | 144 | } 145 | ``` 146 | -------------------------------------------------------------------------------- /Algorithm/Kruskal算法介绍.md: -------------------------------------------------------------------------------- 1 | [1.Kruskal算法介绍](1.Kruskal算法介绍) 2 | 3 | [2.模板实现](2.模板实现) 4 | 5 | [3.例题](3.例题) 6 | 7 |
8 | 9 | # 1.Kruskal算法介绍 10 | 克鲁斯卡尔算法可以称为“加边法”,初始最小生成树边数为0,每迭代一次就选择一条满足条件的最小代价边,加入到最小生成树的边集合里。 11 | 1. 把图中的所有边按代价从小到大排序; 12 | 2. 把图中的n个顶点看成独立的n棵树组成的森林; 13 | 3. 按权值从小到大选择边,所选的边连接的两个顶点ui,viui,vi,应属于两颗不同的树,则成为最小生成树的一条边,并将这两颗树合并作为一颗树。 14 | 4. 重复(3),直到所有顶点都在一颗树内或者有n-1条边为止。 15 | ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200914103548705.png?#pic_center) 16 | 17 | **总结:==从小开始加,确保无回路(树)==** 18 | 19 | 20 |
21 |
22 | || 区别普利姆最小生成树算法:普利姆算法从顶点的角度为出发点。时间复杂度为O(n^2)。**更适合于稠密度更高的连通网**。 23 | 而克鲁斯卡尔算法从边的角度求最小生成树,时间复杂度为O(eloge),**更适合于稠密度更高的连通网**。 24 | 25 |
26 | || 判断是否会产生回路的方法为: 27 | 在初始状态下给每个顶点赋予不同的标记,对于遍历过程的每条边,其都有两个顶点,判断这两个顶点的标记是否一致,如果一致,说明它们本身就处在一棵树中,如果继续连接就会产生回路;如果不一致,说明它们之间还没有任何关系,可以连接。 28 | 29 |
30 |
31 | 32 | # 2.模板实现 33 | ```cpp 34 | //最小生成树(Kruskal算法) 35 | #include 36 | #include 37 | using namespace std; 38 | 39 | struct point{ 40 | int x; 41 | int y; 42 | int v; 43 | }; //写结构体用来构造边 44 | point a[10000];//存边 45 | 46 | int cmp(const point &a,const point &b){ 47 | if(a.v>n; 66 | for(i=1;i<=n;i++) 67 | for(j=1;j<=n;j++) 68 | { 69 | cin>>m; 70 | if(m!=0){ 71 | k++; 72 | a[k].x=i; 73 | a[k].y=j; 74 | a[k].v=m; 75 | } 76 | }//输入,存边 77 | sort(a+1,a+1+k,cmp);//快排所有边 78 | 79 | for(i=1;i<=n;i++){ 80 | fat[i]=i; 81 | }//初始化,将每个点看做独立集合 82 | 83 | for(i=1;i<=k;i++){ 84 | if(father(a[i].x)!=father(a[i].y)){//如果这条边连接的两个点属于不同集合 85 | ans+=a[i].v;//将这条边加入最小生成树 86 | unionn(a[i].x,a[i].y);//将两个点所在的集合合并为一个集合 87 | cnt++;//计数已添加的边 88 | } 89 | if(cnt==n-1) break;//当已经有n-1条边的时候,结束 90 | } 91 | 92 | cout< 100 | 101 | 102 | # 3.例题 103 | ![在这里插入图片描述](https://img-blog.csdnimg.cn/2020091411260018.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2ExMzM1MjkxMjYzMg==,size_16,color_FFFFFF,t_70#pic_center) 104 | 105 | ![image](https://user-images.githubusercontent.com/50513297/93366530-dff1fd00-f87d-11ea-83a8-467987d70f88.png) 106 | ///////////////////////////////////////////////解法 107 | ![image](https://user-images.githubusercontent.com/50513297/93366570-ef714600-f87d-11ea-9a43-89c0d48a4628.png) 108 | ![image](https://user-images.githubusercontent.com/50513297/93366586-f304cd00-f87d-11ea-9168-416c41ccaf82.png) 109 | 110 | 111 | ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200914112752712.png?#pic_center) 112 | 113 | 114 | 115 | 116 | 117 | -------------------------------------------------------------------------------- /Algorithm/自动机-字符串算法.md: -------------------------------------------------------------------------------- 1 | ![](https://github.com/fang0jun/Blog/blob/master/images/20200912154046124.png) 2 | 3 | ![](https://github.com/fang0jun/Blog/blob/master/images/20200912154125121.png) 4 | 5 | # 代码实现 6 | ```cpp 7 | /* ---------------------模板-----------------------*/ 8 | class Automaton { 9 | string state = "start"; 10 | unordered_map> table = { 11 | {"start", {"start", "signed", "in_number", "end"}}, 12 | {"signed", {"end", "end", "in_number", "end"}}, 13 | {"in_number", {"end", "end", "in_number", "end"}}, 14 | {"end", {"end", "end", "end", "end"}} 15 | }; 16 | 17 | int get_col(char c) { 18 | if (isspace(c)) return 0; 19 | if (c == '+' or c == '-') return 1; 20 | if (isdigit(c)) return 2; 21 | return 3; 22 | } 23 | public: 24 | int sign = 1; 25 | long long ans = 0; 26 | 27 | void get(char c) { 28 | state = table[state][get_col(c)]; 29 | if (state == "in_number") { 30 | ans = ans * 10 + c - '0'; 31 | ans = sign == 1 ? min(ans, (long long)INT_MAX) : min(ans, -(long long)INT_MIN); 32 | } 33 | else if (state == "signed") 34 | sign = c == '+' ? 1 : -1; 35 | } 36 | }; 37 | 38 | 39 | /* ---------------------调用-----------------------*/ 40 | class Solution { 41 | public: 42 | int myAtoi(string str) { 43 | Automaton automaton; 44 | for (char c : str) 45 | automaton.get(c); 46 | return automaton.sign * automaton.ans; 47 | } 48 | }; 49 | 50 | ``` 51 | -------------------------------------------------------------------------------- /Articles/C中文件操作复习.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | - [fopen()](#fopen) 4 | - [fputc() 和 fgetc()](#fputc-和-fgetc) 5 | - [fgets()](#fgets) 6 | - [fputs()](#fputs) 7 | - [fread()和fwrite()](#fread和fwrite) 8 | - [读写函数的区别](#读写函数的区别) 9 | - [详解EOF](#详解eof) 10 | 11 | || FILE 是系统定义的一个类型,其中包含由文件的各种信息,如文件名,文件地址 12 | || 我们一般使用FILE *fp —— 一个文件指针来操作文件 13 | 14 | 15 | ## fopen() 16 | || fopen():用来以指定的方式打开文件,其原型为: 17 | 18 | ```c 19 | FILE * fopen(const char * path, const char * mode); 20 | ``` 21 | 打开成功时返回类型为文件指针,若打开失败则返回空指针NULL 22 | 第一个参数为文件路径: `fp = fopen(./123.txt, "w")` 23 | 第二个参数mode为打开方式,有以下几种方式: 24 | |打开方式| 说明| 25 | |--|--| 26 | |r |以只读方式打开文件,该文件必须存在。 27 | |r+| 以读/写方式打开文件,该文件必须存在。 28 | |rb+ |以读/写方式打开一个二进制文件,只允许读/写数据。 29 | |rt+ |以读/写方式打开一个文本文件,允许读和写。 30 | |w| 打开只写文件,若文件存在则长度清为0,即该文件内容消失,若不存在则创建该文件。 31 | |w+| 打开可读/写文件,若文件存在则文件长度清为零,即该文件内容会消失。若文件不存在则建立该文件。 32 | |a |以附加的方式打开只写文件。若文件不存在,则会建立该文件,如果文件存在,写入的数据会被加到文件尾,即文件原先的内容会被保留(EOF符保留)。 33 | |a+| 以附加方式打开可读/写的文件。若文件不存在,则会建立该文件,如果文件存在,则写入的数据会被加到文件尾后,即文件原先的内容会被保留(原来的EOF符 不保留)。 34 | |wb| 以只写方式打开或新建一个二进制文件,只允许写数据。 35 | |wb+| 以读/写方式打开或建立一个二进制文件,允许读和写。 36 | |wt+| 以读/写方式打开或建立一个文本文件,允许读写。 37 | |at+| 以读/写方式打开一个文本文件,允许读或在文本末追加数据。 38 | |ab+| 以读/写方式打开一个二进制文件,允许读或在文件末追加数据。 39 | 40 | --- 41 | ## fputc() 和 fgetc() 42 | 43 | || **fgetc()**: fgetc 是 file get char 的缩写,意思是**从指定的文件中读取一个字符到缓存区**。 44 | 经常配合使用 putchar(ch) -- 从缓存区输出一个字符到屏幕上 45 | >它的语法为:`int fgetc (FILE *fp);` 46 | 47 | 48 | 读取成功时返回读取到的字符,读取到文件末尾或读取失败时返回EOF(EOF 是 end of file 的缩写,表示文件末尾,它的值是一个负数,往往是 -1(反正不能是char(char为正数) ) ) 49 | 50 |
51 | 52 | 【示例】在屏幕上显示 D:\\demo.txt 文件的内容。 53 | 54 | ```c 55 | #include 56 | int main(){ 57 | FILE *fp; 58 | char ch; 59 | 60 | //如果文件不存在,给出提示并退出 61 | if( (fp=fopen("D:\\demo.txt","rt")) == NULL ){ 62 | puts("Fail to open file!"); 63 | exit(0); 64 | } 65 | 66 | //每次读取一个字节,直到读取完毕 67 | while( (ch=fgetc(fp)) != EOF ){ 68 | putchar(ch); 69 | } 70 | putchar('\n'); //输出换行符 71 | 72 | if(ferror(fp)){ 73 | puts("读取出错"); 74 | }else{ 75 | puts("读取成功"); 76 | } 77 | 78 | fclose(fp); 79 | return 0; 80 | } 81 | ``` 82 | 83 | 84 |
85 | 86 | || **fputc()**: fputtc 是 file output char 的缩写,意思是 **从缓存区读取一个字符到指定的文件中** 。 87 | 经常配合使用getchar() **从键盘中读取一个字符到缓存区** 88 | >它的语法为:`int fputc ( int ch, FILE *fp );` 89 | 90 | 91 | 【示例】从键盘输入一行字符,写入文件。 92 | 93 | ```c 94 | #include 95 | int main(){ 96 | FILE *fp; 97 | char ch; 98 | 99 | //判断文件是否成功打开 100 | if( (fp=fopen("D:\\demo.txt","wt+")) == NULL ){ 101 | puts("Fail to open file!"); 102 | exit(0); 103 | } 104 | 105 | printf("Input a string:\n"); 106 | //每次从键盘读取一个字符并写入文件 107 | while ( (ch=getchar()) != '\n' ){ 108 | fputc(ch,fp); 109 | } 110 | fclose(fp); 111 | return 0; 112 | } 113 | ``` 114 | 115 | 116 | >== fgetc() / fputc()默认包含移动一个位置指针的功能== 117 | >在文件内部有一个位置指针,用来指向当前读写到的位置,也就是读写到第几个字节。在文件打开时,该指针总是指向文件的第一个字节。使用 fgetc() 函数后,该指针会向后移动一个字节,所以可以连续多次使用 fgetc() 读取多个字符。 118 | 119 | 120 | 121 | 122 | 123 |
124 | 125 | ## fgets() 126 | || 读字符串函数 fgets() 127 | fgets() 函数用来从指定的文件中读取一个字符串,并保存到字符数组中(至缓存区),它的语法为: 128 | >它的语法为:`char *fgets ( char *str, int n, FILE *fp ); // str 为字符数组,n 为要读取的字符数目,fp 为文件指针。` 129 | 130 | 131 | tip_1:读取到的字符串会在末尾自动添加 '\0',n 个字符也包括 '\0'。 132 | *也就是说*:实际只读取到了 n-1 个字符,如果希望读取 100 个字符,n 的值应该为 101。 133 | tip_2:需要重点说明的是,在读取到 n-1 个字符之前如果出现了**换行'\n'**,或者读到了**文件末尾**,则读取结束。 134 | *也就是说*:不管 n 的值多大,fgets() 最多只能读取一行数据,不能跨行。在C语言中,没有按行读取文件的函数,我们可以借助 fgets(),将 n 的值设置地足够大,每次就可以读取到一行数据。 135 | 136 |
137 | 138 | 【示例】一行一行地读取文件。 139 | 140 | ```c 141 | #include 142 | #include 143 | #define N 100 144 | int main(){ 145 | FILE *fp; 146 | char str[N+1]; 147 | if( (fp=fopen("d:\\demo.txt","rt")) == NULL ){ 148 | puts("Fail to open file!"); 149 | exit(0); 150 | } 151 | 152 | while(fgets(str, N, fp) != NULL){ 153 | printf("%s", str); 154 | } 155 | 156 | fclose(fp); 157 | return 0; 158 | } 159 | ``` 160 | 161 | 162 |
163 |
164 | 165 | ## fputs() 166 | fputs() 函数用来向指定的文件写入一个字符串,(至缓存区),它的用法为: 167 | 168 | ```c 169 | int fputs( char *str, FILE *fp ); 170 | ``` 171 | 【示例】向上例中建立的 d:\\demo.txt 文件中追加一个字符串。 172 | ```c 173 | #include 174 | int main(){ 175 | FILE *fp; 176 | char str[102] = {0}, strTemp[100]; 177 | if( (fp=fopen("D:\\demo.txt", "at+")) == NULL ){ 178 | puts("Fail to open file!"); 179 | exit(0); 180 | } 181 | printf("Input a string:"); 182 | gets(strTemp); 183 | strcat(str, "\n"); 184 | strcat(str, strTemp); 185 | fputs(str, fp); 186 | fclose(fp); 187 | return 0; 188 | } 189 | ``` 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | ## fread()和fwrite() 198 | 对于 Windows 系统,使用 fread() 和 fwrite() 时应该以二进制的形式打开文件。附[《文本文件和二进制文件的差异和区别》](https://blog.csdn.net/a13352912632/article/details/108743530) 199 | 200 | fread() 函数用来从指定文件中读取块数据。所谓块数据,也就是若干个字节的数据,可以是一个字符,可以是一个字符串,可以是多行数据,并没有什么限制(无限制的fgetc()/fgets() )。fread() 的原型为: 201 | 202 | ```c 203 | size_t fread ( void *ptr, size_t size, size_t count, FILE *fp ); 204 | ``` 205 | 206 | fwrite() 函数用来向文件中写入块数据,它的原型为: 207 | 208 | ```c 209 | size_t fwrite ( void * ptr, size_t size, size_t count, FILE *fp ); 210 | ``` 211 | 212 | || 对参数的说明: 213 | >- ptr 为内存区块的指针,它可以是数组、变量、结构体等。fread() 中的 ptr 用来存放读取到的数据,fwrite() 中的 ptr 用来存放要写入的数据。 214 | >- size:表示每个数据块的字节数。 215 | >- count:表示要读写的数据块的块数。 216 | >- fp:表示文件指针。 217 | 理论上,每次读写 size*count 个字节的数据。 218 | 219 | size_t 是在 stdio.h 和 stdlib.h 头文件中使用 typedef 定义的数据类型,表示无符号整数,也即非负数,常用来表示数量。 220 | 221 | || 返回值:返回成功读写的块数,也即 count。如果返回值小于 count: 222 | - 对于 fwrite() 来说,肯定发生了写入错误,可以用 ferror() 函数检测。 223 | - 对于 fread() 来说,可能读到了文件末尾,可能发生了错误,可以用 ferror() 或 feof() 检测。 224 | 225 |
226 | 227 | 【示例】从键盘输入一个数组,将数组写入文件再读取出来。 228 | 229 | ```c 230 | #include 231 | #define N 5 232 | int main(){ 233 | //从键盘输入的数据放入a,从文件读取的数据放入b 234 | int a[N], b[N]; 235 | int i, size = sizeof(int); 236 | FILE *fp; 237 | if( (fp=fopen("D:\\demo.txt", "rb+")) == NULL ){ //以二进制方式打开 238 | puts("Fail to open file!"); 239 | exit(0); 240 | } 241 | 242 | //从键盘输入数据 并保存到数组a 243 | for(i=0; i 263 |
264 | 265 | ## 读写函数的区别 266 | 267 | ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200922213531829.png#pic_center) 268 | 269 |

270 | 271 | ## 详解EOF 272 | || EOF 本来表示文件末尾,意味着文件*读取* 结束,但是很多函数在读取出错时也返回 EOF,那么当返回 EOF 时,到底是文件读取完毕了还是读取出错了?我们可以借助 stdio.h 中的两个函数来判断,分别是 feof() 和 ferror()。 273 | 274 | || feof() 函数用来判断文件内部指针是否指向了文件末尾,它的原型是:`int feof ( FILE * fp );` 275 | 当指向文件末尾时返回非零值,否则返回零值。 276 | 277 | || ferror() 函数用来判断文件操作是否出错,它的原型是:`int ferror ( FILE *fp );` 278 | 出错时返回非零值,否则返回零值。 279 | 280 | tip:需要说明的是,文件出错是非常少见的情况,上面的示例基本能够保证将文件内的数据读取完毕。如果追求完美,也可以加上判断并给出提示: 281 | ```c 282 | if(ferror(fp)){ puts("读取出错");} 283 | else{ puts("读取成功"); } 284 | fclose(fp); 285 | ``` 286 | 287 | >注意:怎么记忆什么函数返回NULL还是EOF? 函数原型中返回类型若是char 则失败返回EOF, 若返回类型是char* 则返回空指针NULL 288 | - [fopen()](#fopen) 289 | - [fputc() 和 fgetc()](#fputc-和-fgetc) 290 | - [fgets()](#fgets) 291 | - [fputs()](#fputs) 292 | - [fread()和fwrite()](#fread和fwrite) 293 | - [读写函数的区别](#读写函数的区别) 294 | - [详解EOF](#详解eof) -------------------------------------------------------------------------------- /Articles/Engineering a Compiler读书笔记(1)---编译概述.md: -------------------------------------------------------------------------------- 1 | 2 | ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200825075609719.png?#pic_center) 3 | 4 | 5 | 6 | - [1.简介](#1简介) 7 | - [2.编译器的结构](#2编译器的结构) 8 | - [3.转换概述](#3转换概述) 9 | - [3.1 前端中:](#31-前端中) 10 | - [3.2 优化器中:](#32-优化器中) 11 | - [3.3 后端中:](#33-后端中) 12 | - [4.思维导图](#font-colorred4思维导图) 13 | 14 | 15 | 16 | 17 | 18 | 19 | ----------- 20 | 序言: 21 | 22 | 一个现代的优化器中包含有各式各样的技术。编译器使用**贪婪启发式搜索**来探索很大的解空间,使用**确定性有限自动机**来识别输入中的单词,**不动点算法**用于判断程序的行为,通过**定理证明程序和代数化简器**来预测表达式的值。编译器使用**快速匹配算法**将抽象计算映射到机器层次的操作,它们使用**线性丢番图方程和普锐斯伯格算术**来分析数组下标。编译器使用了大量的经典算法和数据结构,如散列表,图算法,和稀疏集实现方法等 23 | 24 | --------- 25 | 第一章:编译概观 26 | 27 | 28 | # 1.简介 29 | 30 | || 编译器是一个计算机程序(类似OS),负责将一种语言编写的编写程序转换为令一种语言编写的程序。编译器的主要组件有:编译器,解释器,自动转换 31 | 32 | || 概念实现的路线图: 33 | 编译器为了实现其语言转换功能,那么就必须有以下功能: 34 | - 理解输入语言的形式和内容(即语法和语义)。 35 | - 理解输出语言的形式和内容(即语法和语义)。 36 | - 映射方案:将源语言映射到目标语言的法则 37 | 38 | 39 | || 由以上功能需求,我们可以得到编译器的结构: 40 | - 前端:用于处理源语言 41 | - 后端:用于处理目标语言 42 | - 中间形式:将前后端连接起来 43 | - 优化器:改进优化转换,用于分析并重写中间形式 44 | 45 | || 有关程序设计语言的说明: 46 | 作用:我们使用程序设计语言将计算表达为操作的序列,计算机程序就是一种由程序设计语言编写的抽象操作序列。 47 | 特点:1,其中的程序设计语言是用来精确表示计算的形式语言 2,是一种不允许有二义性的语言。3,往往具有较高的抽象性 48 | 49 | || 编译器若输出的仍是面对人类的程序设计语言,而非计算机的汇编语言。则称其为 *由源到源的转换器* 50 | 51 | || 解释器和编译器的区别: 52 | 53 | - 编译器的输入是一个可执行的规格,输出的是另一种可执行的规格 54 | - 编译器的输入是一个可执行的规格,输出的是执行该规格的结果 55 | 56 | ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200416170531228.png) 57 | ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200416170517275.png) 58 | 59 | || 解释器和编译器的共同之处: 60 | - 都要分析输入的可执行规格,判断是否有效 61 | - 都会建立一个内部模型,表示输入的结构和语义。 62 | - 都要确定执行期间何处储存值 63 | 64 | || 一些语言在转换方案上的区别: 65 | APL,Scheme,更多的是用解释器实现的,而非编译器 66 | Java,即包括编译,也包括解释来实现:(以下粗略表示过程) 67 | 1. java源代码编译为一种被称为字节码的形式 68 | 2. 在对应的java虚拟机(JVM)上运行字节码执行程序,JVM就是一种字节码的解释器 69 | 70 | || 编译器的基本原则: 71 | 1:编译器必须保存被编译程序的语义 --- 保存是为了在编译过程中保持正确性(防止二义性) 72 | 2:编译器必须以某种课察觉的方式来改进输入程序。例如c语言的源到源的转换器一定程度上由于输入程序,将输入程序改进源程序使得其有更好的可用性和一般性 73 | 74 | 75 | ----------- 76 | # 2.编译器的结构 77 | 78 | || 结构说明: 79 | 前端的工作涉及理解源程序并将其分析结果以IR的形式记录下来; 80 | 优化器的工作专注于改进IR的形式; 81 | 后端的工作则是将转化优化后的IR映射到有限的资源上 82 | 83 | || 编译后代码的实际性能取决于:优化器和后端这两个阶段中使用的技术之间的相互交互的好坏,共同决定(并不是优化功能好,映射功能强,编译效果就好,之间的关联很重要) 84 | ![编译器](https://img-blog.csdnimg.cn/20200416173257426.png) 85 | ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200416173314351.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2ExMzM1MjkxMjYzMg==,size_16,color_FFFFFF,t_70) 86 | 87 | ----- 88 | # 3.转换概述 89 | 90 | ## 3.1 前端中: 91 | || 原因:需要先翻译源代码 92 | 93 | || 前端中进行的转换: 94 | 1. 语法检查: 95 | 96 | || 什么是语法: 97 | 某种规则的有限集定义,称为“语法”。我们通常将句子按词类划分,这样可以通过单一语法规则描述很多句子![在这里插入图片描述](https://img-blog.csdnimg.cn/20200416175645914.png) 98 | || 前端中进行的两趟单独处理,分别称为“词法分析器”和“语法分析器”,来判断输入代码实际上是否属于语法定义中的有效集合 99 | 100 | 101 | 102 | 103 | || 词类分析器: 104 | 进行划分归类工作:识别一句话中各个单词,并将每个单词归入对应的词类中,以形如(p, s)的对的形式归类(p表示单词s的词类) 105 | 作用:将句子划分成已归类的单词构成的流 106 | 107 | 108 | || 语法分析器: 109 | 进行解析(语法分析工作):根据指定的输入语言的语法规则,匹配已分类单词的流,进行*推导* 110 | 作用:判断输入流是不是源语言中的一个句子(即是否满足源语言语法的句子)。 111 | 112 | || 类型检查 113 | 进行类型检查工作:对语法良构的句子进行类型判断(字符串/整型......) 114 | 作用:检查输入程序中对名字的使用在类型上是否一致 115 | 116 | 117 | 2. 中间表示 118 | 生成出代码的IR形式,由于会生成各种种类的IR形式,故会涉及到选择策略问题 119 | 120 | ------- 121 | ## 3.2 优化器中: 122 | 123 | || 原因:IR程序运行时,语句根据其在源代码中的顺序逐条运行时,代码将在更加有限,更加可预测的上下文中来执行。 124 | 功能:为了更加有效地分析IR代码,优化器会分析代码的IR形式,以发现有关上下文的事实,并利用此项有关上下文的知识来重写代码,使之更有效地获得同样的答案。 125 | 126 | || 优化中发生的转换 127 | 1. 分析:判断程序在何处安全且有利地应用优化技术 128 | 常用的分析技术:数据流分析/相关性分析 129 | 130 | 2. 转换:重写分析过的代码 131 | 132 | 133 | || 实例 134 | ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200416182532958.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2ExMzM1MjkxMjYzMg==,size_16,color_FFFFFF,t_70) 135 | ## 3.3 后端中: 136 | 137 | || 原因:后端会遍历优化后的IR代码。为每个IR操作其选择对应的目标机操作来实现它,确定哪些值能够驻留在寄存器中,哪些值需要放进内存中,并自行插入代码以实现这些决策,并选择出一种执行高效的次序。 138 | 139 | || 后端中发生的转换 140 | 1. 指令选择: 141 | 将IR操作重写为目标机操作,这个过程称为指令选择 142 | 143 | 2. 寄存器分配:(最小化内存) 144 | 指令选择阶段,编译器会有意忽略目标机寄存器有限的事实。故这个阶段会重写代码,实现寄存器资源的分配 145 | 146 | 3. 指令调度(最小化时间) 147 | 重排指令的次序,最小化指令在等待操作数撒谎给你所浪费的时间 148 | 149 | ------------ 150 | # 4.思维导图 151 | ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200416190824375.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2ExMzM1MjkxMjYzMg==,size_16,color_FFFFFF,t_70) -------------------------------------------------------------------------------- /Articles/Github下载加速.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 经常从GitHub下载代码非常慢,有时还容易卡住。 4 | 例如从GitHub上下载OpenCV,速度太慢,下载几次都没下载下来。 5 | 6 | 7 | ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200814110419162.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2ExMzM1MjkxMjYzMg==,size_16,color_FFFFFF,t_70#pic_center) 8 | 9 | 10 | ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200814110441440.png#pic_center) 11 | 12 | 13 | 14 | 15 | 16 | 于是网上找看看有没有GitHub下载加速的办法,找了好几处,还是觉得使用国内网站码云间接下载更方便。 码云是开源中国出品的代码托管协作开发云平台。 17 | 码云官网地址:https://gitee.com/ 18 | 19 | 20 | ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200814110242652.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2ExMzM1MjkxMjYzMg==,size_16,color_FFFFFF,t_70#pic_center) 21 | 22 | 23 | 24 | 25 | 26 | 下面举例介绍如何利用码云下载GitHub上的资源。 27 | 28 | 29 | 第一步: 登录码云,没有账号可以注册登录。 30 | 31 | 32 | 第二步: 如下图所示,点击进入: 从GitHub/GitLab 导入仓库 。 33 | 34 | ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200814110251552.png#pic_center) 35 | 36 | 37 | 38 | 第三步: 复制GitHub需要下载仓库的链接:https://github.com/opencv/opencv 39 | 40 | ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200814110314640.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2ExMzM1MjkxMjYzMg==,size_16,color_FFFFFF,t_70#pic_center) 41 | 42 | 43 | 第四步: 在码云中添加仓库的链接,然后导入。 44 | 45 | ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200814110326798.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2ExMzM1MjkxMjYzMg==,size_16,color_FFFFFF,t_70#pic_center) 46 | 47 | 第五步:导入成功后,码云上就有GitHub的仓库,然后下载即可。 48 | 49 | ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200814110334169.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2ExMzM1MjkxMjYzMg==,size_16,color_FFFFFF,t_70#pic_center) 50 | 51 | 52 | 53 | 这个下载速度明显快了。 54 | 55 | ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200814110532805.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2ExMzM1MjkxMjYzMg==,size_16,color_FFFFFF,t_70#pic_center) 56 | 57 | 58 | 59 | 以上就是GitHub下载加速的方法,个人觉得比较简单、方便,写个笔记做个记录。 60 | 61 | 62 | 总结: 在国内网站码云中导入需要下载的GitHub链接,导入成功后,在码云下载即可。 63 | 64 | 65 | 66 | 67 | 68 | 参考资料 69 | 70 | [1] 一招搞定GitHub下载加速! 71 | [2] 如何将 GitHub 项目导入码云?一步搞定! 72 | -------------------------------------------------------------------------------- /Articles/Matlab操作(1):基础的矩阵操作及运算.md: -------------------------------------------------------------------------------- 1 | ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200822153724620.png#pic_center) 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 | ```matlab 34 | >> A = [1 2; 3 4; 5 6] 35 | A = 36 | 1 2 37 | 3 4 38 | 5 6 39 | 40 | 41 | >> A = [1 2; % ;号在这里的作用可以看做是换行符,也就是生成矩阵的下一行。 42 | > 3 4; 43 | > 5 6] 44 | A = 45 | 1 2 46 | 3 4 47 | 5 6 48 | 49 | >> V1 = [1 2 3] 50 | V1 = 51 | 1 2 3 52 | 53 | >> V2 = [1; 2; 3] 54 | V2 = 55 | 1 56 | 2 57 | 3 58 | ``` 59 | 60 | 61 | 62 | ##### 矩阵生成的内置函数 63 | 64 | `ones(m, n)` 函数生成一个m行n列的矩阵,矩阵中每个元的值为1。 65 | 66 | `zeros(m, n)` 函数生成一个m行n列的矩阵,矩阵中每个元的值为0。 67 | 68 | `rand(m, n)` 函数生成一个m行n列的矩阵,矩阵的每个元是0到1之间的一个随机数。 69 | 70 | `eye(m)` 函数生成一个大小为m的单位矩阵。 71 | 72 | 73 | 74 | ```matlab 75 | >> ones(2, 3) 76 | ans = 77 | 1 1 1 78 | 1 1 1 79 | 80 | >> w = zeros(1, 3) 81 | w = 82 | 0 0 0 83 | 84 | >> w = rand(1, 3) 85 | w = 86 | 0.19402 0.23458 0.49843 87 | 88 | >> eye(4) 89 | ans = 90 | Diagonal Matrix 91 | 1 0 0 0 92 | 0 1 0 0 93 | 0 0 1 0 94 | 0 0 0 1 95 | ``` 96 | 97 | 98 | 99 | # 向量 / 矩阵的属性 100 | 101 | > 默认创建了一个矩阵,方便下文说明 102 | > A = 103 | > 1 2 104 | > 3 4 105 | > 5 6 106 | 107 | 108 | 109 | ##### 矩阵的大小 110 | 内置`size`函数 111 | 112 | `size`函数返回的结果也是一个矩阵,但这个矩阵的大小是1×2,这个1×2的矩阵中,两个元素的值分别代表了参数矩阵的行数和列数。 113 | 114 | 增加参数可以选择需要的数据size(A, 1)为行数,size(A, 2)为列数 115 | 116 | ```matlab 117 | >> sa = size(A); 118 | >> sa 119 | sa = 120 | 3 2 121 | 122 | >> size(A, 1) 123 | ans = 3 124 | >> size(A, 2) 125 | ans = 2 126 | ``` 127 | 128 | 129 | 130 | ##### 矩阵的维度 131 | 132 | 内置`length`函数 133 | 134 | 对于矩阵来说,它获取的是矩阵中最大的那个维度的值;对于向量来说,它获取的就是向量的维度了 135 | 136 | ```matlab 137 | >> V = [1 2 3 4] 138 | V = 139 | 1 2 3 4 140 | 141 | >> length(V) 142 | ans = 4 143 | 144 | octave:67> length(A) 145 | ans = 3 146 | ``` 147 | 148 | 149 | 150 | # 向量 / 矩阵的运算 151 | 152 | 153 | 154 | ##### 获取矩阵中的元素 155 | 156 | 获取矩阵指定行指定列的元素:使用括号取值,返回一个元素(注意,下标编号是从1开始的不是从0哦) 157 | 158 | ```matlab 159 | >> A(3, 2) 160 | ans = 6 161 | ``` 162 | 163 | 获取矩阵指定整行或整列的元素:括号中使用`:`代替行或列,返回一个向量 164 | 165 | ``` 166 | >> A(3,:) 167 | ans = 168 | 5 6 169 | 170 | >> A(:, 2) 171 | ans = 172 | 2 173 | 4 174 | 6 175 | ``` 176 | 177 | 也可以指定要获取的某几行或某几列的元素:括号中使用方括号包含你想选择的列 178 | 179 | ```matlab 180 | >> A([1, 3],:) 181 | ans = 182 | 1 2 183 | 5 6 184 | 185 | >> A(:,[2]) 186 | ans = 187 | 2 188 | 4 189 | 6 190 | ``` 191 | 192 | 193 | 194 | ##### 矩阵的元素重新赋值: 195 | 196 | ```matlab 197 | >> A(:,2) = [10, 11, 12] 198 | A = 199 | 1 10 200 | 3 11 201 | 5 12 202 | 203 | >> A(1,:) = [11 22] 204 | A = 205 | 206 | 11 22 207 | 3 4 208 | 5 6 209 | ``` 210 | 211 | 212 | 213 | 214 | 215 | ##### 矩阵进行扩展:(常用于增广矩阵) 216 | 217 | ```matlab 218 | >> A = [A [100; 101; 102]] 219 | A = 220 | 1 2 100 221 | 3 4 101 222 | 5 6 102 223 | ``` 224 | 225 | 226 | 227 | 228 | 229 | ##### 矩阵间的运算 230 | 231 | > 设A,B,C三个矩阵 232 | 233 | ```matlab 234 | >> A*C 235 | >> A/C 236 | >> A^2 237 | ``` 238 | 239 | 240 | 241 | ##### 矩阵间的点运算 242 | 243 | > 可以理解为对矩阵中每个元素做对应运算 244 | 245 | ```matlab 246 | >> A .^ 2 247 | ans = 248 | 1 4 249 | 9 16 250 | 25 36 251 | 252 | >> 1 ./ [1; 2; 3] 253 | ans = 254 | 1.00000 255 | 0.50000 256 | 0.33333 257 | 258 | %(A中的各个元素乘以B中对应位置的元素) 259 | >> A .* B 260 | ans = 261 | 11 24 262 | 39 56 263 | 75 96 264 | 265 | 266 | %(特殊情况:当一个实数与矩阵做乘法运算时,我们可以省略.直接使用*即可) 267 | >> -1 * [1; -2; 3] % 也可以简写为 -1[1; 2; 3] 268 | ans = 269 | -1 270 | 2 271 | -3 272 | ``` 273 | 274 | ------------ 275 | 以上是矩阵的基本操作,更多线性代数中的矩阵操作跳转我的另外一篇博客: 276 | [Matlab操作(2):线性代数中求矩阵相关数据的高级方法](https://blog.csdn.net/a13352912632/article/details/108172981) 277 | 278 | 279 | -------------------------------------------------------------------------------- /Articles/Octave基础知识——矩阵操作及运算.md: -------------------------------------------------------------------------------- 1 | ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200822153724620.png#pic_center) 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 | ```matlab 36 | >> A = [1 2; 3 4; 5 6] 37 | A = 38 | 1 2 39 | 3 4 40 | 5 6 41 | 42 | 43 | >> A = [1 2; % ;号在这里的作用可以看做是换行符,也就是生成矩阵的下一行。 44 | > 3 4; 45 | > 5 6] 46 | A = 47 | 1 2 48 | 3 4 49 | 5 6 50 | 51 | >> V1 = [1 2 3] 52 | V1 = 53 | 1 2 3 54 | 55 | >> V2 = [1; 2; 3] 56 | V2 = 57 | 1 58 | 2 59 | 3 60 | ``` 61 | 62 | 63 | 64 | ##### 矩阵生成的内置函数 65 | 66 | `ones(m, n)` 函数生成一个m行n列的矩阵,矩阵中每个元的值为1。 67 | 68 | `zeros(m, n)` 函数生成一个m行n列的矩阵,矩阵中每个元的值为0。 69 | 70 | `rand(m, n)` 函数生成一个m行n列的矩阵,矩阵的每个元是0到1之间的一个随机数。 71 | 72 | `eye(m)` 函数生成一个大小为m的单位矩阵。 73 | 74 | 75 | 76 | ```matlab 77 | >> ones(2, 3) 78 | ans = 79 | 1 1 1 80 | 1 1 1 81 | 82 | >> w = zeros(1, 3) 83 | w = 84 | 0 0 0 85 | 86 | >> w = rand(1, 3) 87 | w = 88 | 0.19402 0.23458 0.49843 89 | 90 | >> eye(4) 91 | ans = 92 | Diagonal Matrix 93 | 1 0 0 0 94 | 0 1 0 0 95 | 0 0 1 0 96 | 0 0 0 1 97 | ``` 98 | 99 | 100 | 101 | # 向量 / 矩阵的属性 102 | 103 | > 默认创建了一个矩阵,方便下文说明 104 | > A = 105 | > 1 2 106 | > 3 4 107 | > 5 6 108 | 109 | 110 | 111 | ##### 矩阵的大小 112 | 内置`size`函数 113 | 114 | `size`函数返回的结果也是一个矩阵,但这个矩阵的大小是1×2,这个1×2的矩阵中,两个元素的值分别代表了参数矩阵的行数和列数。 115 | 116 | 增加参数可以选择需要的数据size(A, 1)为行数,size(A, 2)为列数 117 | 118 | ```matlab 119 | >> sa = size(A); 120 | >> sa 121 | sa = 122 | 3 2 123 | 124 | >> size(A, 1) 125 | ans = 3 126 | >> size(A, 2) 127 | ans = 2 128 | ``` 129 | 130 | 131 | 132 | ##### 矩阵的维度 133 | 134 | 内置`length`函数 135 | 136 | 对于矩阵来说,它获取的是矩阵中最大的那个维度的值;对于向量来说,它获取的就是向量的维度了 137 | 138 | ```matlab 139 | >> V = [1 2 3 4] 140 | V = 141 | 1 2 3 4 142 | 143 | >> length(V) 144 | ans = 4 145 | 146 | octave:67> length(A) 147 | ans = 3 148 | ``` 149 | 150 | 151 | 152 | # 向量 / 矩阵的运算 153 | 154 | 155 | 156 | ##### 获取矩阵中的元素 157 | 158 | 获取矩阵指定行指定列的元素:使用括号取值,返回一个元素(注意,下标编号是从1开始的不是从0哦) 159 | 160 | ```matlab 161 | >> A(3, 2) 162 | ans = 6 163 | ``` 164 | 165 | 获取矩阵指定整行或整列的元素:括号中使用`:`代替行或列,返回一个向量 166 | 167 | ``` 168 | >> A(3,:) 169 | ans = 170 | 5 6 171 | 172 | >> A(:, 2) 173 | ans = 174 | 2 175 | 4 176 | 6 177 | ``` 178 | 179 | 也可以指定要获取的某几行或某几列的元素:括号中使用方括号包含你想选择的列 180 | 181 | ```matlab 182 | >> A([1, 3],:) 183 | ans = 184 | 1 2 185 | 5 6 186 | 187 | >> A(:,[2]) 188 | ans = 189 | 2 190 | 4 191 | 6 192 | ``` 193 | 194 | 195 | 196 | ##### 矩阵的元素重新赋值: 197 | 198 | ```matlab 199 | >> A(:,2) = [10, 11, 12] 200 | A = 201 | 1 10 202 | 3 11 203 | 5 12 204 | 205 | >> A(1,:) = [11 22] 206 | A = 207 | 208 | 11 22 209 | 3 4 210 | 5 6 211 | ``` 212 | 213 | 214 | 215 | 216 | 217 | ##### 矩阵进行扩展:(常用于增广矩阵) 218 | 219 | ```matlab 220 | >> A = [A [100; 101; 102]] 221 | A = 222 | 1 2 100 223 | 3 4 101 224 | 5 6 102 225 | ``` 226 | 227 | 228 | 229 | 230 | 231 | ##### 矩阵间的运算 232 | 233 | > 设A,B,C三个矩阵 234 | 235 | ```matlab 236 | >> A*C 237 | >> A/C 238 | >> A^2 239 | ``` 240 | 241 | 242 | 243 | ##### 矩阵间的点运算 244 | 245 | > 可以理解为对矩阵中每个元素做对应运算 246 | 247 | ```matlab 248 | >> A .^ 2 249 | ans = 250 | 1 4 251 | 9 16 252 | 25 36 253 | 254 | >> 1 ./ [1; 2; 3] 255 | ans = 256 | 1.00000 257 | 0.50000 258 | 0.33333 259 | 260 | %(A中的各个元素乘以B中对应位置的元素) 261 | >> A .* B 262 | ans = 263 | 11 24 264 | 39 56 265 | 75 96 266 | 267 | 268 | %(特殊情况:当一个实数与矩阵做乘法运算时,我们可以省略.直接使用*即可) 269 | >> -1 * [1; -2; 3] % 也可以简写为 -1[1; 2; 3] 270 | ans = 271 | -1 272 | 2 273 | -3 274 | ``` 275 | 276 | 277 | 278 | # 矩阵的常用操作汇总 ( 重要!!) 279 | 280 | `pinv(A)`: 矩阵的逆 281 | 282 | `rref(A)`:化简矩阵!!! (高斯) 283 | 284 | `A'`:矩阵的转置 285 | 286 | ```matlab 287 | >> V + ones(length(V), 1) % V = [1; 2; 3] 288 | ans = 289 | 2 290 | 3 291 | 4 292 | 293 | % 矩阵的转置 294 | >> A' 295 | ans = 296 | 1 3 5 297 | 2 4 6 298 | 299 | % 求矩阵的逆 300 | >> pinv(A) 301 | ans = 302 | 0.147222 -0.144444 0.063889 303 | -0.061111 0.022222 0.105556 304 | -0.019444 0.188889 -0.102778 305 | 306 | >> rref(A) 307 | ans = 308 | 309 | 1 0 -1 310 | 0 1 2 311 | 0 0 0 312 | ``` 313 | 314 | 315 | 316 | # 求解线性方程组 ( 重要!!) 317 | 318 | 319 | 320 | ![undefined](https://imgconvert.csdnimg.cn/aHR0cDovL3d3MS5zaW5haW1nLmNuL2xhcmdlLzAwNlAwOGxSZ3kxZ2ZkeXNlYzgzcmozMDdiMDkybXd6LmpwZw?x-oss-process=image/format,png) 321 | 322 | ---------------- 323 | 参考于:https://blog.csdn.net/iszhenyu/article/details/78712228 -------------------------------------------------------------------------------- /Articles/c语言中extern的使用.md: -------------------------------------------------------------------------------- 1 | - [extern的使用](#extern的使用) 2 | - [1. 作用一:防止编译器混淆同文件中的声明与定义](#1-作用一防止编译器混淆同文件中的声明与定义) 3 | - [2. 作用二:防止编译器混淆不同文件中声明与定义](#2-作用二防止编译器混淆不同文件中声明与定义) 4 | 5 | # extern的使用 6 | ## 1. 作用一:防止编译器混淆同文件中的声明与定义 7 | 在使用外部链接和内部链接的静态变量时,为了防止同名变量的覆盖(防止编译器混淆声明与定义),我们按声明的位置把变量分为: 8 | - 外部变量(**external variable**):,把变量的定义性声明放在了所有函数外面的变量 9 | - 内部变量:自动变量,寄存器变量,静态变量 10 | 11 | ```c 12 | #include 13 | int num = 1; // 外部链接的静态变量 14 | static char ch = 'a'; // 内部链接的静态变量 15 | int main(){ 16 | extern int num; // 该语句为声明而非定义(再次声明了num外部链接的静态变量) 17 | extern char ch; 18 | /* int num; 该语句为定义,而非声明(定义了一个同名为num的局部变量) */ 19 | /* char ch; 该语句为定义,而非声明(定义了一个同名为ch的局部变量) */ 20 | 21 | return 0; 22 | } 23 | ``` 24 | 25 | ## 2. 作用二:防止编译器混淆不同文件中声明与定义 26 | 27 | ```c 28 | #incldue 29 | int num1 = 1; // 此处定义了该文件中的一个外部链接的静态变量num1 30 | extern int num2; // 此处是声明了一其他文件中的一个外部链接的静态变量num2 31 | 32 | int main(){ 33 | 34 | return 0; 35 | } 36 | ``` 37 | 38 | 总结: 39 | ==函数内使用extern,那么“外部”是相对于函数的,也就是指该文件的函数外 40 | 函数外使用extern,那么“外部”是相对于文件的,也就是指该文件外== 41 | -------------------------------------------------------------------------------- /Articles/haskell一些内置函数的实现和扩展(1).md: -------------------------------------------------------------------------------- 1 | 2 | -- 取头元素 3 | ```haskell 4 | head' :: [a] -> a 5 | head' [] = error "empty list"; 6 | head' (x:xs) = x 7 | ``` 8 | 9 | 取第二个元素 10 | ```haskell 11 | headSecond :: [a] -> a 12 | headSecond [] = error "empty list" 13 | headSecond [x] = error "only one element" 14 | headSecond [x,y] = y 15 | headSecond (x:y:z) = headSecond [x,y] 16 | ``` 17 | 18 | -- 取最后一个元素 19 | ```haskell 20 | last' :: [a] -> a 21 | last' [] = error "empty list" 22 | last' [x] = x 23 | last' (x:xs) = last' xs 24 | ``` 25 | 26 | -- 注意:错误写法: last' (x:xs) = last' [xs] 27 | -- 此处的被":" 的 xs 本来就是list 28 | 29 | -- 取倒数第二个元素 30 | ```haskell 31 | lastSecond :: [a] -> a 32 | lastSecond [] = error "empty list" 33 | lastSecond [x] = error "only one element" 34 | lastSecond [x, y] = x 35 | lastSecond (x:y:xs) = lastSecond (y:xs) 36 | ``` 37 | 38 | -- 此处的":" x,y是变量;xs是list 39 | -- ch1 :: [a] -> [b] 这里的变量必不能是一样的 40 | 41 | -- 将头元素放至list的尾端 42 | ```haskell 43 | ch1 :: [a] -> [a] 44 | ch1 [] = error "empty list" 45 | ch1 [x] = [x] 46 | ch1 (x:xs) = xs ++ [x] 47 | ``` 48 | 49 | --删掉最后一个元素 50 | 51 | ```haskell 52 | delLast :: [a] -> [a] 53 | delLast [] = error "empty list" 54 | delLast [x] = [] 55 | delLast (x:xs) = x : delLast xs 56 | ``` 57 | 58 | --将最后一个数字移至开头 59 | ```haskell 60 | ch2 :: [a] -> [a] 61 | ch2 [] = error "empty list" 62 | ch2 [x] = [x] 63 | ch2 (x:xs) = [last' xs] ++ delLast xs 64 | ``` 65 | 66 | --置换开头和最后一个元素 67 | 68 | ```haskell 69 | ch3 :: [a] -> [a] 70 | ch3 [] = error "empty list" 71 | ch3 [x] = [x] 72 | ch3 [x,y] = [y, x] 73 | ch3 (x:y:xs) = [last' (y:xs)] ++ delLast (y:xs) ++ [x] 74 | ``` 75 | 76 | 77 | ```haskell 78 | ch3' :: [a] -> [a] 79 | ch3' [] = [] 80 | ch3' [x] = [x] 81 | ch3' (x:xs) = 82 | let (f, g) = swap x xs 83 | in f:g 84 | where swap k [y] = (y, [k]) 85 | swap k (y:ys) = let (n,m) = swap k ys in (n, y:m) 86 | ``` 87 | 88 | -- 删除数组中指定值 89 | 90 | ```haskell 91 | delVal :: (Eq) a => a -> [a] -> [a] 92 | delVal elem [] = [] 93 | delVal elem (x:xs) 94 | | elem == x = delVal elem xs 95 | | otherwise = x : delVal elem xs 96 | ``` 97 | 98 | 99 | --删除与第一个元素值相同的值 100 | 101 | ```haskell 102 | get :: (Eq) a => [a] -> [a] 103 | --get [] = error "empty list" 104 | get [] = [] 105 | get (x:xs) = x : get ( delVal x xs ) 106 | ``` 107 | 108 | 109 | 110 | ```haskell 111 | get1 :: (Eq) a => [a] -> [a] 112 | --get [] = error "empty list" 113 | get1 [] = [] 114 | get1 (x:xs) 115 | | delVal x xs == xs = x : get1 xs 116 | | otherwise = get1 ( delVal x xs ) 117 | ``` 118 | 119 | 120 | ```haskell 121 | dump1 :: (Eq a) => [a] -> [a] 122 | dump1 [] = [] 123 | dump1 [x] = [x] 124 | dump1 (x:xs) = x: [k | k <- dump1(xs), k /= x] 125 | ``` 126 | 127 | 128 | --删除与第一个元素值相同的值,包括第一个元素 129 | 130 | ```haskell 131 | dump2 :: (Eq a) => [a] -> [a] 132 | dump2 [] = [] 133 | dump2 [x] = [x] 134 | dump2 (x:xs) 135 | | [k | k <- xs, k==x] == [] = x:(dump2 xs) 136 | | otherwise = dump2[k | k <- (xs) , k /= x] 137 | ``` 138 | 139 | 140 | 141 | 142 | 143 | -------------------------------------------------------------------------------- /Articles/python实现弹幕雨(简化版).md: -------------------------------------------------------------------------------- 1 | 注意: 2 | 1,原文中41行的FONT_NAME,需要下载ttf字体包。若懒得下载,直接将源码中的FONT_NAME 改为None 也可以完美运行 3 | 2,本文使用pycharm工具,需导入pygame作为开发工具 4 | 5 | 6 | ---------- 7 | 最终效果(不会发动态图...) 8 | ![在这里插入图片描述](httpsimg-blog.csdnimg.cn2020022113074160.pngx-oss-process=imagewatermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2ExMzM1MjkxMjYzMg==,size_16,color_FFFFFF,t_70) 9 | 10 | ------------- 11 | 源代码: 12 | ```python 13 | import pygame 14 | import random 15 | from pygame.locals import 16 | from random import randint 17 | 18 | # 定义一些窗体参数及加载字体文件 19 | SCREEN_WIDTH = 900 # 窗体宽度 20 | SCREEN_HEIGHT = 600 # 窗体宽度 21 | LOW_SPEED = 4 # 字体移动最低速度 22 | HIGH_SPEED = 10 # 字体移动最快速度 23 | FONT_COLOR = (00, 150, 00) # 字体颜色 24 | FONT_SIZE = 5 # 字体尺寸 25 | FONT_NOM = 20 # 显示字体数量 从0开始 26 | FONT_NAME = calibrii.ttf # 注意字体的文件名必须与真实文件完全相同(注意ttf的大小写),且文件名不能是中文 27 | FREQUENCE = 10 # 时间频度 28 | times = 0 # 初始化时间 29 | 30 | 31 | # 定义随机参数 32 | def randomspeed() 33 | return randint(LOW_SPEED, HIGH_SPEED) 34 | 35 | 36 | def randomposition() 37 | return randint(0, SCREEN_WIDTH), randint(0, SCREEN_HEIGHT) 38 | 39 | 40 | def randomoname() 41 | return randint(0, 100000) 42 | 43 | 44 | def randomvalue() 45 | return randint(0, 100) # this is your own display number range 46 | 47 | 48 | # class of sprite 49 | class Word(pygame.sprite.Sprite) 50 | def __init__(self, bornposition) 51 | pygame.sprite.Sprite.__init__(self) 52 | self.value = randomvalue() 53 | self.font = pygame.font.Font(FONT_NAME, FONT_SIZE) 54 | self.image = self.font.render(str(self.value), True, FONT_COLOR) 55 | self.speed = randomspeed() 56 | self.rect = self.image.get_rect() 57 | self.rect.topleft = bornposition 58 | 59 | def update(self) 60 | self.rect = self.rect.move(0, self.speed) 61 | if self.rect.top SCREEN_HEIGHT 62 | self.kill() 63 | 64 | 65 | # init the available modules 66 | pygame.init() 67 | screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT)) 68 | pygame.display.set_caption(ViatorSun CodeRain) 69 | clock = pygame.time.Clock() 70 | group = pygame.sprite.Group() 71 | group_count = int(SCREEN_WIDTH FONT_NOM) 72 | 73 | # mainloop 74 | while True 75 | time = clock.tick(FREQUENCE) 76 | for event in pygame.event.get() 77 | if event.type == QUIT 78 | pygame.quit() 79 | exit() 80 | 81 | screen.fill((0, 0, 0)) 82 | for i in range(0, group_count) 83 | group.add(Word((i FONT_NOM, -FONT_NOM))) 84 | 85 | group.update() 86 | group.draw(screen) 87 | pygame.display.update() 88 | 89 | 90 | ``` 91 | 92 | 参考自:httpsblog.csdn.netViatorSunarticledetails82751273utm_source=app -------------------------------------------------------------------------------- /Articles/《C Prime Plus》读书笔记(14):各种特殊数据形式总结struct,union,enum.md: -------------------------------------------------------------------------------- 1 | 2 | - [一,struct结构](#一struct结构) 3 | - [1. 有关struct的声明](#1-有关struct的声明) 4 | - [1.1 结构模板名](#11-结构模板名) 5 | - [1.2 创建结构变量](#12-创建结构变量) 6 | - [1.3 与typedef的配合](#13-与typedef的配合) 7 | - [2. 有关struct的初始化](#2-有关struct的初始化) 8 | - [二,union联合](#二union联合) 9 | - [三,enum枚举](#三enum枚举) 10 | - [3.1 enum的语法](#31-enum的语法) 11 | - [3.2 enum中枚举符的赋值](#32-enum中枚举符的赋值) 12 | 13 | -------- 14 | # 一,struct结构 15 |
16 | 17 | ## 1. 有关struct的声明 18 | ### 1.1 结构模板名 19 | ```c 20 | struct { // 结构的模板(勾勒一个结构) 21 | int num; 22 | char arr[10]; 23 | }; 24 | ``` 25 | 26 | 27 | ```c 28 | struct book{ // book为结构模板的名称 --- 模板名 29 | int num; 30 | char arr[10]; 31 | } 32 | ``` 33 | ==结构的模板名可写可不写,一般在以下情况中会写出模板名:需要重复使用该结构本身时== 34 | 35 | ----- 36 | ### 1.2 创建结构变量 37 | ```c 38 | struct book{ 39 | int num; 40 | char arr[10]; 41 | }; 42 | 43 | struct book library; 44 | 45 | /* 等价于: */ 46 | 47 | struct book{ 48 | int num; 49 | char arr[10]; 50 | } library; 51 | 52 | /* 也等价于: */ 53 | 54 | struct{ int num;char arr[10];} library; // 如果无创建多个声明名的需要 55 | ``` 56 | 57 | ==`struct{ } ` 可以直接用作 一个类型 去使用== 58 | 59 | ---- 60 |

61 | 62 | ### 1.3 与typedef的配合 63 | 64 | ```c 65 | typedef struct book{ 66 | int num; 67 | char arr[10]; 68 | } LIBRARY; 69 | 70 | typedef struct { //声明名不重要 71 | int num; 72 | char arr[10]; 73 | } LIBRARY; 74 | 75 | ``` 76 | ==注意:此时花括号之后是typedef定义的struct别名,是一个类型名。区别`struct{ } xxx;` xxx为变量名== 77 | 78 | ------ 79 | 80 | ## 2. 有关struct的初始化 81 | 82 | 按顺序初始化 83 | ```c 84 | struct book library = {1, "《深入理解计算机系统》"}; 85 | ``` 86 | 指定成员初始化 87 | ```c 88 | struct book library = { 89 | .num = 1, 90 | .arr = "《深入理解计算机系统》" 91 | }; 92 | ``` 93 | ----- 94 |

95 | 96 | ------- 97 | 98 | # 二,union联合 99 | 100 | **union是多选一版的struct** 。struct 的变量将能同时包含有多个数据类型,union 的变量一次只能代表其中一种数据类型 101 | 102 | union类型,可以代表联合结构中声明的各种类型中的唯一一个类型 103 | union变量,可以存放联合结构中声明的各种类型中的唯一一个类型的变量(使用时,union变量必须调用其中某种类型的成员,union变量自身所属的类型将与该调用成员的数据类型一致) 104 | 105 | union的内存为联合声明中占用字节最大的类型的大小 106 | 107 | ```c 108 | union chooseOne{ 109 | int Int; 110 | char Char; 111 | }; 112 | 113 | union chooseOne Tom; 114 | Tom.Int = 1; // 相当于: int Tom = 1; 此时整个Tom联合结构中只有一个 1 115 | Tom,Int += 2; // 相当于int 116 | Tom.Char = 'A' // 相当于: char Tom = 'A'; 此时整个Tom联合结构中只有一个 ‘A’,原先的1被删除 117 | ``` 118 | 119 | ```c 120 | struct ownerPeople{ 121 | char peopleName[20]; 122 | int age; 123 | } 124 | struct ownerCompany{ 125 | char companyName[20]; 126 | char leader[20]; 127 | } 128 | union data{ 129 | struct ownerPeople peopleInfo; 130 | struct ownerCompany companyInfo; 131 | }; 132 | 133 | struct carData{ 134 | char carName[20] 135 | union data ownerInfo; 136 | }; 137 | 138 | ``` 139 | 也可写成匿名联合, 此时调用为 (carData benci): `benci.peopleInof;` 而不再是`benci.ownerInfo.peopleInfo;` (union变量名略过直接使用struct结构名调用) 140 | 141 | ```c 142 | struct carData{ 143 | char carName[20] 144 | union { 145 | struct ownerPeople peopleInfo; 146 | struct ownerCompany companyInfo; 147 | }; 148 | }; 149 | ``` 150 | 151 | 152 | ----- 153 |

154 | 155 | # 三,enum枚举 156 | ## 3.1 enum的语法 157 | **限定取值的整型数据类型, 且利用枚举符来表示整型数据**(更具有好的可读性) 158 | 枚举符本质上就是整型变量,类似于`#define 枚举符 赋予的值` 159 | ```c 160 | enum somecolor{red, orange, green}; // red/orange/green为枚举符 161 | enum somecolor color; 162 | ``` 163 | ## 3.2 enum中枚举符的赋值 164 | 165 | ```c 166 | enum somecolor{red, orange, green}; // 默认赋值 此时{red=0, orange=1, green=3}; 从(0/前一位赋值)+ 1开始 167 | enum somecolor{red, orange = 20, green}; // 特殊默认赋值 此时{red = 0, orange = 20, green = 21}; 168 | enum somecolor{red = 1, orange = 2, green = 3}; //分别赋值 169 | ``` 170 | 171 |
172 | 173 | ==typedef 和 #define 的区别 与 union 和 enum的区别类似 (一个针对类型,一个针对值)== 174 | 175 | 176 | -------------------------------------------------------------------------------- /Articles/不用公式学线代, 纯纯纯几何视角下的线性代数.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 观前提醒:文章前后关联性较强,后文都是在前文的几何概念上展开。建议顺序阅读 4 | 5 | - [什么是向量?](#什么是向量) 6 | - [三种视角看向量](#三种视角看向量) 7 | - [什么是线性组合](#什么是线性组合) 8 | - [线性组合的概念](#线性组合的概念) 9 | - [空间的概念](#空间的概念) 10 | - [线性相关的几何概念](#线性相关的几何概念) 11 | - [空间的基的定义](#空间的基的定义) 12 | - [什么是矩阵](#什么是矩阵) 13 | - [什么是线性变换](#什么是线性变换) 14 | - [线性变换的可视化理解](#线性变换的可视化理解) 15 | - [总结线性变换的几何本质:](#总结线性变换的几何本质) 16 | - [线性变换的表达式 --- 矩阵](#线性变换的表达式-----矩阵) 17 | - [什么是矩阵乘法](#什么是矩阵乘法) 18 | - [矩阵乘法的几何意义](#矩阵乘法的几何意义) 19 | - [矩阵乘法运算上的几何意义](#矩阵乘法运算上的几何意义) 20 | - [矩阵乘法的运算律的几何视角证明](#矩阵乘法的运算律的几何视角证明) 21 | - [无交换率 AB!=BA](#无交换率-abba) 22 | - [有结合律 (AB) C = A (BC)](#有结合律-ab-c--a-bc) 23 | - [什么是行列式](#什么是行列式) 24 | - [行列式的几何意义](#行列式的几何意义) 25 | - [行列式为0的特殊情况:](#行列式为0的特殊情况) 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 | 55 | 物理专业视角:向量是有方向的箭头 eg: -----> 56 | 57 | 计算机专业视角:向量是有序的数字列表 eg:[1, 2] 58 | 59 | 数学专业视角: 向量是任何东西!只要能保证其两个相加或与常数相乘是有意义的。eg:小松鼠是向量,松鼠+松鼠 = 松鼠宝宝;3 * 松鼠 = 三只松鼠 60 | 61 | > tips:我们将不断加深数学专业的视角上的向量理解,由于本篇着重讲述几何本质,我们可以用物理和计算机专业的视角去想象向量:向量是坐标系中的以原点为起点的有方向的箭头,其终点在坐标系的位置我们使用数字列表的形式表示出来(其实单个常数在线性代数中的主要作用就是用于缩放向量,例如坐标表示就是该数字缩放了对应基向量) 62 | 63 | 64 | 65 | ------------------------------- 66 | 67 | # 什么是线性组合 68 | 69 | ## 线性组合的概念 70 | >为方便叙述我们默认坐标系为二维坐标系,i为x轴基向量,j为y轴基向量 71 | 72 | 前面提到了向量表示,我们可以看作是向量坐标 **放缩了对应的基向量并相加** 73 | 74 | **两个数乘向量的和就称作两个向量的线性组合** 75 | 76 | 77 | 78 | 79 | 80 | 81 | ## 空间的概念 82 | 83 | 给定基向量可以组成的**所有线性组合的集合**称作给定向量**张成的空间**。 84 | 85 | 因此大部分二维向量们张成的空间就是所有二维向量的集合(二维空间),而共线的二维向量张成的空间就是落在一条线上的向量的集合( 一维空间 ) 86 | 87 | 88 | 89 | ## 线性相关的几何概念 90 | 91 | 线性相关和线性无关的判断的直接依据就是:**是否每个向量都给张成的空间增加了维度。** 92 | 93 | 向量不使张成空间增加维度 ---> 则向量在落在该张成空间中 ---> 张成空间是其他向量们所有线性组合的集合 ---> 向量可以被其他向量线性表示出来 ---> 该向量组是线性相关的 94 | 95 | 96 | 97 | ## 空间的基的定义 98 | 99 | 空间的一组基:就是张成该空间的线性无关向量的集合(每个决定该空间的维度的向量的集合) 100 | 101 | 102 | 103 | 104 | 105 | ------------------------------------------- 106 | 107 | # 什么是矩阵 108 | 109 | > 总结:线性变换是一种操纵空间的手段,它直观上使得坐标系网格保持平行且等距分布进行变换,且这个变换只需要通过几个数字的组合(变换后的基向量坐标)就可以表示出来,这个数字的组合就是矩阵(即矩阵表示了一种线性变换) 110 | 111 | ## 什么是线性变换 112 | 113 | **变换** 等价于 函数,函数大多是一个数经过函数的处理得到一个数,而线性变换是一个向量经过变换处理得到一个向量(变换是函数花哨的说法)(从一个向量变成另一个向量) 114 | 115 | **线性**限定了变换的范围,变换可以非常复杂,既然是线性代数那我们就只讨论线性的变换。变换满足下面两个性质,就是线性的: 116 | 117 | 1. 直线在变换后仍是直线,不可弯曲 118 | 119 | 2. 坐标原点必须固定不动(若直线仍为直线,但坐标原点移动则为仿射变换) 120 | 121 | 122 | ## 线性变换的可视化理解 123 | 124 | - 在充满网格的二维平面中,**变换可以被可视化理解**为: 125 | 坐标系网格发生改变,从代表某一空间的坐标系网格图,变换为另一空间的坐标系网格图(因为该空间的每一个向量都进行了变换(即每一个向量从一个向量变成另一个向量)等同于整个空间都被进行了变换(即从一个空间变成另一个空间)) 126 | 127 | 128 | 129 | - 在充满网格的二维平面中,**线性变换的两个性质可被可视化理解**为: 130 | 使得 **保持坐标系网格平行且等距分布** 的变换 131 | 132 | 133 | 134 | 135 | 136 | (线性变换需要保持网格平行很好理解,而理解为何要等距的平行,可以想象一条斜直线,若不等距变换会将其变成曲线) 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | ## 总结线性变换的几何本质: 147 | 148 | 线性变换使得代变某一空间的网格图按照保持坐标系网格平行且等距分布的原则变化 149 | 150 | 151 | 152 | ## 线性变换的表达式 --- 矩阵 153 | 154 | 首先我们由 “ 网格图按照保持坐标系网格平行且等距分布的原则变化” 可以得出一个重要推论: 155 | **向量关于基的线性组合在变换前后是不改变的**: v = -i + 2j / v ' = -i ' + 2j ' 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 因此变换后的向量可以表示为: 169 | 170 | ![微信图片_20200609005441.png](https://imgconvert.csdnimg.cn/aHR0cDovL3d3MS5zaW5haW1nLmNuL2xhcmdlLzAwNlAwOGxSZ3kxZ2ZsZGJtM3JneGozMGxlMDJvcTJ2LmpwZw?x-oss-process=image/format,png) 171 | 172 | 因此:因为向量在线性变换中的线性组合不变(即基向量的缩放比例不变),我们只需要记录下变换后的基向量,就可以像上面那样算出,变换后的基形成的新向量的坐标!因此我们可以通过**变换后的基向量组合就可以表示出这种线性变换** 而这个**变换后基向量的组合**就是我们说的 **矩阵** !(我们往往可以通过矩阵中新基向量大致判断出这是一个怎样的线性变换) 173 | 174 | 175 | 176 | 177 | 178 | 179 | 因此矩阵与向量相乘的几何意义就是:对该向量进行线性变换 180 | **(往往我们把向量中的数字看成是缩放基的标量)** 181 | 182 | 183 | 184 | 185 | --------------------- 186 | 187 | # 什么是矩阵乘法 188 | 189 | ## 矩阵乘法的几何意义 190 | 191 | 由上文可知,矩阵是一种线性变换,若矩阵乘变量则会对变量进行线性变换。而矩阵乘矩阵,其实就是对一个线性变换进行线性变换,即**线性变换的复合** (我们同样可以通过追踪基向量的变换来表示这种复合变换) 192 | 193 | 194 | 195 | 196 | 197 | (注意:矩阵乘法从右到左读,就像复合函数 f ( g(x) ) ) 198 | 199 | ## 矩阵乘法运算上的几何意义 200 | 201 | 矩阵乘矩阵,是对一个线性变换进行线性变换,即对前一个线性变化的基分别进行线性变化 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | ## 矩阵乘法的运算律的几何视角证明 216 | 217 | ### 无交换率 AB!=BA 218 | 219 | 易得矩阵乘法无交换律,因为易知线性变换的前后作用顺序不同造成的结果是不同的 220 | 221 | ### 有结合律 (AB) C = A (BC) 222 | 223 | (AB) C ---> C变换的基础上进行(AB)的复合变换,等价于C变换进行B变换再进行A变换(复合变换的几何意义) 224 | A (BC) ---> (BC)复合变换的基础上进行A变换,等价于C变换进行B变换再进行A变换(复合变换的几何意义) 225 | 226 | 因此二者都等价于 (ABC) ,即C变换先进行B变换再进行A变换 227 | 228 | ------------ 229 | 230 | # 什么是行列式 231 | 232 | ## 行列式的几何意义 233 | 234 | **行列式表示的是一个线性变换对空间的挤压拉伸程度** 235 | 236 | 237 | 矩阵的行列式的值 就是其代表的线性变换 对某一块空间(面积/体积)的 缩放比例 238 | 239 | 我们经常使用原基向量构成的1*1小方块作为基准来谈缩放比例,因为根据网格线平行且等距,1 *1小方块的缩放比例与其他所有特定的空间的缩放比例都相同 240 | 241 | 242 | 243 | 244 | 245 | 246 | ## 行列式为0的特殊情况: 247 | 248 | (将空间的缩放比例为0,即降维) 249 | 250 | 251 | 252 | 253 | 254 | ## 行列式为负数的情况: 255 | 256 | (基向量 i 和 j 的位置关系改变,空间的定向在线性变换中被改变,动态体现就是:空间在线性变换中转了个面) 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | (二维中:一般基向量 i 在 j 的右边,如图变换后 i 在 j的左边,位置关系变换,空间的定向变换) 267 | 268 | (三维中:空间的定向由右手法则判定) 269 | 270 | --------------- 271 | 272 | # 什么是逆矩阵 273 | 274 | ## 线性方程组 275 | 276 | 线性代数之所以在很多个领域都会应用的主要原因是:它可以解特定的方程组(线性方程组)(注意:线性方程组中的方程只允许出现数乘和相加的操作,类似x^2^,sinx等式子是不能出现的) 277 | 278 | 279 | 线性方程组的求解可以写成矩阵与向量相乘等于一个向量的新形式 280 | 281 | 282 | 283 | 284 | 285 | 这样一来其线性方程组的几何意义就是:常数矩阵A将未知数向量 **x**经过线性变换后,与常数向量 **v**重叠 286 | 287 | 288 | 289 | ## 秩与列空间 290 | 291 | 秩(rank) --- 描述线性变换后空间的维度大小。 292 | eg: det(A) = 0, 当rank = 1时,A矩阵将空间压缩为一维直线,而当rank = 2时,A 矩阵将空间压缩为二维平面 293 | 294 | 295 | 列空间 --- 矩阵的列空间是 矩阵所有可能的变换结果的集合(变为点,变为线,变为面等等) 296 | (之所以称之为“ 列空间”的原因:矩阵所有可能变换出的空间,其实就是其列(基向量)张成的空间) 297 | 298 | 299 | 因此秩更准确的定义是:列空间的维度 300 | 301 | 302 | 303 | ## 秩与零空间 304 | 305 | 当秩达到最大值时,意味着秩与列数相等,称为满秩 306 | 307 | 308 | 309 | 原点处的情况: 310 | 311 | 1. 满秩矩阵下: 312 | 由于线性变换中原点的位置不变,因此零向量在满秩矩阵的作用下仍位置不变,原点处只存在一个零向量 (满秩矩阵下唯一位置不变的向量) 313 | 314 | 2. 非满秩矩阵下: 315 | 一系列的向量在降维的变换中变为零向量。原点处可能压缩了一个直线的向量甚至可能压缩了一平面的向量! 316 | 经过矩阵变换后落在原点的向量构成矩阵的**零空间**或**核** 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | ## 线性方程组的求解---逆矩阵 326 | 327 | 使用 A**x** = **v**时有两种情况: 328 | 329 | 1. 当det(A)!= 0 , 即线性变换未将空间降维,此时只存在一个对应的**x**,方程只有一个解 330 | 331 | 这时在空间中只存在一个**x**我们可以通过**倒带**的方式由**v**找到**x**。 332 | 333 | 这里说的倒带,其实指的是一种线性变换 --- **逆矩阵** A^-1^ ,(A^-1^的核心是满足 A^-1^A = I) 334 | 335 | 此时**x**的解法为: A^-1^A**x** = A^-1^ **v** ---> **x** = A^-1^ **v** 336 | 337 | 2. 当det(A)= 0 , 即线性变换将空间降维,此时没有逆变换,但当向量**x**,**v**恰好同在降维上后的空间中时,那么解仍然存在 338 | 339 | 340 | 341 | 342 | 343 | 344 | - 还有一种特殊的情况,当**v** 为零向量时,几何意义就是:**x** 变换后落在了零向量原点上,此时 **x** 就是矩阵的零空间 345 | 346 | 347 | 348 | ---------------------------- 349 | 350 | # 什么是点积 351 | 352 | > 总结:向量的点乘中,向量对偶于一个高维到一维的线性变换 353 | > 354 | > 在向量1与向量2的点积中,向量1投影到向量2上,即有一个1*n降维矩阵使得向量1变换到向量2所在的直线上,而该矩阵的值恰为向量2的坐标值。故 矩阵1乘向量2 == 向量1点乘向量2 355 | 356 | ## 常见的点积几何意义解释: 357 | 358 | 点积是常用于解决向量指向和理解投影的有利几何工具 359 | 360 | **x** • **v** 指 **x**在**v**上的投影 与 **v** 的乘积 361 | (但是为什么点积会跟投影扯上关系呢 : ) 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | ## 将点积与线性变化相关联 374 | 375 | 376 | 377 | 378 | 379 | 380 | 381 | 如图:当且仅当原本图像上相互等距的一系列点,落到数轴上后也是等距的,多维到一维(一维数轴,上图为x轴)的变换是线性变换。 382 | 383 | ------------------------------------------- 384 | 385 | 现在解决 **矩阵值和向量值相同**, 接着往下思考: 386 | 387 | 1. 我们有**x** • **v** ,以**v** 所在的向量为我们降维变换后的数轴 388 | 389 | 390 | 391 | 392 | 393 | 2. 为了求出该降维变换的矩阵,我们还是从基向量入手根据对称性原则,**1*n矩阵的两元素 正是v 向量的坐标**! 394 | 395 | 396 | 397 | <-------> 398 | 399 | 400 | 401 | 402 | 403 | 404 | 3. 故点乘**x** • **v** ,就是以 **v向量坐标为矩阵元素的矩阵 对x 向量进行了线性变换(使x v共线)** ,在图像上表现为,x线性变换至v所在直线上,即投影,在数值上表现为a * c + b *d,即向量对应相乘 405 | 406 | 407 | 408 | 409 | 410 | 411 | ## 启示:对偶性 412 | 413 | **向量的点乘中,向量对偶于一个高维到一维的线性变换** 414 | 415 | ( 对偶性 :即一种出乎意料但又自然的对应关系) 416 | 417 | ---------------------------------------------------- 418 | 419 | 420 | 421 | # 什么是基变换 422 | 423 | > 核心在于:基的变换,就是通过矩阵进行的视角切换。 424 | 425 | ps: 下文用别人的基(非默认基)和自己的基(默认基)来区分两套不同坐标系的基。 426 | 427 | 428 | 429 | ## 将她的基表示的坐标转换成自己的基表示 430 | 431 | **用自己的视角去看她的视角下的坐标的表示,使用自己视角下她的基向量组成的矩阵对她的向量进行线性变换就好** 432 | 433 | 434 | 435 | 436 | 437 | 438 | 439 | **总结一下:通过自己的基表示她的基向量作为矩阵A,可以将 她的基表示的坐标翻译成自己的基表示的坐标** 440 | 441 | ## 将自己的基表示的坐标转换成她的基表示 442 | 443 | **用她的视角看自己的视角下的坐标的表示,将上面的程序反过来(通过A的逆矩阵A^-1^)对自己的向量进行线性变换就好** 444 | 445 | 446 | 447 | 448 | **总结: 通过A^-1^,可以将 自己的基表示的坐标 翻译成 她的基表示的坐标** 449 | 450 | ## 非自己的基的坐标系进行线性变换 451 | 452 | ### 矩阵的线性变换有作用范围 453 | 454 | 首先先来看看自己的基的线性变换。我们的矩阵追踪记录的都是自己基,因此**该矩阵只能对自己基的坐标系进行线性变换,而不能直接对别人的基坐标系进行线性变换** 455 | 456 | 457 | 458 | 459 | 460 | 461 | 462 | ### 视角的转化 463 | 464 | 465 | 466 | 467 | 468 | 469 | 470 | 471 | 472 | 注意:A^-1^MA 暗示着一种数学上的转移作用。M是你想进行的转移,而A,A^-1^则有视角转化的作用。矩阵的转换仍是同一种变换(只不过是转化了角度,是在其它基的坐标系上进行的转换) 473 | 474 | 475 | 476 | 477 | 478 | ------------------ 479 | 480 | 481 | 482 | # 什么是特征向量和特征值 483 | 484 | 在以上所有知识的基础上,我们着手解决这个大问题。 485 | 486 | 487 | 488 | ## 一种特殊的性质和特征向量 489 | 490 | 有些向量在经过线性变换后,它留在原来向量张成的空间里。即线性变换对它来说仅仅就是一种缩放。 491 | 492 | 493 | 494 | 有这样特殊性质的向量就是**特征向量** 495 | 496 | 而每一个特征向量被缩放的比例就是特征向量的**特征值** 497 | 498 | 499 | 500 | ## 特征向量的几何意义 501 | 502 | **特征向量就是旋转轴**!他能让你不过多依赖坐标系地去理解矩阵所代表的线性变换(若单单从基向量缩放去理解线性变换往往过度依赖坐标系) 503 | 504 | 505 | 506 | 507 | 508 | 509 | 510 | 511 | ## 特征向量中计算 512 | 513 | 514 | 515 | 516 | 计算时,将右边的 λ 常量化成 λ对角矩阵,使式子左右两边形式一致 517 | 即 A**v** = ( **λ**I )**v**, 形式转换后就有 (A - **λ**I )**v** = **0** 518 | 这样一来我们需要矩阵(A - **λ**I ) 能将 **v**压缩至原点(零空间),故需要由det((A - **λ**I )) = 0来求出**λ**,后求出满足条件的**v** 519 | 520 | 可能出现的情况 : 521 | 522 | 1. 无特征值。如90°翻转 523 | 2. 单个特征值单个特征向量。如剪切变换 524 | 3. 单个特征值多个特征向量。如 坐标系全体倍增两倍变换 525 | 4. 多个特征值多个特征向量 526 | 527 | ## 特征基 528 | 529 | 当基向量为特征向量时称之为特征基(即基仅在原有的方向上进行缩放) 530 | 531 | 含特征基的线性变换,矩阵表示出来就是一个对角矩阵,矩阵的对角元是特征值。 532 | 换句话说:对角矩阵表示的是含特征基的线性变换 533 | 534 | 535 | 536 | 537 | 选用特征基构成的对角矩阵在计算时有极大的优势: 538 | 539 | 540 | 541 | 542 | 543 | 544 | 545 | ## 构成含特征基的线性变换 546 | 547 | 而当你有**多个特征向量**时,将原来的基转换为以特征向量为基,那么线性变换就成为了含特征基的变换。 548 | 549 | **因此为了使得线性变换称为含特征基的线性变换**,我们使用基的A^-1^MA转换式中,易知最后的结果一定是个对角矩阵 550 | 551 | 552 | 553 | ----------- 554 | 555 | 参考资料: 556 | - 代数学引论(第1/2卷).(俄罗斯)柯斯特利金 557 | - [youtube] 3Bule1Brown视频资料 558 | -------------------------------------------------------------------------------- /Articles/写给github新人,如何下载并运行一个Github项目.md: -------------------------------------------------------------------------------- 1 | - [【写在前面】](#写在前面) 2 | - [【项目有关】](#项目有关) 3 | - [【工具与资源】](#工具与资源) 4 | - [【运行步骤】](#运行步骤) 5 | 6 | ------------------- 7 | # 【写在前面】 8 | 有时候对于开源项目来说能不能在自己电脑上跑起来, 直接决定了你有没有心情消化这些开源代码💢。很久以前就有过好几次阅读github开源项目的想法,但是由于有限的英文水平,有限的国内网络,和复杂庞大的代码,每次都是连代码都运行不了😥,看着一大片报错自然生不出读源码的念想,好几次被劝退。 9 | 因此这篇文章写给想要入坑github的新人们,帮助他们成功运行出第一个项目,获得入门的成就感 10 | 11 | # 【项目有关】 12 | halo,基于H2数据库的个人独立博客系统(可能是因为H2不需要单独安装,而MySQL得额外配置),习惯写博客的同学可以把这个博客作为私人笔记本甚至是私人日记本 13 | 14 | # 【工具与资源】 15 | GitHub项目源码:https://github.com/halo-dev/halo 16 | 开发工具:IntelliJ IDEA 17 | 相关库与包与依赖:太多了...使用idea可以自动导入 18 | 19 | # 【运行步骤】 20 | **1**,登录github,尽量连接v/p/n,没有账号则进行注册 21 | 22 | **2**,gihub界面左上角搜索 halo,而后选择最高星的首个项目 23 | tip:这里有一个高级搜索的技巧:使用关键字 "in:description 关键词" + “star:>星数” 可以精准地搜索 24 | 25 | 26 | ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200329161938752.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2ExMzM1MjkxMjYzMg==,size_16,color_FFFFFF,t_70) 27 | ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200329162001765.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2ExMzM1MjkxMjYzMg==,size_16,color_FFFFFF,t_70) 28 | 29 | **3**, 进入项目源码后,粗略地阅读代码文件,查看其项目结构和项目管理工具 30 | 由倒数第4个文件bulid.gradle可以得知,halo系统是基于gradle管理的,其他项目管理工具还有xml 31 | 32 | ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200329162018942.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2ExMzM1MjkxMjYzMg==,size_16,color_FFFFFF,t_70) 33 | 34 | 35 | **4**, 克隆源码 36 | 第一种方式:打开git命令行,输入:git clone https://github.com/halo-dev/halo.git 37 | 第二种方式:点击Download Zip,下载压缩包后解压 38 | 39 | 40 | ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200329162053223.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2ExMzM1MjkxMjYzMg==,size_16,color_FFFFFF,t_70) 41 | 成功下载的最终项目文件: 42 | ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200329162059999.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2ExMzM1MjkxMjYzMg==,size_16,color_FFFFFF,t_70) 43 | 44 | **5**,打开idea,点击import project,输入项目文件的地址,再选择gradle启动(由第三步我们已经知道代码是基于gradle管理的)等待项目导入(第一次导入过程较慢) 45 | ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200329162316338.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2ExMzM1MjkxMjYzMg==,size_16,color_FFFFFF,t_70) 46 | ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200329163558459.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2ExMzM1MjkxMjYzMg==,size_16,color_FFFFFF,t_70) 47 | 导入成功 48 | ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200329162125443.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2ExMzM1MjkxMjYzMg==,size_16,color_FFFFFF,t_70) 49 | 50 | **6**,导入成功后点击右上角application(绿色箭头),启动项目,启动时间长短与电脑配置好坏相关 51 | 52 | tip:若绿色箭头呈灰色无法点击 解决方案:右侧栏gradle ==》 Tasks ==》 application ==》 bootRun 53 | 54 | ![在这里插入图片描述](https://img-blog.csdnimg.cn/2020032916242883.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2ExMzM1MjkxMjYzMg==,size_16,color_FFFFFF,t_70) 55 | 56 | **7**, 编译成功后,找到网址 ,在浏览器输入网址就大功告成了 57 | tip:网址1:是供其他用户观看的网址。 网址2:是供自己(admin)管理博客的网址 58 | 59 | ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200329162406748.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2ExMzM1MjkxMjYzMg==,size_16,color_FFFFFF,t_70) 60 | 61 | 62 | 63 | ------------ 64 | **8**,我的报错与解决方案: 65 | 66 | 报错:打开网址后显示404![在这里插入图片描述](https://img-blog.csdnimg.cn/20200329162648868.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2ExMzM1MjkxMjYzMg==,size_16,color_FFFFFF,t_70) 67 | bug位置:anatole子文件未成功下载导入 68 | ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200329162636232.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2ExMzM1MjkxMjYzMg==,size_16,color_FFFFFF,t_70) 69 | 解决方案:使用gitzip for githup(chrome插件) 或者 DownGit在原网站下载该文件后导入,这些工具可以指定只下载单个文件 70 | ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200329163726353.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2ExMzM1MjkxMjYzMg==,size_16,color_FFFFFF,t_70) 71 | 72 | --------- 73 | 【运行后展示】 74 | ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200329163001268.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2ExMzM1MjkxMjYzMg==,size_16,color_FFFFFF,t_70)![在这里插入图片描述](https://img-blog.csdnimg.cn/20200329162953913.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2ExMzM1MjkxMjYzMg==,size_16,color_FFFFFF,t_70) 75 | 76 | ------- 77 | 祝各位入坑愉快。 -------------------------------------------------------------------------------- /Articles/字符串到底是什么?.md: -------------------------------------------------------------------------------- 1 | - [字符串的本质](#字符串的本质) 2 | - [字符串常量相关](#字符串常量相关) 3 | - [字符串数组和初始化](#字符串数组和初始化) 4 | # 字符串的本质 5 | ```c 6 | // 探究一个字符串由什么构成 7 | #include 8 | 9 | 10 | int main(){ 11 | char arr[50] = "asdasdasdasdasdasd"; 12 | printf("以%c打印整个字符串数组"); 13 | for(int i = 0; i < 50; i++)printf("%c ", arr[i]); 14 | printf("\n"); 15 | printf("以%d打印整个字符串数组"); 16 | for(int i = 0; i < 50; i++)printf("%d ", arr[i]); 17 | return 0; 18 | } 19 | ``` 20 | ![在这里插入图片描述](https://img-blog.csdnimg.cn/20201008000003892.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2ExMzM1MjkxMjYzMg==,size_16,color_FFFFFF,t_70#pic_center) 21 | 由上面可以看出: 22 | ==字符串包含字符串常量和末尾加入的空字符\0们== 23 | 24 | 1.这里的0实际上是char形式的空字符\0而非数字字符0,第一个\0是编译器自动添加的,之后的\0是故char数组默认初始化而出的 25 | 2.故为了保证让编译器自动添加空字符'\0',数组开辟空间时大小必须≥ (字符数量+1) 。如果未添加空字符\0,那么这个char数组便仅仅是**字符数组**而非**字符串数组** 26 | 27 | 28 | - 字符串数组 = 字符数组 + 空字符'\0' 29 | - 字符串 = 字符常量 + 空字符'\0' 30 | 31 | 32 | ----- 33 | 34 |
35 | 36 | # 字符串常量相关 37 | 双括号中的内容称为字符串字面量, 也叫做**字符串常量**。故上文黄字可写为: 38 | 39 | 40 | 41 | 字符串常量可以看作是一个不会改变的变量,它是静态储存的(注意!字符串常量储存在数据段,是静态储存!) 42 | 43 | 我们把字符串常量作为指向该字符串储存位置的指针(类似把数组名作为指向数组储存位置指针) 44 | 45 | ```c 46 | // 将字符串常量作为存放了字符串地址的指针进行操作 47 | int main(){ 48 | char arr[50] = "asdasdasdasdasdasda"; 49 | 50 | printf("%c, %s, %p", *"asdasdasdasdasdasda", "asdasdasdasdasdasda", "asdasdasd"); 51 | return 0; 52 | 53 | // 结果为 a, "asdasdasdasdasdasda", 0x100000f61 54 | } 55 | 56 | ``` 57 | 58 | ----- 59 | 60 |
61 | 62 | # 字符串数组和初始化 63 | 64 | 字符串数组的构建需要编译器区自动添加一个\0,因此我们需要用特殊的初始化方法来让编译器知道你初始化的是一个字符数组还是字符串数组。 65 | 66 | ==字符串的初始化同数组的初始化,只不过都是通过字符常量来赋值。== 67 | 68 | 69 | >```c 70 | >int main(){ 71 | > char arr1[8] = "i am sad"; 72 | > char arr2[8] = {'i',' ', 'a','m', 's', 'a', 'd','\0'}; 73 | > char arr3[7] = {'i',' ', 'a','m', 's', 'a', 'd'}; 74 | > /*当然也可以不提前声明数组的大小,编译器会同数组一样自动分配该字符串的大小*/ 75 | > char arr4[] = "i am sad"; 76 | > /*使用指针*/ 77 | > char *arr5 = "i am sad"; 78 | >} 79 | >``` 80 | >arr1的初始化等效于arr2的初始化,它们都是字符串数组,而arr3只是一个普通的字符数组 81 | 82 | 83 | ------ 84 | 85 |
86 | 87 | 个人有个小问题: 88 | 若char数组末尾是默认初始化为\0,而不是编译器自动添加的\0,此时的char数组时字符串数组吗? 89 | (实际结构一模一样的话应该就是了吧(大雾)...) 90 | 91 | ```c 92 | ```c 93 | int main(){ 94 | char arr2[8] = {'i',' ', 'a','m', 's', 'a', 'd','\0'}; 95 | char arr2[8] = {'i',' ', 'a','m', 's', 'a', 'd'}; // 问:默认初始化为\0而不是编译器自动添加的\0,此时的char数组时字符串数组吗 96 | } 97 | ``` 98 | -------------------------------------------------------------------------------- /Articles/数据结构(严蔚敏)读书笔记 (1)---绪论.md: -------------------------------------------------------------------------------- 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 | ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200926104302980.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2ExMzM1MjkxMjYzMg==,size_18,color_FFFFFF,t_70#pic_center) 27 | 28 | 29 |

30 | 31 | ## 数据结构 32 | ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200926101353895.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2ExMzM1MjkxMjYzMg==,size_16,color_FFFFFF,t_70#pic_center) 33 |

34 | ## 数据类型 35 | || 类型暗含了数据的 **“取值范围,储存方式”** 和 **“允许的操作”** 36 | 37 | || 数据类型就是 **值的集合**(数据项的集合 / 数据元素 ) 和 这些值上的**一组操作** 的总称 38 | 带操作的数据对象 = 数据类型 (成员函数 + 成员变量 = 类) 39 | 40 | --------------- 41 | 42 | 43 |


44 | # 算法 45 |
46 | 47 | ## 算法的定义和特性 48 | || 算法的定义:是解决某个问题的有限长的操作序列 49 | 50 | || 五个特性:有穷性,确定性,可行性,输入,输出 51 | 52 | ---> 算法判定:先有: 正确性,高效性 / 后有: 可读性,健壮性 53 | 54 |
55 | 56 | ## 算法的时间复杂度 57 | 58 | || 影响时间的因素:问题规模,语句频率,最好最坏情况 59 | 60 | || 取**问题规模n**的代表**执行次数的函数f(n)** 的 **同阶无穷大函数 大O** 来表示 算法的时间复杂度 61 | tip: 与问题规模n无关的for循环,仅代表次数,不影响大O复杂度 62 | 63 |
64 | 65 | ## 算法的空间复杂度 66 | ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200926103557563.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2ExMzM1MjkxMjYzMg==,size_16,color_FFFFFF,t_70#pic_center) 67 | 68 | -------------------------------------------------------------------------------- /Articles/数据结构(严蔚敏)读书笔记 (2)---线性表.md: -------------------------------------------------------------------------------- 1 | - [顺序表](#顺序表) 2 | - [链表](#链表) 3 | - [双向表](#双向表) 4 | 5 | ------------ 6 |
7 |
8 | 9 | # 顺序表 10 | 11 | ```cpp 12 | #include 13 | #include 14 | using namespace std; 15 | 16 | #define OK 1 17 | #define ERROR 0 18 | #define MAX 1000 19 | typedef int ElemType; 20 | 21 | typedef struct{ 22 | ElemType *elem; 23 | int length; 24 | }SqList; 25 | 26 | 27 | int InitList(SqList &L){ 28 | L.elem = new ElemType[MAX]; 29 | if(!L.elem) exit(EOVERFLOW); // 分配内存失败 30 | 31 | L.length = 0; 32 | return OK; 33 | } 34 | 35 | int GetElem(SqList L, int i, ElemType &e){ // 注意这里直接传递了引用 36 | 37 | if(i < 1 || i > L.length) return ERROR; 38 | 39 | e = L.elem[i - 1]; return OK; 40 | } 41 | 42 | int LocateElem(SqList L, ElemType e){ 43 | for(int i = 0; i < L.length - 1; i++){ 44 | if(L.elem[i] = e) return i+1; 45 | } 46 | return 0; 47 | } 48 | 49 | int ListInsert(SqList &L, int i, ElemType e){ 50 | if(i < 1 || i > L.length) return ERROR; 51 | if(L.length == MAX) return ERROR; 52 | 53 | for(int j = L.length - 1; j > i - 1; j--){ 54 | L.elem[j + 1] = L.elem[j]; 55 | } 56 | 57 | L.elem[i - 1] = e; 58 | L.length++; 59 | 60 | return OK; 61 | } 62 | 63 | int DeleteList(SqList &L, int i){ 64 | if(i < 1 || i > L.length) return ERROR; 65 | if(L.length == 0) return ERROR; 66 | 67 | 68 | for(int j = i - 1; j < L.length - 2; j++){ 69 | L.elem[j] = L.elem[j + 1]; 70 | } 71 | 72 | L.length--; 73 | 74 | return OK; 75 | 76 | 77 | } 78 | 79 | 80 | int main(int argc, char*argv[]){ 81 | return 0; 82 | } 83 | ``` 84 | 85 |
86 |
87 | 88 | 89 | # 链表 90 | 91 | ```cpp 92 | #include 93 | using namespace std; 94 | 95 | #define OK 1 96 | #define ERROR 0 97 | #define MAX 1000 98 | typedef int ElemType; 99 | 100 | typedef struct LNode{ 101 | ElemType data; 102 | LNode *next; 103 | }LNode, *LinkList; 104 | 105 | int InitList(LinkList &L){ 106 | L = new LNode; 107 | L -> next = NULL; 108 | 109 | return OK; 110 | } 111 | 112 | int GetElem(LinkList L, int i, ElemType &e){ 113 | LinkList p = L -> next; int j = i; 114 | 115 | while(p && j < i){ 116 | p = p -> next; 117 | j++; 118 | } 119 | if(!p | j > i) return ERROR; 120 | 121 | e = p -> data; 122 | 123 | return OK; 124 | 125 | } 126 | 127 | LNode* LocateElem(LinkList L, ElemType e){ 128 | LinkList p = L -> next; 129 | int i = 1; 130 | while(p && p -> data != e){ 131 | p = p -> next; 132 | } 133 | if(!p) return ERROR; 134 | return p; 135 | } 136 | 137 | 138 | int InsertList(LinkList &L, int i, ElemType e){ 139 | LinkList p = L -> next; int j = 0; 140 | while(p && (j < i - 1)){ // p是被插入节点的前一个节点 141 | p = p -> next; 142 | j++; 143 | } 144 | 145 | if(!p || (j > i - 1)) return ERROR; 146 | 147 | LNode *s = new LNode; // // 注意new返回的是指针! 148 | s->data = e; 149 | s->next = p -> next; 150 | p->next = s; 151 | return OK; 152 | } 153 | 154 | int DeleteList(LinkList &L, int i){ 155 | int j = 0; LinkList p = L -> next; 156 | 157 | while((p->next) && (j < i - 1) ){ // p是被删节点的前一个节点 158 | p = p -> next; j++; 159 | } 160 | 161 | if(!p || j > i - 1) return ERROR; 162 | LNode* q = p -> next; 163 | p -> next = q -> next; 164 | delete q; 165 | return OK; 166 | } 167 | 168 | 169 | 170 | int main(int argc, char*argv[]){ 171 | 172 | return 0; 173 | } 174 | ``` 175 | 176 |
177 |
178 | 179 | 180 | 181 | # 双向表 182 | 183 | ```cpp 184 | #include 185 | #include 186 | #include 187 | using namespace std; 188 | 189 | #define OK 1 190 | #define ERROR 0 191 | #define MAX 1000 192 | typedef int ElemType; 193 | 194 | typedef struct DuLNode{ 195 | ElemType data; 196 | struct DuLNode *prior; 197 | struct DuLNode *next; 198 | }DuLNode, *DuLinkList; 199 | 200 | 201 | DuLNode* GetElem_DuL(DuLinkList &L, int i){ 202 | DuLinkList p = L; int j = 0; 203 | while(p || (j < i)){ 204 | p = p->next; 205 | j++; 206 | } 207 | if(!p || (j > i)) return ERROR; 208 | 209 | return p; 210 | } 211 | 212 | int InitDuLinkList(){ 213 | DuLinkList L = new DuLNode; 214 | L->next = NULL; 215 | L->prior = NULL; 216 | return OK; 217 | } 218 | 219 | int InsertDuLinkList(DuLinkList &L, int i, ElemType e){ 220 | DuLNode* p= GetElem_DuL(L, i); 221 | if(!(p)) return ERROR; 222 | DuLNode* s = new DuLNode; 223 | s->data = e; s->prior = p->prior; p->prior->next = s; 224 | s->next = p; p->prior = s; 225 | 226 | return OK; 227 | } 228 | 229 | 230 | int DeleteDuLinkList(DuLinkList &L, int i){ 231 | DuLNode* p= GetElem_DuL(L, i); 232 | if(!(p)) return ERROR; 233 | 234 | p->prior->next = p->next; 235 | p->next->prior = p->prior; 236 | 237 | delete p; 238 | 239 | return OK; 240 | } 241 | 242 | 243 | 244 | int main(int argc, char*argv[]){ 245 | return 0; 246 | } 247 | ``` 248 |
249 |
250 | 251 | ------- 252 | -------------------------------------------------------------------------------- /Articles/数据结构(严蔚敏)读书笔记 (3)---栈和队列.md: -------------------------------------------------------------------------------- 1 | @[toc] 2 | 3 |

4 | # 顺序栈 5 | 6 | ```cpp 7 | #include 8 | #include 9 | #include 10 | using namespace std; 11 | 12 | #define OK 1 13 | #define ERROR 0 14 | #define MAX 1000 15 | typedef int ElemType; 16 | 17 | typedef struct { 18 | ElemType *base; 19 | ElemType *top; 20 | int stacksize; 21 | }SqStack; 22 | 23 | int InitStack(SqStack &s){ 24 | s.base = new ElemType[MAX]; 25 | if(!s.base) exit(EOVERFLOW); 26 | s.top = s.base; 27 | s.stacksize = MAX; 28 | 29 | return OK; 30 | } 31 | 32 | int Push(SqStack &s, ElemType e){ 33 | if(s.top - s.base == s.stacksize) return ERROR; 34 | *s.top = e; 35 | s.top++; 36 | return OK; 37 | } 38 | 39 | int Pop(SqStack &s, ElemType &e){ 40 | if(s.top == s.base) return ERROR; 41 | e = *--s.top; 42 | return OK; 43 | } 44 | 45 | int GetTop(SqStack s){ 46 | if(s.top == s.base) return ERROR; 47 | return *(s.top - 1); 48 | 49 | 50 | 51 | } 52 | 53 | 54 | int main(int argc, char*argv[]){ 55 | 56 | 57 | return 0; 58 | } 59 | ``` 60 | 61 |
62 |
63 | 64 | 65 | # 链栈 66 | 67 | ```cpp 68 | #include 69 | #include 70 | #include 71 | using namespace std; 72 | 73 | #define OK 1 74 | #define ERROR 0 75 | #define MAX 1000 76 | typedef int ElemType; 77 | 78 | typedef struct StackNode{ 79 | ElemType data; 80 | struct StackNode *next; 81 | }Stack, *LinkStack; 82 | 83 | int InitStack(LinkStack &s){ 84 | s = new StackNode; 85 | s = NULL; //?????????? 86 | return OK; 87 | 88 | } 89 | 90 | int Push(LinkStack &s, ElemType e){ 91 | StackNode* p = new StackNode; 92 | p->data = e; 93 | p->next = s; 94 | s = p; 95 | return OK; 96 | 97 | } 98 | 99 | int Pop(LinkStack &s, ElemType &e){ 100 | if(s == NULL) return ERROR; 101 | e = s->data; 102 | StackNode* p = s; 103 | s = s->next; 104 | delete p; 105 | return OK; 106 | 107 | 108 | } 109 | 110 | ElemType GetTop(LinkStack s){ 111 | if(s == NULL) return ERROR; 112 | 113 | 114 | return s->data;; 115 | } 116 | 117 | 118 | int main(int argc, char*argv[]){ 119 | return 0; 120 | } 121 | ``` 122 |

123 | # 有关递归 124 | || 高级语言编制的程序中, 调用函数和被调用函数之间的链接及信息交换需通过栈来进行。 125 | 126 | || 当有多个函数构成嵌套调用时, 按照 “后调用先返回" 的原则, 上述函数之间的信息传递和控制转移必须通过 "栈 ” 来实现, 即系统将整个程序运行时所需的数据空间安排在一个栈中,每当调用一个函数时,就为它在栈顶分配一个存储区,每当从一个函数退出时,就释放它的存储区,则当前正运行的函数的数据区必在栈顶。 127 | 128 |

129 | 130 | 131 | 132 | # 顺序队列(循环队列) 133 | || 初始化创建空队列时,令 front = rear = 0 , 每当插入新的队列尾元素时,尾指针 rear增1; 每当删除队列头元素时, 头指针 front增1。因此,在非空队列中,头指针始终指向队列头元素,而尾指针始终指向队列尾元素的下一个位置 134 | **当把rear顶到最上方时,,队列无法再入队,处于“假溢出”的状态,我们采用循环的方式,通过 “模” 运算,Q.rear = (Q.rear + 1)%6, 把rear重置到下方。** 135 | 136 | 此时 137 | - 队空的条件: Q.front = Q.rear 138 | - 队满的条件: (Q rear+ 1)%M心CQSIZE = Q.front 139 | 140 | ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200927214200127.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2ExMzM1MjkxMjYzMg==,size_16,color_FFFFFF,t_70#pic_center) 141 | ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200927214302673.png#pic_center) 142 | 143 | ```cpp 144 | #include 145 | #include 146 | using namespace std; 147 | 148 | #define OK 1 149 | #define ERROR 0 150 | #define MAX 1000 151 | typedef int ElemType; 152 | 153 | typedef struct{ 154 | ElemType *base; 155 | int front; // 头指针 156 | int rear; // 尾指针 157 | }SqQueue; 158 | 159 | 160 | int InitQueue(SqQueue &q){ 161 | q.base = new ElemType[MAX]; 162 | if(!q.base) exit(EOVERFLOW); 163 | q.front = q.rear = 0; 164 | return OK; 165 | } 166 | 167 | int QueueLength(SqQueue Q){ 168 | return (Q.rear - Q.front + MAX) % MAX; 169 | } 170 | 171 | int EnQueue(SqQueue &Q, ElemType e){ 172 | if((Q.rear + 1) % MAX == Q.front) return ERROR; 173 | Q.base[Q.rear] = e; 174 | Q.rear = (Q.rear + 1) % MAX; 175 | 176 | return OK; 177 | } 178 | 179 | int DeQueue(SqQueue &Q, ElemType &e){ 180 | if(Q.front == Q.rear) return ERROR; 181 | e = Q.base[Q.front]; 182 | Q.front = (Q.front + 1) % MAX; 183 | return OK; 184 | 185 | } 186 | 187 | 188 | ElemType GetHead(SqQueue Q){ 189 | if(Q.front == Q.rear) return ERROR; 190 | return Q.base[Q.front]; 191 | } 192 | 193 | 194 | int main(int argc, char*argv[]){ 195 | 196 | return 0; 197 | } 198 | 199 | ``` 200 | 201 | # 链队 202 | 203 | ```cpp 204 | #include 205 | #include 206 | using namespace std; 207 | 208 | #define OK 1 209 | #define ERROR 0 210 | #define MAX 1000 211 | typedef int ElemType; 212 | 213 | typedef struct { // 头尾两个特殊指针即可以表示链队列 214 | QueuePtr front; // 队头指针 215 | QueuePtr rear; // 队尾指针 216 | }LinkQueue; 217 | 218 | int InitQueue(LinkQueue &q){ 219 | q.front = q.rear = new QNode; // 头节点 220 | 221 | q.front->next = NULL; // 头指针的头节点指向NULL 222 | return OK; 223 | } 224 | 225 | 226 | 227 | 228 | 229 | int InitQueue(LinkQueue &q){ 230 | q.front = q.rear = new QNode; // 澶磋妭鐐? 231 | 232 | q.front->next = NULL; // 澶存寚閽堢殑澶磋妭鐐规寚鍚慛ULL 233 | return OK; 234 | } 235 | 236 | int EnQueue(LinkQueue &q, ElemType e){ 237 | QNode* a = new QNode; 238 | a->data = e; 239 | //a->next = q.rear; 240 | a->next=NULL; q.rear->next = a; 241 | q.rear = a; 242 | 243 | return OK; 244 | 245 | } 246 | 247 | 248 | int DeQueue(LinkQueue &Q, ElemType &e){ 249 | if(Q.front == Q.rear) return ERROR; 250 | 251 | QNode* p = Q.front->next; // 头节点后的首元节点 252 | e = Q.front->data; 253 | Q.front->next = Q.front->next->next; 254 | if(Q.rear==Q.front->next) Q.rear=Q.front; // 注意最后一个元素被删除时要>将对为指针指向头节点 255 | delete p; 256 | return OK; 257 | 258 | 259 | } 260 | 261 | 262 | ElemType GetHead(LinkQueue Q){ 263 | if(Q.front != Q.rear) 264 | return Q.front->next->data; 265 | return ERROR; 266 | } 267 | 268 | int main(int argc, char*argv[]){ 269 | 270 | return 0; 271 | } 272 | ``` 273 | -------------------------------------------------------------------------------- /Articles/数据结构(严蔚敏)读书笔记(4)---串(KMP).md: -------------------------------------------------------------------------------- 1 | - [一,串](#一串) 2 | - [二,串的模式匹配算法 - KMP](#二串的模式匹配算法---kmp) 3 | - [1.什么是KMP](#1什么是kmp) 4 | - [2.为什么可以移位?](#2为什么可以移位) 5 | - [1.从公式推导来说](#1从公式推导来说) 6 | - [2.从直观来说](#2从直观来说) 7 | - [3.对移位规则的实现 --- Next[]](#3对移位规则的实现-----next) 8 | - [4.【一句话总结】在计算机中的实现KMP的流程](#4一句话总结在计算机中的实现kmp的流程) 9 | - [font color=red1.KMP实现: i,j位比较,相等时S,T同进位,相异时T移位进行前缀匹配](#font-colorred1kmp实现-ij位比较相等时st同进位相异时t移位进行前缀匹配) 10 | - [font color=red2.构建Next[]:找Next[j+1],就是看能否扩充T[1, j]中的子前缀](#font-colorred2构建next找nextj1就是看能否扩充t1-j中的子前缀) 11 | - [5.具体代码实现和解释](#5具体代码实现和解释) 12 | - [附:修正后的Next代码](#附修正后的next代码) 13 | 14 | 15 | # 一,串 16 | 串(字符串) 是特殊的线性表,唯一的区别在于串的数据对象约束为字符集 17 | 18 | 串的储存结构 19 | 20 | ```cpp 21 | -------------串的定长顺序储存结构------ 22 | #define MAXLEN 255 23 | typedef struct{ 24 | char ch[MAXLEN + 1] 25 | int length; 26 | }String; 27 | 28 | C语言中的“堆”,可以动态分配一块实际串长所需的储存空间,若分配成功返回初始地址指针,若失败返回NULL 29 | ------------串的堆式储存结构------- 30 | typedef struct{ 31 | char ch; 32 | int length; 33 | } 34 | 35 | ------------串的链式储存结构------- 36 | #define CHUNKSIZE 80 37 | typedef struct Chunk{ 38 | char ch[CHUNKSIZE]; 39 | struct Chunk next; 40 | }Chunk; 41 | typedef struct{ 42 | Chunk head, tail; 43 | int length; 44 | }LinkString; 45 | ``` 46 | 47 | # 二,串的模式匹配算法 - KMP 48 | ## 1.什么是KMP 49 | KMP是利用最大公共子串进行移位匹配的匹配算法。在失配时固定主串指针i (i无需回溯),依据Next[]将模式串向后移动与匹配指针对齐 50 | 51 | 对比朴素暴力匹配法O(nm),KPM匹配更高效O(n+m) 52 | 53 | 54 | 55 | 56 | 实现过程: 57 | ![在这里插入图片描述](httpsimg-blog.csdnimg.cn20200928145916596.gif#pic_center) 58 | brbr 59 | 60 | ------- 61 | ## 2.为什么可以移位? 62 | 63 | 64 | ### 1.从公式推导来说 65 | 66 | 67 | ![在这里插入图片描述](httpsimg-blog.csdnimg.cn20200928134405124.pngx-oss-process=imagewatermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2ExMzM1MjkxMjYzMg==,size_16,color_FFFFFF,t_70#pic_center) 68 | brbr 69 | 70 | ### 2.从直观来说 71 | 72 | 为了方便叙述,声明了几个名词 73 | 把模板T在指针j之前字符构成的子串,姑且先称之为 “已配对模板子串”,把已配对模板子串的开头前k-1项,和j前k-1项,称为模板j前子串的“前缀”和“后缀” 74 | 75 | 已知主串Si的前x项已经和“已配对模板子串”完全相等, 在第i项时Tj与Si相异, 现在考虑移位问题。 76 | 77 | 既然i前面部分已完全相等,Si的前x项中每个位置都已经和“已配对模板子串”的对应位置一一对应了(此时“已配对模板子串”的“前后缀”,也是Si前的前x项的前后缀 ),如果一个一个移位的话大多情况下都是在“已配对模板子串”开头部分就已经无法对应,但是有一种特殊情况除外 --- 当“前缀”等于“后缀” 时,将“已配对模板子串”的“前缀” 直接 移到主串S的“后缀”对应位置,以此达到了快速移位,减少无意义匹配的目的 78 | 79 | brbr 80 | 81 | ------- 82 | ## 3.对移位规则的实现 --- Next[] 83 | 84 | font color = red模式T的移位是为了前后缀匹配 85 | 86 | ![在这里插入图片描述](httpsimg-blog.csdnimg.cn20200928142331942.pngx-oss-process=imagewatermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2ExMzM1MjkxMjYzMg==,size_16,color_FFFFFF,t_70#pic_center) 87 | 88 | brbr 89 | 90 | ------- 91 | 92 | ## 4.【一句话总结】在计算机中的实现KMP的流程 93 | 判异同 和 移位(前缀匹配) 94 | 因为构建Next数组本质上也是使用KPM匹配(主串和模式都为原模式T),所以为了更普适Next的实现,调整了一下KPM和Next数组的实现流程图 95 | 96 | ### font color=red1.KMP实现: i,j位比较,相等时S,T同进位,相异时T移位进行前缀匹配 97 | ![在这里插入图片描述](httpsimg-blog.csdnimg.cn20200928145224852.pngx-oss-process=imagewatermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2ExMzM1MjkxMjYzMg==,size_16,color_FFFFFF,t_70#pic_center) 98 | 99 | ### font color=red2.构建Next[]:找Next[j+1],就是看能否扩充T[1, j]中的子前缀 100 | tip扩充前缀(即前缀后一位Tk与Tj相等) 101 | 102 | ![在这里插入图片描述](httpsimg-blog.csdnimg.cn20200928145231785.pngx-oss-process=imagewatermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2ExMzM1MjkxMjYzMg==,size_16,color_FFFFFF,t_70#pic_center) 103 | 104 | 105 | brbr 106 | 107 | ------- 108 | 109 | ## 5.具体代码实现和解释 110 | ```cpp 111 | #includebitsstdc++.h 112 | using namespace std; 113 | 114 | void get_next(string T, int next[]){ T中T[0]储存的是T的字符串长度 115 | int i = 1, j = 0; i为T中指针,j为next数组下标 116 | Next[1] = 0; 117 | 118 | while(i T[0]){ j即保存了Ti配位的位置,也通过 j-1 保存了最大公共子串的字符数 119 | if(j == 0 T[i] == T[j]) {i++;j++;Next[i] = j;} 120 | else j = Next[j]; 121 | } 122 | 123 | 124 | 125 | } 126 | 127 | 128 | int KMP(string S, string T, int pos){ T中T[0]储存的是T的字符串长度 129 | int i = pos; int j = 1; 130 | while(i = S.length && j = S.length){ 131 | if(j==0 T[j] == S[i]) {++i; ++j;} 132 | else j = next[j]; 133 | } 134 | if(j T[0]) return i - T[0]; 135 | else return 0; 136 | 137 | } 138 | 139 | int main(){ 140 | 141 | 142 | 143 | return 0; 144 | } 145 | 146 | ``` 147 | 148 | ## 附:修正后的Next代码 149 | ![在这里插入图片描述](httpsimg-blog.csdnimg.cn20200928160840666.png#pic_center) 150 | 151 | ```cpp 152 | #includebitsstdc++.h 153 | using namespace std; 154 | 155 | int getNext2(int Next[], string T){ 156 | int j = 0; Next[1] = 0; 157 | int i = 1; 158 | while(i string.length()){ 159 | if(j = 0 T[i] == T[j]) { 160 | j++; i++; 161 | if(T[i] != T[j]) Next[i] = j; 162 | else next[i] = next[j]; 等于前一位 163 | } 164 | else j = Next[j]; 165 | 166 | } 167 | 168 | } 169 | ``` -------------------------------------------------------------------------------- /Articles/文本文件和二进制文件的区别.md: -------------------------------------------------------------------------------- 1 | @[toc] 2 | 3 |
4 | 5 | # 编码上的区别 6 | 计算机的存储在物理上是二进制的,所以文本文件与二进制文件的区别并不是物理上的,而是逻辑上的。这两者只是在编码层次上有差异。 7 | 8 | 简单来说,文本文件是基于字符编码的文件,常见的编码有ASCII编码,UNICODE编码等等。二进制文件是基于值编码的文件,你可以根据具体应用,指定某个值(可以看作是自定义编码)。 9 | 10 | 文本文件基本上是定长编码的(也有非定长的编码如UTF-8),基于字符,每个字符在具体编码中是固定的,ASCII码是8个比特的编码,UNICODE一般占16个比特。 11 | 而二进制文件可看成是变长编码的,因为是值编码,多少个比特代表一个值,完全由自己决定。 12 | 13 | # 存取上的区别 14 | 文本工具打开一个文件,首先读取文件物理上所对应的二进制比特流,然后按照所选择的解码方式来解释这个流,然后将解释结果显示出来。一般来说,你选取的解码方式会是ASCII码形式(ASCII码的一个字符是8个比特),接下来,它8个比特8个比特地来解释这个文件流。记事本无论打开什么文件都按既定的字符编码工作(如ASCII码),所以当他打开二进制文件时,出现乱码也是很必然的一件事情了,解码和译码不对应。 15 | 16 | 文本文件的存储与其读取基本上是个逆过程。而二进制文件的存取与文本文件的存取差不多,只是编/解码方式不同而已。 17 | # 优缺点 18 | 因为文本文件与二进制文件的区别仅仅是编码上不同,所以他们的优缺点就是编码的优缺点。一般认为, 19 | - 文本文件编码基于字符定长,译码容易; 20 | - 二进制文件编码是变长的,所以它灵活,存储利用率要高些,译码难一些(不同的二进制文件格式,有不同的译码方式)。 21 | 22 | 在windows下,文本文件不一定是ASCII来存贮的,因为ASCII码只能表示128的标识,打开一个txt文档,然后另存为,有个选项是编码,可以选择存贮格式,一般来说UTF-8编码格式兼容性要好一些。而二进制用的计算机原始语言,不存贮兼容性。 23 | 24 |
25 |
26 |
27 | 28 | -------- 29 | 参考总结自: 30 | [https://www.cnblogs.com/macliu/p/6340131.html](https://www.cnblogs.com/macliu/p/6340131.html) -------------------------------------------------------------------------------- /Articles/浮点数详解(IEEE 754标准).md: -------------------------------------------------------------------------------- 1 | ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200401143739273.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2ExMzM1MjkxMjYzMg==,size_16,color_FFFFFF,t_70) 2 | 3 | -------------- 4 | ==【浮点数有关】== 5 | 在计算机发展过程中,曾经提出过许多种实数的表达方法,比较典型的有浮点数,定点数两种 6 | 7 | 【定点数简介】 8 | || 在定点数表达法中,其小数点固定地位于实数所有数字中间的某个位置。例如,货币的表达就可以采用这种表达方式,如 55.00 或者 00.55 可以用于表达具有 4 位精度,小数点后有两位的货币值。由于小数点位置固定,所以可以直接用 4 位数值来表达相应的数值。 9 | 10 | || 但我们不难发现,定点数表达法的缺点就在于其形式过于僵硬,固定的小数点位置决定了固定位数的整数部分和小数部分,不利于同时表达特别大的数或者特别小的数。因此,最终绝大多数现代的计算机系统都采纳了所谓的浮点数表达法。 11 | 12 | 【浮点数简介】 13 | || 浮点数表达法采用了科学计数法来表达实数,即用一个有效数字。一个基数(Base)、一个指数(Exponent)以及一个表示正负的符号来表达实数。比如,666.66 用十进制科学计数法可以表达为 6.6666×102(其中,6.6666 为有效数字,10 为基数,2 为指数)。浮点数利用指数达到了浮动小数点的效果,从而可以灵活地表达更大范围的实数。 14 | 15 | || 当然,对实数的浮点表示仅作如上的规定是不够的,因为同一实数的浮点表示还不是唯一的。例如,上面例子中的 666.66 可以表达为 0.66666×103、6.6666×102 或者 66.666×101 三种方式。因为这种表达的多样性,因此有必要对其加以规范化以达到统一表达的目标。规范的浮点数表达方式具有如下形式: 16 | ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200401111951388.png)(其中,d.dd…d 为有效数字,β 为基数,e 为指数) 17 | 18 | 19 | || 有效数字中数字的个数称为精度,我们可以用 p 来表示,即可称为 p 位有效数字精度。 20 | 21 | 22 | ||十进制的基数 β 等于 10,每个数字 d 只能在 0 和 9 之间取值 , 二进制的 β 等于 2,而每个数字 d 只能在 0 和 1 之间取值。他们之间的转换关系式(在第二步进行了十进制的运算) 23 | ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200401112812856.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2ExMzM1MjkxMjYzMg==,size_16,color_FFFFFF,t_70) 24 | 25 | 26 | || 由上面的等式,我们可以得出: 27 | 1,向左移动二进制小数点一位相当于这个数除以 2,而向右移动二进制小数点一位相当于这个数乘2。如 101.11=3/4,而 10.111=7/8。 28 | 2,一个十进制小数要能用浮点数精确地表示,最后一位必为5(当然这是必要条件,并非充分条件) 29 | 可以使用程序证明: 30 | 31 | ```c 32 | #include 33 | int main(void) 34 | { 35 | float f1=34.6; 36 | float f2=34.5; 37 | float f3=34.0; 38 | printf("34.6-34.0=%f\n",f1-f3); 39 | printf("34.5-34.0=%f\n",f2-f3); 40 | return 0; 41 | } 42 | ``` 43 | 44 | || 误差原理:因为计算机将二进制转换为十进制的浮点数时,若十进制浮点数尾数非5/0,会因为二进制数无法精确转化为该数而保存四舍五入的结果,故造成了误差,如下图: 45 | 46 | ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200401113931826.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2ExMzM1MjkxMjYzMg==,size_16,color_FFFFFF,t_70) 47 | 48 | 因此,建议不要将浮点数用于精确计算!!! 49 | 且建议不要将浮点数直接用 == 或 != 进行比较,尽量转换为><号 50 | ---------------------------------- 51 | 52 | ```c 53 | #include 54 | int main(void) 55 | { 56 | float f1=34.7; 57 | if(f1 - 34.7 < 0.001) 58 | printf("Right!"); 59 | 60 | if(f1 == 34.7) 61 | printf("Right!"); 62 | 63 | return 0; 64 | } 65 | ``` 66 | 67 | 68 | --------------- 69 | ==【IEEE浮点数表示法】== 70 | 71 | || 本质:IEEE 浮点数标准是从逻辑上用三元组{S,E,M}来表示一个浮点数 V 的,即 V=(-1)S×M×2E 72 | ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200401114647358.png) 73 | 74 | - 符号位 s(Sign)决定数是正数(s=0)还是负数(s=1),而对于数值 0 的符号位解释则作为特殊情况处理。 75 | 76 | - 有效数字位 M(Significand)是二进制小数,它的取值范围为 1~2-ε,或者为 77 | 0~1-ε。它也被称为尾数位(Mantissa)、系数位(Coefficient),甚至还被称作“小数”。 78 | 79 | 80 | - 指数位E(Exponent)是 2 的幂(可能是负数),它的作用是对浮点数加权。 81 | 82 | 83 | **||(分析思路:位数 = =》 有效范围 = =》实际范围 )** 84 | 85 | 【32位单精度浮点数详解】 86 | 87 | Float 88 | S--------E-------M 89 | 1位-----8位-----23位 90 | **M位**:代表其精度,有效数字的个数有 2^ (23+1) = 16777216个,即二进制数的范围为(0,16777216) 化为十进制:10^ 7 < 16777216 < 10^8,所以说单精度浮点数的**有效位数是7位**。 91 | 92 | **E位**:代表其指数位:有效数字个数有 2^ 8 = 256个,即指数范围为(0,255)除去第一个和最后一个数字作为特殊值,有效指数的范围为(1,254),设置一个偏差值(2k-1-1)= -127 使之可以表示负指数,故**实际指数范围(-126,127)**,可以代表127个正指数和126个负指数加1个零指数。 93 | 94 | 95 | 【64位双精度浮点数详解】 96 | 97 | Double 98 | S--------E-------M 99 | 1位-----11位----52位 100 | **M位**:代表其精度,有效数字个数有*2^ (52+1) = 9007199254740992,又10^ 16 < 9007199254740992 < 10^17,所以双精度的**有效位数是16位**。 101 | **E位**:代表其指数位:有效数字个数有 2^ 11 = 2048个,即指数范围为(0,2047)除去第一个和最后一个数字作为特殊值,有效指数的范围为(1,2046),设置一个偏差值(2k-1-1)= 1023 使之可以表示负指数,故**实际指数范围(-1022,1023)**,可以代表1023个正指数和11022个负指数加1个零指数。 102 | 103 | 104 | 105 | 106 | || 浮点异常值:NAN,QNAN,SNAN 107 | 这里所要说的浮点异常值就是这种IEEE浮点表示产生的几种特殊值,IEEE规定根据指数和尾数的不同分别可表示如下几种特殊值: 108 | 109 | 1. 零值:按上述的浮点表述形式如果指数部分全部为0,并且尾数全部为0,则表示为浮点0.0,并且规定-0 = +0 110 | 111 | 2. 非规格化值:如果指数全部为0,尾数非0,则表示非规格化的值,16进制看到的就是[80xxxxxx]h或者[00xxxxxx]h 112 | 113 | 3. 无穷值:如果指数全部为1,尾数全部为0,则根据符号位分别表示正无穷大和负无穷大,16进制看到的就是[FF800000]h或者[7F800000]h 114 | 115 | 4. NAN:如果指数全部为1,尾数非0,则表示这个值不是一个真正的值(Not A Number)。NAN又分成两类:QNAN(Quiet NAN)和SNAN(Singaling NAN)。 116 | QNAN与SNAN的不同之处在于,QNAN的尾数部分最高位定义为1,SNAN最高位定义为0; 117 | QNAN一般表示未定义的算术运算结果(技术NaN),最常见的莫过于除0运算;SNAN一般被用于标记未初始化的值 (信号NaN),以此来捕获异常。 118 | -------------------------------------------------------------------------------- /Articles/美赛部分python代码-情感分析源码(中文).md: -------------------------------------------------------------------------------- 1 | 粗浅地突击学习了一点点自然语言处理,在文章里会分析python实现的文本情感分析代码, 2 | 3 | **代码功能**:分析一句话(中文)里蕴含的正面情绪和负面情绪并评分,最后返回正负面情绪的总分,平均分,标准差 4 | 5 | 6 | **写在前面**: 7 | 其实实现的思路很清晰:分词 - 词语分析(正面词/负面词/程度词/否定词) - 按打分规则评分 8 | 9 | 10 | -------- 11 | || 导入jieba库和numpy矩阵 12 | ```python 13 | import jieba 14 | import numpy as np 15 | ``` 16 | || 打开词典文件,返回列表 17 | 18 | ```python 19 | def open_dict(Dict = 'hahah', path=r'/Users/86133/乱七八糟的代码们/python/Textming/'): 20 | path = path + '%s.txt' % Dict 21 | dictionary = open(path, 'r', encoding='utf-8') 22 | dict = [] 23 | for word in dictionary: 24 | word = word.strip('\n') 25 | dict.append(word) 26 | return dict 27 | ``` 28 | 29 | || 将自己的中文语料文本导入(这里你要修改path路径)。 30 | ```python 31 | deny_word = open_dict(Dict = '否定词', path= r'/Users/86133/乱七八糟的代码们/python/Textming/') 32 | posdict = open_dict(Dict = 'positive', path= r'/Users/86133/乱七八糟的代码们/python/Textming/') 33 | negdict = open_dict(Dict = 'negative', path= r'/Users/86133/乱七八糟的代码们/python/Textming/') 34 | degree_word = open_dict(Dict = '程度级别词语', path= r'/Users/86133/乱七八糟的代码们/python/Textming/' 35 | ``` 36 | 37 | || 针对程度词细分程度:extreme,very,more,ish,last (tips:用以划分的标志词需要在程度词文本中写入) 38 | ```python 39 | mostdict = degree_word[degree_word.index('extreme')+1 : degree_word.index('very')]#权重4,即在情感词前乘以4 40 | verydict = degree_word[degree_word.index('very')+1 : degree_word.index('more')]#权重3 41 | moredict = degree_word[degree_word.index('more')+1 : degree_word.index('ish')]#权重2 42 | ishdict = degree_word[degree_word.index('ish')+1 : degree_word.index('last')]#权重0.5 43 | ``` 44 | 45 | || 核心代码:评分逻辑 46 | ```python 47 | def judgeodd(num): 48 | if (num % 2) == 0: 49 | return 'even' 50 | else: 51 | return 'odd' 52 | 53 | def sentiment_score_list(dataset): 54 | seg_sentence = dataset.split('%%%') 55 | 56 | count1 = [] 57 | count2 = [] 58 | for sen in seg_sentence: #循环遍历每一个评论 59 | segtmp = jieba.lcut(sen, cut_all=False) #把句子进行分词,以列表的形式返回 60 | i = 0 #记录扫描到的词的位置 61 | a = 0 #记录情感词的位置 62 | poscount = 0 #积极词的第一次分值 63 | poscount2 = 0 #积极词反转后的分值 64 | poscount3 = 0 #积极词的最后分值(包括叹号的分值) 65 | negcount = 0 66 | negcount2 = 0 67 | negcount3 = 0 68 | for word in segtmp: 69 | if word in posdict: # 判断词语是否是情感词 70 | poscount += 1 71 | c = 0 72 | for w in segtmp[a:i]: # 扫描情感词前的程度词 73 | if w in mostdict: 74 | poscount *= 4.0 75 | elif w in verydict: 76 | poscount *= 3.0 77 | elif w in moredict: 78 | poscount *= 2.0 79 | elif w in ishdict: 80 | poscount *= 0.5 81 | elif w in deny_word: 82 | c += 1 83 | if judgeodd(c) == 'odd': # 扫描情感词前的否定词数 84 | poscount *= -1.0 85 | poscount2 += poscount 86 | poscount = 0 87 | poscount3 = poscount + poscount2 + poscount3 88 | poscount2 = 0 89 | else: 90 | poscount3 = poscount + poscount2 + poscount3 91 | poscount = 0 92 | a = i + 1 # 情感词的位置变化 93 | 94 | elif word in negdict: # 消极情感的分析,与上面一致 95 | negcount += 1 96 | d = 0 97 | for w in segtmp[a:i]: 98 | if w in mostdict: 99 | negcount *= 4.0 100 | elif w in verydict: 101 | negcount *= 3.0 102 | elif w in moredict: 103 | negcount *= 2.0 104 | elif w in ishdict: 105 | negcount *= 0.5 106 | elif w in degree_word: 107 | d += 1 108 | if judgeodd(d) == 'odd': 109 | negcount *= -1.0 110 | negcount2 += negcount 111 | negcount = 0 112 | negcount3 = negcount + negcount2 + negcount3 113 | negcount2 = 0 114 | else: 115 | negcount3 = negcount + negcount2 + negcount3 116 | negcount = 0 117 | a = i + 1 118 | elif word == '!' or word == '!': ##判断句子是否有感叹号 119 | for w2 in segtmp[::-1]: # 扫描感叹号前的情感词,发现后权值+2,然后退出循环 120 | if w2 in posdict or negdict: 121 | poscount3 += 2 122 | negcount3 += 2 123 | break 124 | i += 1 # 扫描词位置前移 125 | 126 | 127 | # 以下是防止出现负数的情况 128 | pos_count = 0 129 | neg_count = 0 130 | if poscount3 < 0 and negcount3 > 0: 131 | neg_count += negcount3 - poscount3 132 | pos_count = 0 133 | elif negcount3 < 0 and poscount3 > 0: 134 | pos_count = poscount3 - negcount3 135 | neg_count = 0 136 | elif poscount3 < 0 and negcount3 < 0: 137 | neg_count = -poscount3 138 | pos_count = -negcount3 139 | else: 140 | pos_count = poscount3 141 | neg_count = negcount3 142 | 143 | count1.append([pos_count, neg_count]) 144 | count2.append(count1) 145 | count1 = [] 146 | 147 | return count2 148 | ``` 149 | || 数据汇总 150 | 151 | 为每句话创建一个矩阵,矩阵中每行代表一句话按规则划分出的一系列词组,每列代表这些词组的各项打分, 152 | 对这些矩阵中的数据进行列求和操作( 即针对一句话的每一个部分的评分进行汇总),最后结果使用一维数组返回 153 | 154 | >若将需要计算的数据放入二维数组中,将出现TypeError: list indices must be integers or slices, not tuple的报错因为在python中列表中的每一个元素大小可能不同,因此不能直接取其某一列进行操作应该利用numpy.array函数将其转变为标准矩阵,再对其进行取某一列的操作 155 | ```python 156 | def sentiment_score(senti_score_list): 157 | score = [] 158 | i = 0 159 | for review in senti_score_list: 160 | i = i + 1 161 | score_array = np.array(review) 162 | Pos = np.sum(score_array[:, 0]) 163 | Neg = np.sum(score_array[:, 1]) 164 | AvgPos = np.mean(score_array[:, 0]) 165 | AvgPos = float('%.1f'%AvgPos) 166 | AvgNeg = np.mean(score_array[:, 1]) 167 | AvgNeg = float('%.1f'%AvgNeg) 168 | StdPos = np.std(score_array[:, 0]) 169 | StdPos = float('%.1f'%StdPos) 170 | StdNeg = np.std(score_array[:, 1]) 171 | StdNeg = float('%.1f'%StdNeg) 172 | score.append([Pos, Neg, AvgPos, AvgNeg, StdPos, StdNeg]) 173 | 174 | return score 175 | ``` 176 | 177 | || 测试代码 178 | ```python 179 | data = """这个做的不行!!""" 180 | data2 = """你做的真好真不错!""" 181 | arr = sentiment_score(sentiment_score_list(data)) 182 | for x in range(len(arr)): 183 | print(arr[x]) 184 | ``` 185 | -------------------------------------------------------------------------------- /Articles/解决git push报错 hint Updates were rejected because the tip of your current branch is behind和各种其它小报错.md: -------------------------------------------------------------------------------- 1 | - [报错原因](#报错原因) 2 | - [解决方案一](#解决方案一) 3 | - [解决方案二](#解决方案二) 4 | - [解决方案三](#解决方案三) 5 | 6 | 7 | 8 | ## 报错原因 9 | ! [rejected] master -> master (fetch first) 10 | error: failed to push some refs to 'https://github.com/fang0jun/myLeetCode.git' 11 | hint: Updates were rejected because the remote contains work that you do 12 | hint: not have locally. This is usually caused by another repository pushing 13 | hint: to the same ref. You may want to first integrate the remote changes 14 | hint: (e.g., 'git pull ...') before pushing again. 15 | hint: See the 'Note about fast-forwards' in 'git push --help' for details. 16 | 17 | ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200917105757461.png#pic_center) 18 | 19 | **这本地仓库与线上仓库不一致产生的报错!** 20 | 21 | 22 | ------------- 23 | 24 | ## 解决方案一 25 | 产生的原因是本地仓库与线上仓库的内容不匹配,或者说本地相对于远程不是最新,先pull更新本地,再把自己的push上去。** ps:如果不想代码清光光的话,切忌使用-f 强制push(希望人没事🙏) 26 |
27 | 命令: 28 | ```cpp 29 | git pull xxx(网址或者别名) xxx分支 30 | ``` 31 | 32 | ## 解决方案二 33 | 若方案一为解决push仍然失败,尝试使用以下代码重新pull 34 | 35 | 命令: 36 | ```bash 37 | git pull xxx(网址或者别名) xxx分支 --allow-unrelated-histories 38 | ``` 39 | 40 | ## 解决方案三 41 | 若github项目提交失败,报错: master -> master (non-fast-forward) 42 | 43 | 命令 44 | - 先执行git pull 45 | - 然后再执行 git push --force origin master(代替git push origin master) -------------------------------------------------------------------------------- /Articles/详解C中的系统调用open,close,read,write.md: -------------------------------------------------------------------------------- 1 | 2 | - [fopen()](#fopen) 3 | - [fputc() 和 fgetc()](#fputc-和-fgetc) 4 | - [fgets()](#fgets) 5 | - [fputs()](#fputs) 6 | - [fread()和fwrite()](#fread和fwrite) 7 | - [读写函数的区别](#读写函数的区别) 8 | - [详解EOF](#详解eof) 9 | 10 | ------ 11 | 12 | 先谈谈open/close/read/write与fopen/fclose/fread/fwrite的区别 13 | - open/close/read/write是低级IO, 是系统调用函数 14 | - fopen/fclose/fread/fwrite是高级IO,是标准库中的函数 15 | 16 | 后者由前者实现:例如getchar() 17 | 18 | ```c 19 | int getchar (void){ 20 | char c; 21 | return ( read (0, &c, 1) == 1) ? (int)c : EOF); 22 | } 23 | ``` 24 | 25 | 附图:对应的一些特殊文字描述符![在这里插入图片描述](https://img-blog.csdnimg.cn/20200923123024960.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2ExMzM1MjkxMjYzMg==,size_16,color_FFFFFF,t_70#pic_center) 26 | 27 |

28 | 29 | 30 | 31 | 32 | || FILE 是系统定义的一个类型,其中包含由文件的各种信息,如文件名,文件地址 33 | || 我们一般使用FILE *fp —— 一个文件指针来操作文件 34 | 35 | 36 | ## fopen() 37 | || fopen():用来以指定的方式打开文件,其原型为: 38 | 39 | ```c 40 | FILE * fopen(const char * path, const char * mode); 41 | ``` 42 | 打开成功时返回类型为文件指针,若打开失败则返回空指针NULL 43 | 第一个参数为文件路径: `fp = fopen(./123.txt, "w")` 44 | 第二个参数mode为打开方式,有以下几种方式: 45 | |打开方式| 说明| 46 | |--|--| 47 | |r |以只读方式打开文件,该文件必须存在。 48 | |r+| 以读/写方式打开文件,该文件必须存在。 49 | |rb+ |以读/写方式打开一个二进制文件,只允许读/写数据。 50 | |rt+ |以读/写方式打开一个文本文件,允许读和写。 51 | |w| 打开只写文件,若文件存在则长度清为0,即该文件内容消失,若不存在则创建该文件。 52 | |w+| 打开可读/写文件,若文件存在则文件长度清为零,即该文件内容会消失。若文件不存在则建立该文件。 53 | |a |以附加的方式打开只写文件。若文件不存在,则会建立该文件,如果文件存在,写入的数据会被加到文件尾,即文件原先的内容会被保留(EOF符保留)。 54 | |a+| 以附加方式打开可读/写的文件。若文件不存在,则会建立该文件,如果文件存在,则写入的数据会被加到文件尾后,即文件原先的内容会被保留(原来的EOF符 不保留)。 55 | |wb| 以只写方式打开或新建一个二进制文件,只允许写数据。 56 | |wb+| 以读/写方式打开或建立一个二进制文件,允许读和写。 57 | |wt+| 以读/写方式打开或建立一个文本文件,允许读写。 58 | |at+| 以读/写方式打开一个文本文件,允许读或在文本末追加数据。 59 | |ab+| 以读/写方式打开一个二进制文件,允许读或在文件末追加数据。 60 | 61 | --- 62 | ## fputc() 和 fgetc() 63 | 64 | || **fgetc()**: fgetc 是 file get char 的缩写,意思是**从指定的文件中读取一个字符到缓存区**。 65 | 经常配合使用 putchar(ch) -- 从缓存区输出一个字符到屏幕上 66 | >它的语法为:`int fgetc (FILE *fp);` 67 | 68 | 69 | 读取成功时返回读取到的字符,读取到文件末尾或读取失败时返回EOF(EOF 是 end of file 的缩写,表示文件末尾,它的值是一个负数,往往是 -1(反正不能是char(char为正数) ) ) 70 | 71 |
72 | 73 | 【示例】在屏幕上显示 D:\\demo.txt 文件的内容。 74 | 75 | ```c 76 | #include 77 | int main(){ 78 | FILE *fp; 79 | char ch; 80 | 81 | //如果文件不存在,给出提示并退出 82 | if( (fp=fopen("D:\\demo.txt","rt")) == NULL ){ 83 | puts("Fail to open file!"); 84 | exit(0); 85 | } 86 | 87 | //每次读取一个字节,直到读取完毕 88 | while( (ch=fgetc(fp)) != EOF ){ 89 | putchar(ch); 90 | } 91 | putchar('\n'); //输出换行符 92 | 93 | if(ferror(fp)){ 94 | puts("读取出错"); 95 | }else{ 96 | puts("读取成功"); 97 | } 98 | 99 | fclose(fp); 100 | return 0; 101 | } 102 | ``` 103 | 104 | 105 |
106 | 107 | <<<<<<< HEAD 108 | || **fputc()**: fputtc 是 file output char 的缩写,意思是 **从缓存区读取一个字符到指定的文件中** 。 109 | 经常配合使用getchar() **从键盘中读取一个字符到缓存区** 110 | >它的语法为:`int fputc ( int ch, FILE *fp );` 111 | 112 | 113 | 【示例】从键盘输入一行字符,写入文件。 114 | 115 | ```c 116 | #include 117 | int main(){ 118 | FILE *fp; 119 | char ch; 120 | 121 | //判断文件是否成功打开 122 | if( (fp=fopen("D:\\demo.txt","wt+")) == NULL ){ 123 | puts("Fail to open file!"); 124 | exit(0); 125 | } 126 | 127 | printf("Input a string:\n"); 128 | //每次从键盘读取一个字符并写入文件 129 | while ( (ch=getchar()) != '\n' ){ 130 | fputc(ch,fp); 131 | } 132 | fclose(fp); 133 | return 0; 134 | } 135 | ``` 136 | 137 | 138 | >== fgetc() / fputc()默认包含移动一个位置指针的功能== 139 | >在文件内部有一个位置指针,用来指向当前读写到的位置,也就是读写到第几个字节。在文件打开时,该指针总是指向文件的第一个字节。使用 fgetc() 函数后,该指针会向后移动一个字节,所以可以连续多次使用 fgetc() 读取多个字符。 140 | 141 | ======= 142 | - 第三个参数mode权限设置: 143 | **该参数只有在建立新文件时才会生效,即当flag为O_CREAT时使用mode设置** 144 | 145 | | 指令 | 说明 | 146 | |--|--| 147 | | S_IRWXU00700 权限| 代表该文件所有者具有可读、可写及可执行的权限. 148 | | S_IRUSR 或S_IREAD00400 权限| 代表该文件所有者具有可读取的权限. 149 | | S_IWUSR 或S_IWRITE, 00200 权限|代表该文件所有者具有可写入的权限. 150 | | S_IXUSR 或S_IEXEC, 00100 权限| 代表该文件所有者具有可执行的权限. 151 | | S_IRWXG 00070 权限|代表该文件用户组具有可读、可写及可执行的权限. 152 | | S_IRGRP 00040 权限| 代表该文件用户组具有可读的权限. 153 | | S_IWGRP 00020 权限| 代表该文件用户组具有可写入的权限. 154 | | S_IXGRP 00010 权限| 代表该文件用户组具有可执行的权限. 155 | | S_IRWXO 00007 权限| 代表其他用户具有可读、可写及可执行的权限. 156 | | S_IROTH 00004 权限| 代表其他用户具有可读的权限 157 | | S_IWOTH 00002 权限| 代表其他用户具有可写入的权限. 158 | | S_IXOTH 00001 权限| 代表其他用户具有可执行的权限. 159 | >>>>>>> bc07df29a1ea62646c06b0fdbc0cf32995bde10a 160 | 161 | 162 | 163 | 164 |
165 | 166 | ## fgets() 167 | || 读字符串函数 fgets() 168 | fgets() 函数用来从指定的文件中读取一个字符串,并保存到字符数组中(至缓存区),它的语法为: 169 | >它的语法为:`char *fgets ( char *str, int n, FILE *fp ); // str 为字符数组,n 为要读取的字符数目,fp 为文件指针。` 170 | 171 | 172 | tip_1:读取到的字符串会在末尾自动添加 '\0',n 个字符也包括 '\0'。 173 | *也就是说*:实际只读取到了 n-1 个字符,如果希望读取 100 个字符,n 的值应该为 101。 174 | tip_2:需要重点说明的是,在读取到 n-1 个字符之前如果出现了**换行'\n'**,或者读到了**文件末尾**,则读取结束。 175 | *也就是说*:不管 n 的值多大,fgets() 最多只能读取一行数据,不能跨行。在C语言中,没有按行读取文件的函数,我们可以借助 fgets(),将 n 的值设置地足够大,每次就可以读取到一行数据。 176 | 177 |
178 | 179 | 【示例】一行一行地读取文件。 180 | 181 | ```c 182 | #include 183 | #include 184 | #define N 100 185 | int main(){ 186 | FILE *fp; 187 | char str[N+1]; 188 | if( (fp=fopen("d:\\demo.txt","rt")) == NULL ){ 189 | puts("Fail to open file!"); 190 | exit(0); 191 | } 192 | 193 | while(fgets(str, N, fp) != NULL){ 194 | printf("%s", str); 195 | } 196 | 197 | fclose(fp); 198 | return 0; 199 | } 200 | ``` 201 | 202 | 203 |
204 |
205 | 206 | ## fputs() 207 | fputs() 函数用来向指定的文件写入一个字符串,(至缓存区),它的用法为: 208 | 209 | ```c 210 | int fputs( char *str, FILE *fp ); 211 | ``` 212 | 【示例】向上例中建立的 d:\\demo.txt 文件中追加一个字符串。 213 | ```c 214 | #include 215 | int main(){ 216 | FILE *fp; 217 | char str[102] = {0}, strTemp[100]; 218 | if( (fp=fopen("D:\\demo.txt", "at+")) == NULL ){ 219 | puts("Fail to open file!"); 220 | exit(0); 221 | } 222 | printf("Input a string:"); 223 | gets(strTemp); 224 | strcat(str, "\n"); 225 | strcat(str, strTemp); 226 | fputs(str, fp); 227 | fclose(fp); 228 | return 0; 229 | } 230 | ``` 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | ## fread()和fwrite() 239 | 对于 Windows 系统,使用 fread() 和 fwrite() 时应该以二进制的形式打开文件。附[《文本文件和二进制文件的差异和区别》](https://blog.csdn.net/a13352912632/article/details/108743530) 240 | 241 | fread() 函数用来从指定文件中读取块数据。所谓块数据,也就是若干个字节的数据,可以是一个字符,可以是一个字符串,可以是多行数据,并没有什么限制(无限制的fgetc()/fgets() )。fread() 的原型为: 242 | 243 | ```c 244 | size_t fread ( void *ptr, size_t size, size_t count, FILE *fp ); 245 | ``` 246 | 247 | fwrite() 函数用来向文件中写入块数据,它的原型为: 248 | 249 | ```c 250 | size_t fwrite ( void * ptr, size_t size, size_t count, FILE *fp ); 251 | ``` 252 | 253 | || 对参数的说明: 254 | >- ptr 为内存区块的指针,它可以是数组、变量、结构体等。fread() 中的 ptr 用来存放读取到的数据,fwrite() 中的 ptr 用来存放要写入的数据。 255 | >- size:表示每个数据块的字节数。 256 | >- count:表示要读写的数据块的块数。 257 | >- fp:表示文件指针。 258 | 理论上,每次读写 size*count 个字节的数据。 259 | 260 | size_t 是在 stdio.h 和 stdlib.h 头文件中使用 typedef 定义的数据类型,表示无符号整数,也即非负数,常用来表示数量。 261 | 262 | || 返回值:返回成功读写的块数,也即 count。如果返回值小于 count: 263 | - 对于 fwrite() 来说,肯定发生了写入错误,可以用 ferror() 函数检测。 264 | - 对于 fread() 来说,可能读到了文件末尾,可能发生了错误,可以用 ferror() 或 feof() 检测。 265 | 266 |
267 | 268 | 【示例】从键盘输入一个数组,将数组写入文件再读取出来。 269 | 270 | ```c 271 | #include 272 | #define N 5 273 | int main(){ 274 | //从键盘输入的数据放入a,从文件读取的数据放入b 275 | int a[N], b[N]; 276 | int i, size = sizeof(int); 277 | FILE *fp; 278 | if( (fp=fopen("D:\\demo.txt", "rb+")) == NULL ){ //以二进制方式打开 279 | puts("Fail to open file!"); 280 | exit(0); 281 | } 282 | 283 | //从键盘输入数据 并保存到数组a 284 | for(i=0; i 304 |
305 | 306 | ## 读写函数的区别 307 | 308 | ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200922213531829.png#pic_center) 309 | 310 |

311 | 312 | ## 详解EOF 313 | || EOF 本来表示文件末尾,意味着文件*读取* 结束,但是很多函数在读取出错时也返回 EOF,那么当返回 EOF 时,到底是文件读取完毕了还是读取出错了?我们可以借助 stdio.h 中的两个函数来判断,分别是 feof() 和 ferror()。 314 | 315 | || feof() 函数用来判断文件内部指针是否指向了文件末尾,它的原型是:`int feof ( FILE * fp );` 316 | 当指向文件末尾时返回非零值,否则返回零值。 317 | 318 | || ferror() 函数用来判断文件操作是否出错,它的原型是:`int ferror ( FILE *fp );` 319 | 出错时返回非零值,否则返回零值。 320 | 321 | tip:需要说明的是,文件出错是非常少见的情况,上面的示例基本能够保证将文件内的数据读取完毕。如果追求完美,也可以加上判断并给出提示: 322 | ```c 323 | if(ferror(fp)){ puts("读取出错");} 324 | else{ puts("读取成功"); } 325 | fclose(fp); 326 | ``` 327 | 328 | >注意:怎么记忆什么函数返回NULL还是EOF? 函数原型中返回类型若是char 则失败返回EOF, 若返回类型是char* 则返回空指针NULL 329 | - [fopen()](#fopen) 330 | - [fputc() 和 fgetc()](#fputc-和-fgetc) 331 | - [fgets()](#fgets) 332 | - [fputs()](#fputs) 333 | - [fread()和fwrite()](#fread和fwrite) 334 | - [读写函数的区别](#读写函数的区别) 335 | - [详解EOF](#详解eof) -------------------------------------------------------------------------------- /Daily/.keep: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /Daily/【23-01-01】菊厂入职前的一些小复习: -------------------------------------------------------------------------------- 1 | 2 | # 目录 3 | -[总结](#总结) 4 | -[day1 day2 day3 day4](#day1 day2 day3 day4) 5 | -[day5](#day5) 6 | -[知识点](#知识点) 7 | 8 | 9 | # 总结 10 | 11 | ## Day1 Day2 Day3 Day4 12 | 13 | - 做计划,找资源: 14 | 1、代码实操:acwing和leetcode日常刷题 15 | 2、看书:《Head First设计模式》,《通信原理》樊昌信 16 | 3、语言复习:C重看文件和指针部分,c++prime再过一遍,捡一捡git和linux 17 | 4、补课职场知识:b站相关职场技巧 18 | ## Day5 19 | - 科目一做完驾考宝典交通信号篇 20 | - 看完linux常用命令 21 | - leetcode 18,19,160 22 | - 开始看 23 | 24 | 25 | # 知识点 26 | linux: 27 | 28 | 特殊路径符:. 当前目录 / .. 上一级目录 / ~ 家目录 29 | ls -a -l 30 | cd: change directory 31 | pwd: print work directory 32 | mkdir: 创建文件夹 33 | touch: 创建文件 34 | cat: 查看文件 35 | cp: copy 复制文件 、 cp -r 复制文件夹 36 | mv: move 移动文件/文件夹 37 | rm: remove 删除文件 、rm -r 删除文件夹 tip:可加无限文件参数, 可用通配符*模糊匹配 38 | find: 在参数路径为起始(按名称或大小)搜索文件; find / -name test.txt 或 find / -size +1M(大于1M) 39 | ======= 40 | 41 | grep: 通过关键字在文件中查找文件行 eg: grep qiang test.txt 42 | wc: 文件统计 -c bytes数量统计 / -c 字符数量统计 / -l 行数统计 / -w 单词数量统计 43 | | :管道符,将左边的输出作为右边的输入 44 | 45 | tip 搭配使用:cat test.txt | grep shuai ; cat test.txt | wc ; ls | grep txt 46 | 47 | ======= 48 | 49 | echo: 纯粹输入内容到屏幕上(print); echo HelloWorld! 50 | 反引号`: 其包围的内容作为命令执行; echo `pwd` 51 | 重定向符 >: 将左边的输出,覆盖写到右边; 52 | 重定向符 >>: 将左边的输出,追加写到右边; echo HelloWorld! >> test.txt 53 | 54 | ======= 55 | 56 | groupadd/groupdel : 增删用户组 57 | useradd/userdel : 增删用户 58 | id/usemod : 查看/修改用户所在用户组 59 | 60 | 61 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 | 5 |

fang 0 jun

6 | 7 |
8 | 9 | ## Introduction 10 | Go to [Issues](https://github.com/fang0jun/Blog/issues) to view the blog
/ 前往 [Issues](https://github.com/fang0jun/Blog/issues) 查看博客 11 | 12 | This is my github blog, I will learn and record here 13 | 14 | If you like my blog or my blog is helpful to you, please give me a star :) 15 | 16 | Moreover, My blog is also updated in these places: 17 | * [CSDN](https://blog.csdn.net/a13352912632) 18 | * [personal blog](fang0jun.github.io/) 19 | * Wechat Public: ThunderCat_Allor 20 |
21 | 22 | 23 | 24 |
25 | 26 | ## Contacts 27 | 28 | * Email:[fang0jun@qq.com](fang0jun@qq.com) 29 | * Wechat Public: ThunderCat_Allo :) 30 | -------------------------------------------------------------------------------- /images/20200912154046124.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fang0jun/Blog/f1f992263cca9c9c8fc329afb93f1eeb32c683e9/images/20200912154046124.png -------------------------------------------------------------------------------- /images/20200912154125121.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fang0jun/Blog/f1f992263cca9c9c8fc329afb93f1eeb32c683e9/images/20200912154125121.png -------------------------------------------------------------------------------- /images/20200914103548705.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fang0jun/Blog/f1f992263cca9c9c8fc329afb93f1eeb32c683e9/images/20200914103548705.png -------------------------------------------------------------------------------- /images/2020091411260018.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fang0jun/Blog/f1f992263cca9c9c8fc329afb93f1eeb32c683e9/images/2020091411260018.png -------------------------------------------------------------------------------- /images/20200914112632730.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fang0jun/Blog/f1f992263cca9c9c8fc329afb93f1eeb32c683e9/images/20200914112632730.png -------------------------------------------------------------------------------- /images/20200914112736163.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fang0jun/Blog/f1f992263cca9c9c8fc329afb93f1eeb32c683e9/images/20200914112736163.png -------------------------------------------------------------------------------- /images/20200917105757461.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fang0jun/Blog/f1f992263cca9c9c8fc329afb93f1eeb32c683e9/images/20200917105757461.png --------------------------------------------------------------------------------