当前位置: 首页 > news >正文

【C语言数据结构】第1章:绪论

每日一句

生活总会给你另一个机会,

这个机会叫明天。


目录

每日一句

一.数据结构的基本概念

1.数据相关核心概念

2.数据结构(data structure)

3.数据类型(data type)

4.数据结构的内容(逻辑结构、物理结构、操作集合)

(1)逻辑结构

(2)物理结构(存储结构)

顺序存储

链式存储

索引存储

散列存储(哈希存储)

(3)操作集合

二.抽象数据类型(ADT)

1.抽象的思想

2.抽象数据类型的定义

3.例子:ADT整数(课本表1-2)

4.ADT的意义

三.算法描述

1.算法与程序的关系

2.算法的描述方式

3.算法的5个重要特性

4.“好算法”的目标

四.算法分析

1.算法分析的分类

2.时间复杂度

3.空间复杂度

五.数据结构的C语言表示

1.算法的描述方式

2.用C语言表述抽象数据类型(ADT)

ADT的定义(伪码形式)

用C语言实现ADT(存储结构 + 操作函数)

3.基本操作的算法描述

总结


一.数据结构的基本概念

1.数据相关核心概念

  • 数据(data):**计算机能处理的各种符号(数值、字符、图像、视频等),是 “计算机可识别的信息载体”。**对客观事物的描述,是计算机能输入并加工的符号集合(如数值、字符、图像、视频等),可理解为“计算机能识别和操作的信息”。
  • 数据元素(data element):构成数据的 基本单位 ,程序中通常将其作为整体处理(如 “一条学生选课记录”“报刊订阅系统的一个节点”); 一个数据元素可包含多个 “数据项”。构成数据的基本单位,程序中通常将其作为整体处理。例如:学生选课表的“一行记录”、报刊订阅系统结构图的“每个节点”(如“登录”“用户”等)。
  • 数据项(data item):数据中 不可再分割的最小单位。例如选课记录里的“学号”“课程名”“成绩”,一个数据元素可包含多个数据项(如“一条选课记录”包含学号、课程名等)。
  • 数据对象(data object):由 性质相同的数据元素 组成的集合,是数据的子集。例如:整个学生选课表、“整数集合 ( D = {0, \pm1, \pm2, \dots} )”、“字母集合 ( C = {A,B,\dots,Z} )”。

2.数据结构(data structure)

数据结构是“相互之间存在特定关系的数据元素的集合”,经典定义为二元组 ( \text{Data_Structure} = (D, R) ),其中:

  • ( D ) 是数据对象(要处理的数据集);
  • ( R ) 是 ( D ) 上关系的有限集(数据元素之间的逻辑关联)。
    简言之,数据结构 = 数据元素 + 元素间的关系。

3.数据类型(data type)

是“一个值的集合 + 定义在该集合上的一组操作”的总称。例如C语言的int类型:取值范围为 (-32768 \sim +32767),支持加、减、乘、除等操作,规定了“能存储什么值”和“能对值做什么操作”。
高级语言的“整型、实型、字符型”等,本质是已实现的数据结构实例(因为它们定义了数据的组织方式和操作)。

4.数据结构的内容(逻辑结构、物理结构、操作集合)

数据结构研究三方面内容:逻辑结构物理结构(存储结构)对数据的操作

(1)逻辑结构

数据元素之间的逻辑关系(与“存储方式”无关,只关注元素间的关联),分为4类基本结构

  • 集合结构:元素间仅存在“同属一个集合”的关系,无其他关联;
  • 线性结构:元素间是一对一的关系(如排队,一人接一人);
  • 树形结构:元素间是一对多的关系(如公司架构:老板管理多个经理,每个经理管理多个员工);
  • 图形结构:元素间是多对多的关系(如社交网络:一人可关注多人,多人也可关注同一人)。
    逻辑结构又可分为线性结构(所有元素排成一个序列)和非线性结构(元素与多个其他元素关联)。

(2)物理结构(存储结构)

逻辑结构在计算机内存中的实际存储方式,核心有两种:
物理结构指数据在计算机内存中的具体存储方式与实现逻辑,直接决定数据操作(插入、删除、查找等)的效率。根据存储方式的不同,主要分为以下四种:

顺序存储
  • 定义:将数据元素存放在内存中连续的存储空间内,数据元素的逻辑顺序与物理存储顺序完全一致
  • 核心特点
    • 无需额外存储“元素间的关系信息”,存储密度高
    • 可通过“下标”随机访问元素(时间复杂度 ( O(1) ),如数组 arr[3] 可直接通过地址计算访问);
    • 插入/删除元素时,需移动大量后续数据(如数组中间插入元素,后续元素需整体后移,时间复杂度 ( O(n) ))。
  • 示例:C语言中的数组(如 int arr[5] = {1,2,3,4,5}),元素 1 2 3 依次存储在内存连续地址(如 0x100 0x104 0x108)中。
链式存储
  • 定义:数据元素存放在内存中非连续的存储空间内,通过给每个元素附加“指针(或引用)”,指向其逻辑上的相邻元素,以此建立元素间的关系。
  • 核心特点
    • 插入/删除元素时,仅需修改指针指向(无需移动数据,时间复杂度 ( O(1) ));
    • 无法“随机访问”(需从首元素开始依次遍历,时间复杂度 ( O(n) ));
    • 指针会占用额外存储空间,存储密度低于顺序存储
  • 示例:单链表(每个节点包含“数据域”和“指针域”,如:
    struct Node {int data;           // 数据域:存储元素值struct Node* next;  // 指针域:指向下一个节点
    };
    
    节点1的 next 指针指向节点2,节点2指向节点3,通过指针串联非连续存储的元素)。
索引存储
  • 定义:将数据分为两部分——数据区(存储所有数据元素)和索引表(存储“关键字-数据地址”的映射关系);通过关键字在索引表中快速查找对应数据的存储地址,再到数据区访问数据。
  • 核心特点
    • 大幅提升查找效率(尤其海量数据,时间复杂度接近 ( O(1) ));
    • 索引表会占用额外存储空间
    • 插入/删除数据时,需同步维护索引表(增加操作开销)。
  • 示例
    • 图书馆的“图书索引”:索引表记录“书名 → 书架编号”,读者先查索引找到书架,再去书架取书;
    • 数据库中的索引:如MySQL的B+树索引,通过索引快速定位表中数据的物理位置。
散列存储(哈希存储)
  • 定义:通过“散列函数(哈希函数)”,将数据元素的“关键字”直接映射为其在内存中的存储地址,实现“关键字 → 地址”的直接对应。
  • 核心特点
    • 查找、插入、删除效率极高(理想情况下时间复杂度 ( O(1) ));
    • 可能出现“哈希冲突”(不同关键字映射到同一地址),需额外处理(如链地址法:冲突元素用链表串联;开放定址法:冲突时寻找下一个空闲地址);
    • 散列函数的设计直接影响存储效率(需尽可能减少冲突)。
  • 示例
    • 哈希表:如Java中的 HashMap,通过 hash(key) 计算元素存储位置,直接定位元素;
    • 密码学哈希:如MD5算法,将任意长度数据映射为固定长度的哈希值(用于数据完整性校验)。

(3)操作集合

对数据的操作,如增加、删除、修改、查找、排序等。数据结构的完整定义是:“按逻辑组织的数据 + 存储方式 + 可执行的操作”的整体。

二.抽象数据类型(ADT)

1.抽象的思想

抽象是从同类事物中舍弃“个别、非本质的属性”,抽取“共同、本质的属性”。例如“四边形”:无论正方形、长方形还是不规则四边形,只要是“四条边组成的平面封闭图形”,就被抽象为“四边形”;在数据结构中,用抽象描述程序中数据的组织形式(如树、图的抽象定义)。

2.抽象数据类型的定义

抽象数据类型(Abstract Data Type,ADT)是“一组数据对象 + 元素间的结构关系 + 对数据的操作集合”,形式化表示为三元组:

ADT 抽象数据类型名 {数据对象D;   // 要处理的数据集数据关系R;   // 数据元素间的关系基本操作P;   // 可对数据执行的操作
} ADT 抽象数据类型名

核心是只定义“逻辑特性和操作接口”,不关心“具体实现细节”。例如C语言的“整型”是基本类型,基于它可构造“栈、队列”等更复杂的ADT。

3.例子:ADT整数(课本表1-2)

ADT 整数 {数据对象:整数有序序列(从0到最大整数)、布尔值(True/False);基本操作:Zero();        // 类似构造函数,初始化整数Is_Zero(x);    // 判断x是否为0,返回True/FalseAdd(x, y);     // 两整数相加,返回和Equal(x, y);   // 判断x与y是否相等,返回True/FalseSubtract(x, y);// 两整数相减,返回差Successor(x);  // 返回x的下一个自然数,若x是最大整数则返回最大整数
} ADT 整数

ADT的关键:用户只需关心“如何调用操作”,无需关心“操作内部如何实现”(如Add(x,y)是用硬件加法器还是软件模拟,用户无需知晓)。

4.ADT的意义

ADT实现了“信息隐藏”:内部实现细节(如用数组还是链表存储数据)对外屏蔽,仅暴露“操作接口”。这样带来两个好处:

  • 修改内部实现时,只要接口不变,外部代码无需修改(如把“栈”的存储从数组换成链表,调用push/pop的代码无需变更);
  • 软件更“模块化、可复用”,像“搭积木”一样组合ADT开发大型程序(如栈、队列的ADT可在多个场景重复使用)。
    课本强调:“ADT抽象程度越高,软件复用程度越高”(如“图”的ADT比“整型”抽象程度高,能支持更复杂的场景)。

三.算法描述

1.算法与程序的关系

Niklaus Wirth的名言:“算法 + 数据结构 = 程序”——算法是“解决问题的步骤逻辑”,程序是“算法用具体编程语言的实现”。例如计算 ( 1 - \frac{1}{2} + \frac{1}{3} - \frac{1}{4} + \dots + \frac{1}{99} - \frac{1}{100} ),不同算法对应不同程序代码:

  • 算法1:直接逐项相加/相减

    #include <stdio.h>
    int main() {double sum = 0.0;int sign = 1; // 符号标记:1为正,-1为负for (int i = 1; i <= 100; i++) {sum += sign * 1.0 / i;sign = -sign; // 切换符号}printf("结果:%lf\n", sum);return 0;
    }
    
  • 算法2:拆分为两个多项式相减 ( (1 + \frac{1}{3} + \frac{1}{5} + \dots + \frac{1}{99}) - (\frac{1}{2} + \frac{1}{4} + \frac{1}{6} + \dots + \frac{1}{100}) )

    #include <stdio.h>
    int main() {double sum1 = 0.0, sum2 = 0.0;// 计算奇数项和for (int i = 1; i <= 99; i += 2) {sum1 += 1.0 / i;}// 计算偶数项和for (int i = 2; i <= 100; i += 2) {sum2 += 1.0 / i;}double sum = sum1 - sum2;printf("结果:%lf\n", sum);return 0;
    }
    

2.算法的描述方式

  • 自然语言:用中文、英文等描述,优点是“简单易懂”,缺点是“歧义多、不严谨”(如“然后处理数据”,未明确处理逻辑)。
  • 类语言(伪代码):介于自然语言和编程语言之间,更接近代码逻辑(如for i from 1 to n),比自然语言准确,且无需严格遵循某门语言的语法。
  • 程序设计语言(如C语言):最准确,能直接运行,但“编写繁琐,受语言语法限制”。课本后续用C语言描述算法(因C语言类型丰富、执行效率高)。

3.算法的5个重要特性

算法是 “解决特定问题的有限、确定的步骤集合”,需满足 5 个基本特性

  • 有穷性:对任意合法输入,算法必须在有限步骤内结束,且每个步骤的执行时间有限(死循环不是算法)。
  • 确定性:每一条指令的含义明确无歧义,任何情况下算法只有“一条执行路径”(如“若 ( x>0 ) 则执行操作A,否则执行操作B”,条件清晰)。
  • 可行性:算法中的操作都能通过“已实现的基本运算”(如加减乘除、赋值、比较)有限次完成
  • 输入:可以有0个或多个输入(输入是算法执行前的初始数据,若算法内部可生成数据,则无需外部输入)。
  • 输出:至少有一个输出(算法的结果,如打印、返回值等,无输出的算法无意义)。

4.“好算法”的目标

设计算法时,追求以下目标:

  • 正确性:能正确解决问题,分4个层次:
    • 程序无语法错误;
    • 对“合法输入”能得到符合要求的结果;
    • 对“非法输入”能适当处理(如提示错误);
    • 对“所有合法输入”都能得到正确结果(最难达到,通常验证关键场景)。
  • 可读性:容易被人理解,便于交流、维护(如代码添加注释、逻辑清晰)。
  • 健壮性:输入非法数据时,能“做出反应”(如提示“输入错误”),而非崩溃或给出错误结果。
  • 高效率与低存储量需求:执行时间尽可能短(高效率),占用存储空间尽可能少(低存储量)——两者都与“问题规模”(如数据量大小)相关。

四.算法分析

数据结构的优劣通过算法效率体现,需分析算法的时间效率(执行时间)和空间效率(存储空间)。

1.算法分析的分类

  • 算法分析理论上评估效率,不依赖具体计算机(得到通用结论)。
  • 性能测量实际运行程序,统计执行时间和空间占用,但受硬件、软件环境影响大(如在低配电脑和高配电脑上,同一程序运行时间不同)。
    课本重点讲解算法分析(以得到“与具体机器无关”的通用效率结论)。

2.时间复杂度

  • 定义:算法的执行时间随问题规模 ( n ) 增长的趋势,用大O符号表示(大O表示“渐进上界”,即“最坏情况下的增长趋势”)。
    算法执行时间 ≈ 编译时间 + 所有语句执行时间的总和。由于“编译时间与问题规模无关”,因此主要分析语句执行时间

  • 基本操作:与“问题规模”无关的操作(如赋值、比较、算术运算等)。算法的时间消耗,取决于“基本操作的执行次数”。

  • 语句频度与时间复杂度

    • 语句频度:语句执行的次数,记为 ( T(n) );
    • 时间复杂度:记为 ( T(n) = O(f(n)) ),表示“当 ( n ) 趋近于无穷大时,( T(n) ) 的增长趋势与 ( f(n) ) 一致”(低阶项、常数项可忽略,只关注最高阶项)。
  • 经典例子

    • ① 单条操作:

      ++x;
      

      执行次数为1,时间复杂度 ( O(1) )(常数阶)——无论 ( n ) 多大,执行时间基本不变。

    • ② 一层循环:

      for(int i=1; i<=n; i++) {++x;
      }
      

      循环 ( n ) 次,执行次数为 ( n ),时间复杂度 ( O(n) )(线性阶)——( n ) 翻倍,时间也翻倍。

    • ③ 两层循环:

      for(int i=1; i<=n; i++)for(int j=1; j<=n; j++) {++x;}
      

      循环 ( n^2 ) 次,执行次数为 ( n^2 ),时间复杂度 ( O(n^2) )(平方阶)——( n ) 翻倍,时间翻四倍。

  • 课本案例

    • 矩阵相乘(例1-4)

      #define N 100 // 假设矩阵大小为N×N
      void mult(int a[][N], int b[][N], int c[][N], int n) {for(int i=1; i<=n; i++)for(int j=1; j<=n; j++) {c[i][j] = 0;for(int k=1; k<=n; k++) {c[i][j] += a[i][k] * b[k][j];}}
      }
      

      基本操作是“乘法”,执行次数约为 ( 2n^3 + 2n^2 + n )。当 ( n ) 很大时,低阶项(( 2n^2 )、( n ))和常数可忽略,时间复杂度 ( O(n^3) )。

    • 选择排序(例1-5)

      void select_sort(int a[], int n) {int j, k, temp;for(int i=0; i<n-1; i++) {j = i;for(k=i+1; k<n; k++) {if(a[k] < a[j]) j = k;}if(j != i) {temp = a[i];a[i] = a[j];a[j] = temp;}}
      }
      

      基本操作是“比较”,执行次数约为 ( \frac{n(n-1)}{2} )(≈( \frac{n^2}{2} )),时间复杂度 ( O(n^2) )。

    • 冒泡排序(例1-6)

      void bubble_sort(int a[], int n) {int change, temp;for(int i=n-1; i>=1 && change; i--) {change = 0;for(int j=0; j<i; j++) {if(a[j] > a[j+1]) {temp = a[j];a[j] = a[j+1];a[j+1] = temp;change = 1;}}}
      }
      
      • 最好情况(数组已排好序):执行次数为 ( n ),时间复杂度 ( O(n) );
      • 最坏情况(数组逆序):执行次数为 ( \frac{n(n-1)}{2} ),时间复杂度 ( O(n^2) )。
        通常分析最坏时间复杂度(保证算法在“最坏情况”下也能高效运行)。
  • 常用时间复杂度的顺序
    ( O(1) < O(\log_2 n) < O(n) < O(n \log_2 n) < O(n^2) < O(n^3) < O(2^n) )
    越往后,( n ) 增大时执行时间增长越快,因此优先选择复杂度低的算法。

3.空间复杂度

  • 定义:算法所需存储空间的度量,记为 ( S(n) = O(f(n)) ),其中 ( n ) 是问题规模。

  • 空间组成

    • 固定空间需求:与输入无关的空间,如“指令存储空间”“简单变量”“固定大小的结构变量(如结构体)”“常量”等。
    • 可变空间需求:与输入有关的空间,如“输入数据的存储空间”“动态分配的空间(如链表节点)”“递归调用的栈空间”等。
  • 时间与空间的权衡:“时间成本和空间成本是矛盾的”:

    • 时间换空间:如“压缩数据”(节省空间),但需要花费时间“压缩/解压”;
    • 空间换时间:如“预先计算并存储结果”(节省时间),但需要更多存储空间。

五.数据结构的C语言表示

这部分是“抽象到具体”的关键,将“ADT、数据结构”用C语言落地实现。

1.算法的描述方式

描述算法的常见方式:自然语言、流程图、伪代码、N-S结构流程图、PAD图等。
课本选择**“以C语言为主,伪代码为辅”**的策略:

  • 用C语言描述“可直接运行的数据结构实现”;
  • 用伪代码描述“只含抽象操作的算法逻辑”(避免被C语言语法细节干扰,突出核心逻辑)。

2.用C语言表述抽象数据类型(ADT)

ADT的“实现”分为**“定义(逻辑层面)”“代码(物理层面)”**两步。

ADT的定义(伪码形式)

ADT的定义只关注“逻辑要做什么”,不涉及具体语言语法,格式为:

ADT 抽象数据类型名 {数据对象: <对象的抽象定义>数据关系: <元素间关系的抽象定义>基本操作: <操作的抽象定义>
} ADT 抽象数据类型名

其中,“基本操作”的定义需明确前置条件(操作执行的前提)和后置条件(操作执行的结果)。

例子:ADT string(串的抽象定义,例1-7)

ADT string {数据对象: {S | S由字符组成,i=0,1,…,n-1,n≥0}  // 串是“字符序列”数据关系: {R | R={<S₀,S₁>,<S₁,S₂>,…,<Sₙ₋₂,Sₙ₋₁>}}  // 字符间的“顺序关联”关系基本操作:StrAssign(S, chars);  // 赋值:将字符序列chars赋给串SStrDestroy(S);        // 销毁:释放串S的存储空间StrCopy(S₁, S₂);      // 复制:将串S₂的内容复制到S₁StrCompare(S₁, S₂);   // 比较:比较串S₁和S₂的大小StrCombine(S, S₁, S₂); // 连接:将S₁和S₂连接,生成新串SStrReplace(S, S₁, S₂); // 替换:用S₂替换S中与S₁匹配的子串//... 其他操作
} ADT string

ADT定义是“逻辑抽象”,不关心“具体用C语言如何存储、如何编写函数”,只定义“要做什么”。

用C语言实现ADT(存储结构 + 操作函数)

ADT的“实现”需解决两个核心问题:数据怎么存(存储结构) + 操作怎么写(函数)

  • 存储结构的表示(typedef + 结构体)
    用C语言的typedef(类型定义)和struct(结构体),描述“数据的物理存储方式”。

    例子:串的动态数组存储(例1-8)

    typedef struct string {char *str;          // 指针,指向存储字符串的基地址(动态分配内存)int maxlength;      // 动态数组可存储的最大字符数(总空间大小)int length;         // 当前串的实际长度
    } DString, *DStr;
    

    解释:

    • typedefstruct string重命名为DString结构体类型),*DStr是“指向DString的指针类型”(方便用指针操作串);
    • char *str是动态数组的核心:运行时通过malloc分配空间,可灵活存储字符序列;
    • maxlength记录总空间大小,length记录串的实际长度——这种设计能“按需分配、灵活管理”字符串空间。

    补充:类型与变量的区别DString是“类型名”(规定串的存储规范),只有定义DString s;这样的变量时,才会真正分配存储空间。

  • 用C函数实现ADT的操作
    ADT中的“基本操作”(如StrAssignStrCopy),需编写为C函数,格式为:

    函数类型 函数名(函数参数表) {/* 算法说明 */  // 注释:解释函数要完成的逻辑语句序列       // 具体的C代码(赋值、循环、指针操作等)
    }
    

    示例(简化的StrAssign逻辑):

    // 假设Status为int类型,1表示成功,0表示失败
    typedef int Status;
    Status StrAssign(DString *S, char *chars) {/* 算法说明:将chars赋值给串S。成功返回1,失败返回0 */// 1. 释放S原有空间(若存在)if (S->str != NULL) free(S->str);// 2. 计算chars长度,分配新空间int len = strlen(chars);S->str = (char *)malloc((len + 1) * sizeof(char));if (S->str == NULL) return 0; // 内存分配失败// 3. 复制chars到S->str,并设置长度strcpy(S->str, chars);S->length = len;S->maxlength = len + 1;return 1; // 操作成功
    }
    

    补充:

    • 参数传递:常用指针参数(如DString *S),利用C语言的“传地址”特性,直接修改传入变量的内容;
    • 返回状态:若函数需返回“操作是否成功”,可定义typedef int Status;(如1表示成功,0表示失败)。

3.基本操作的算法描述

课本中算法的“类C语言”描述具有以下特点:

  • 格式:函数类型 函数名(参数表),内部包含“注释(算法说明) + 语句序列”;
  • 参数:明确参数类型,辅助变量可通过注释说明(如/* 字符指针p */);
  • 返回值:若返回“操作状态”则用Status类型,若返回具体数据则用对应类型(如intchar *);
  • 指针传递:依赖C语言的指针特性,实现“修改传入变量”的效果(如修改串的内容、长度)。

总结

绪论搭建了“数据结构与算法”的整体框架:

  • 明确“数据怎么组织”(逻辑结构 + 存储结构);
  • 掌握“怎么抽象描述数据”(ADT);
  • 理解“怎么用算法处理数据”(算法的描述、分析);
  • 学会“怎么用C语言实现”(编程语言与数据结构的结合)。

每个概念都为后续“栈、队列、树、图”等具体数据结构的学习奠定基础,透彻理解绪论,后续学习会更加顺畅。

http://www.dtcms.com/a/390464.html

相关文章:

  • Python自动化办公2.0全能实战:从Excel到BI大屏,从OCR到机器学习,一站式提升办公效率100倍
  • 第十四届蓝桥杯青少组C++选拔赛[2022.11.27]第二部分编程题(3、业务办理时间)
  • 微服务-网关gateway理论与实战
  • 吴恩达机器学习笔记week1-2(线性回归模型及Sklearn的使用)
  • 11.2.4 聊天记录拉取设计与实现
  • 系统性学习数据结构-第五讲-排序
  • 编程的本质,到 AI 编程,再到 Vibe Coding
  • 自定义hadoop的单节点mapreduce
  • C++——面向对象
  • Java 生态监控体系实战:Prometheus+Grafana+SkyWalking 整合全指南(二)
  • One-Rec semantic-ID表征
  • HTML HTML基础(5)
  • EasyDSS视频推拉流技术如何实现无人机高清推流与超低延迟直播?
  • 音视频学习(六十六):使用ffmpeg api将实时的264、265裸流封装为fmp4
  • 【音频】在Ubuntu24.04上,源码编译安装Kamailio
  • 数据库与数据仓库易混淆点——数据库不是也可以用于数据的存储吗?为什么要数据仓库
  • 02-Media-9-video_encoder.py 使用视频编码器(VENC)来捕获并编码视频,保存在TF卡中的示例程序
  • Lighthouse安全组自动化审计与加固:基于MCP协议的智能运维实践
  • PHP基础-数据类型(第九天)
  • jQuery中的函数与其返回结果
  • 自动化机器学习框架NexusCore1.0稳定版文档概述
  • 五传输层TCPUDP-思考题-停止等待-ARQ-滑动窗口
  • 使用Azure OpenAI Realtime模型实现语音助理
  • 【智能系统项目开发与学习记录】LinuxUbuntuROS2 零基础学习笔记(小白友好版)
  • Python5-线性回归
  • Windows 定时任务设置、批处理(.bat)命令详解和通过conda虚拟环境定时运行Python程序
  • 无人机图传:让画面直达掌心的传输艺术
  • Django HttpRequest 对象的常用属性
  • 常见的 2 中缓存
  • Python基于Django的微博舆情可视化系统 关键词/用户ID/评论分析 大数据项目(建议收藏)✅