目录

1. 程序设计 = 数据结构 + 算法

2. 基本概念和术语

2.1 数据

2.2 数据元素

2.3 数据对象

2.4 数据结构

3. 逻辑结构和物理结构

3.1 逻辑结构

3.2 物理结构(存储结构)

3.2.1 物理结构的意义

3.2.1 顺序存储结构

3.2.2 链式存储结构

4. 抽象数据类型

4.1 数据类型

4.2 抽象数据类型

4.3 抽象数据类型实例

4.3.1 三元组抽象类型定义

4.3.2 三元组抽象类型实现

5. 算法概述

5.1 算法的定义

5.2 算法的特性

5.3 算法的评价标准

5.3.1 时间(Time)复杂度T(n)

5.3.2 空间(Space)复杂度S(n)

6. 算法时间复杂度分析

6.1 大O复杂度表示法

6.1.1 假设

6.1.2 示例

6.1.3 公式

6.2 时间复杂度分析方法

6.2.1 只关注循环执行次数最多的代码

6.2.2 加法法则:总复杂度等于量级最大的那段代码的复杂度

6.2.3 乘法法则:嵌套代码的复杂度等于嵌套内外代码复杂度的乘积

6.3 常见时间复杂度实例

6.3.1 常量阶O(1)

6.3.2 对数阶O(longn)和线性对数阶O(nlongn)

6.3.3 O(m+n)和O(m*n)

6.4 最好 / 最坏 / 平均复杂度

6.4.1 引入

6.4.2 最好情况复杂度(best case time complexity)

6.4.3 最坏情况复杂度(worst case time complexity)

6.4.4 平均情况时间复杂度(average case time complexity)

6.5 均摊时间复杂度

6.5.1 引入

6.5.2 摊还分析法与均摊时间复杂度


1. 程序设计 = 数据结构 + 算法

程序设计的实质就是构造一种好的数据结构(处理对象的表示)加上设计一种好的算法(处理对象的步骤),即人们常说的"程序设计 = 数据结构 + 算法"。其中数据结构和算法的关系如下,

① 数据结构是为算法服务的

数据结构是静态的数据组织方式,不在其上施加操作,数据结构就没有意义

② 算法要作用在特定的数据结构之上

e.g. 数组具有随机访问的特点,常用的二分查找算法需要用数组来存储数据,如果选择链表,二分查找算法就无法工作

2. 基本概念和术语

2.1 数据

数据(Data)是对客观事物的符号表示,在计算机中,是指能输入到计算机并能由计算机程序进行处理的符号的总称

e.g. 整数、实数、字符、编码后的声音和图像

2.2 数据元素

数据元素(Data Element)是数据的基本单位,在程序中通常是作为一个整体来进行处理的

一个数据元素通常由若干个数据项(Data Item)组成,而数据项是数据的不可分割的最小单位

e.g. 一本书的信息作为数据元素,其中包含书名、作者、出版社等多个数据项

说明:数据元素是数据结构中建立数据模型的着眼点

2.3 数据对象

数据对象(Data Object)是性质相同的数据元素的集合。任何计算机程序不会只处理一个数据元素,其处理的对象通常是性质相同的数据元素的集合

2.4 数据结构

数据结构(Data Structure)的概念至今还没有一个统一的定义,一般来说,数据结构是相互之间存在的一种或多种特定关系的数据元素的集合

可以认为数据结构由如下2方面构成,

① 数据对象在计算机中的组织方式

② 数据对象必定与一系列施加在其上的操作相关联,完成这些操作所用的方法就是算法

3. 逻辑结构和物理结构

3.1 逻辑结构

逻辑结构:数据对象中数据元素之间的相互关系

逻辑结构分为以下四种:

① 集合结构:集合结构中的数据元素除了同属于一个集合外,没有其他关系

② 线性结构:线性结构中的数据元素之间是一对一的关系

③ 树形结构:树形结构中的数据元素之间存在一对多的层次关系

④ 图形结构:图形结构的数据元素是多对多的关系

说明:由于集合结构是数据元素之间关系极为松散的一种结构,因此可以用其他结构来表示他。一般用线性结构处理集合问题

3.2 物理结构(存储结构)

3.2.1 物理结构的意义

① 物理结构是逻辑结构在计算机中的存储形式

② 数据的物理结构应正确反映数据元素之间的逻辑结构,即如何在物理上存储数据元素之间的逻辑关系

③ 逻辑关系是面向问题的,而物理结构是面向计算机的,其基本的目的就是将数据及其逻辑关系存储到计算机的内存中

④ 算法的设计取决于逻辑结构,而算法的实现依赖于物理结构

3.2.1 顺序存储结构

将数据元素存放在地址连续的存储单元中,利用数据元素在内存中的相对位置表示逻辑关系

3.2.2 链式存储结构

把数据元素存放在任意的存储单元里,利用指向数据元素存储地址的指针表示逻辑关系

4. 抽象数据类型

4.1 数据类型

数据类型是指一组性质相同的值的集合及定义在此集合上的一些操作的总称

说明1:数据类型中同时包含了类型的取值范围,以及该类型可进行的运算

说明2:在C语言中,数据类型分为两类,

① 原子类型:是不可以再分解的基本类型,e.g. 整型、字符型

② 结构类型:由若干个类型组合而成,是可以再分解的

4.2 抽象数据类型

抽象数据类型(Abstract Date Type,ADT)是指一个数学模型及定义在该模型上的一组操作。抽象数据类型的定义仅取决于他的一组逻辑特性,与其在计算机内部如何表示和实现无关

抽象数据类型由对象数据集合和数据集合相关联的操作集组成,一般以如下方式定义,

ADT 抽象数据类型名 {数据对象:<数据对象的定义>数据关系:<数据关系的定义>基本操作:基本操作名(参数表)初始条件:<初始条件描述>操作结果:<操作结果描述>
} ADT 抽象数据类型名

4.3 抽象数据类型实例

4.3.1 三元组抽象类型定义

ADT Triplet {数据对象:D = {e1, e2, e3|e1, e2, e3∈ElemSet}数据关系:R1 = {<e1, e2>, <e2, e3>}基本操作:InitTriplet(&T, v1, v2, v3)操作结果:构造了三元组T,元素e1,e2和e3分别被赋以参数v1,v2和v3的值DestroyTriplet(&T)操作结果:三元组T被销毁Get(T, i, &e)初始条件:三元组T已存在,1≤i≤3操作结果:用e返回T的第i元的值Put(&T, i, e)初始条件:三元组T已存在,1≤i≤3操作结果:改变T的第i元的值为eIsAscending(T)初始条件:三元组T已存在操作结果:如果T的3个元素按升序排列,则返回True,否则返回FalseIsDescending(T)初始条件:三元组T已存在操作结果:如果T的3个元素按降序排列,则返回True,否则返回FalseMax(T, &e)初始条件:三元组T已存在操作结果:用e返回T的3个元素中的最大值Min(T, &e)初始条件:三元组T已存在操作结果:用e返回T的3个元素中的最小值
} ADT Triplet

说明1:ADT抽象在何处

描述数据类型的方法不依赖于具体实现,只描述数据对象集和操作集"是什么",并不涉及"如何实现"的问题

① 与存放数据的机器无关(体系结构)

② 与数据存储的物理结构无关

③ 与实现操作的编程语言和算法无关

说明2:关于引用传递

教材中使用类C++语言描述ADT,引用传递表示操作内部会修改该数据类型的变量,即此处是一个出参

4.3.2 三元组抽象类型实现

借助三元组抽象类型的实现,一并说明后续数据结构的实现风格

/* triplet.h实现 */
#ifndef TRIPLET_H
#define TRIBPLET_H#include "public_header.h"/* 三元组数据类型 */
typedef int ElemType;struct Triplet_t
{ElemType *elem;
};
typedef struct Triplet_t Triplet;/* 三元组操作函数 *//*
* 操作结果:构造三元组T,元素e1,e2和e3分别被赋予参数v1,v2和v3的值
*/
Status InitTriplet(Triplet *T, ElemType v1, ElemType v2,
ElemType v3);/*
* 操作结果:三元组T被销毁
*/
Status DestroyTriplet(Triplet *T);/*
* 初始条件:三元组T已存在,1<=i<=3
* 操作结果:用e返回T的第i元的值
*/
Status Get(const Triplet *T, int i, ElemType* e);/*
* 初始条件:三元组T已存在,1<=i<=3
* 操作结果:改变T的第i元的值为e
*/
Status Put(Triplet *T, int i, ElemType e);/*
* 初始条件:三元组T已存在
* 操作结果:如果T的3个元素按升序排列,则返回True,否则返回False
*/
Status IsAscending(const Triplet *T);/*
* 初始条件:三元组T已存在
* 操作结果:如果T的3个元素按降序排列,则返回True,否则返回False
*/
Status IsDesending(const Triplet *T);/*
* 初始条件:三元组T已存在
* 操作结果:用e返回T的3个元素中的最大值
*/
Status Max(const Triplet *T, ElemType *e);/*
* 初始条件:三元组T已存在
* 操作结果:用e返回T的3个元素中的最小值
*/
Status Min(const Triplet *T, ElemType *e);#endif
#include <stdlib.h>
#include "triplet.h"/* 内部函数 */
/*
* 操作结果:如果a >= b返回True,否则返回False
*/
Bool compare(ElemType a, ElemType b)
{if (a >= b)return TRUE;elsereturn FALSE;
}/* 三元组操作函数 */
/*
* 操作结果:构造三元组T,元素e1,e2和e3分别被赋予参数v1,v2和v3的值
*/
Status InitTriplet(Triplet *T, ElemType v1, ElemType v2,
ElemType v3)
{if (!T)return ERROR;T->elem = (ElemType *)malloc(3 * sizeof(ElemType));if (!T->elem)return ERROR;T->elem[0] = v1;T->elem[1] = v2;T->elem[2] = v3;return OK;
}/*
* 操作结果:三元组T被销毁
*/
Status DestroyTriplet(Triplet *T)
{if (!T || !T->elem)return ERROR;free(T->elem);T->elem = NULL;return OK;
}/*
* 初始条件:三元组T已存在,1<=i<=3
* 操作结果:用e返回T的第i元的值
*/
Status Get(const Triplet *T, int i, ElemType *e)
{if (!T || !T->elem)return ERROR;if (i < 1 || i > 3)return ERROR;*e = T->elem[i - 1];return OK;
}/*
* 初始条件:三元组T已存在,1<=i<=3
* 操作结果:改变T的第i元的值为e
*/
Status Put(Triplet *T, int i, ElemType e)
{if (!T || !T->elem)return ERROR;if (i < 1 || i > 3)return ERROR;T->elem[i - 1] = e;return OK;
}/*
* 初始条件:三元组T已存在
* 操作结果:如果T的3个元素按升序排列,则返回True,否则返回False
*/
Status IsAscending(const Triplet *T)
{if (!T || !T->elem)return FALSE;if (compare(T->elem[1], T->elem[0]) &&compare(T->elem[2], T->elem[1]))return TRUE;elsereturn FALSE;
}/*
* 初始条件:三元组T已存在
* 操作结果:如果T的3个元素按降序排列,则返回True,否则返回False
*/
Status IsDesending(const Triplet *T)
{if (!T || !T->elem)return FALSE;if (compare(T->elem[0], T->elem[1]) &&compare(T->elem[1], T->elem[2]))return TRUE;elsereturn FALSE;
}/*
* 初始条件:三元组T已存在
* 操作结果:用e返回T的3个元素中的最大值
*/
Status Max(const Triplet *T, ElemType *e)
{if (!T || !T->elem)return ERROR;if (compare(T->elem[0], T->elem[1])) {if (compare(T->elem[0], T->elem[2]))*e = T->elem[0];else*e = T->elem[2];}else {if (compare(T->elem[1], T->elem[2]))*e = T->elem[1];else*e = T->elem[2];}return OK;
}/*
* 初始条件:三元组T已存在
* 操作结果:用e返回T的3个元素中的最小值
*/
Status Min(const Triplet *T, ElemType *e)
{if (!T || !T->elem || !e)return ERROR;if (compare(T->elem[0], T->elem[1])) {if (compare(T->elem[1], T->elem[2]))*e = T->elem[2];else*e = T->elem[1];}else {if (compare(T->elem[0], T->elem[2]))*e = T->elem[2];else*e = T->elem[0];}return OK ;
}

说明1:结构体形式描述数据结构

将数据结构封装为结构体,可简化指针操作(不再需要用到二级指针),也便于数据结构的整体描述

说明2:数据结构操作均传递指针

由于将数据结构封装为结构体,传递指针可以提高效率(尤其是当结构体比较复杂时)。对于不会改变结构体变量内容的函数,则传递const类型指针

说明3:内部函数compare

使用compare函数比较两个ElemType类型数据的大小,提升了代码的通用性。当ElemType不是原子类型时,compare函数可根据实际情况实现

5. 算法概述

5.1 算法的定义

算法是解决特定问题求解步骤的描述,在计算机中表现为指令的有限序列,并且每条指令表示一个或多个操作

5.2 算法的特性

① 输入输出

算法具有零个或多个输入,至少有一个输出

② 有穷性

算法在执行有限的步骤后,自动结束而不会出现无限循环,并且每个步骤在可接受的时间内完成

③ 确定性

算法的每个步骤都具有确定的含义,不会出现二义性

④ 可行性

算法的每个步骤都是可行的,都能够通过执行有限的次数完成

5.3 算法的评价标准

5.3.1 时间(Time)复杂度T(n)

根据算法写成的程序在执行时耗费时间的长度。这个长度往往与输入数据的规模有关,时间复杂度过高的低效算法可能导致我们在有生之年都等不到运行结果

5.3.2 空间(Space)复杂度S(n)

根据算法写成的程序在执行时占用内存的大小。这个长度往往与输入数据的规模有关,空间复杂度过高的算法可能导致使用的内存超限,造成程序异常终止(e.g. 层次过深的递归调用)

6. 算法时间复杂度分析

6.1 大O复杂度表示法

6.1.1 假设

假设每行代码的执行时间一样,可记为unit_time

结果:代码总执行时间与代码的执行次数成正比

6.1.2 示例

int cal(int n)
{int sum = 0; // 执行1次int i = 1;   // 执行1次for (; i <= n; ++i) { // 执行n次sum += i; // 执行n次}return sum; // 执行1次
}

在上述示例中,代码的总执行次数为,

f(n) = 2n + 3

6.1.3 公式

T(n) = O(f(n))

其中,

T(n):代码执行时间,n表示数据的规模

f(n):代码的总执行次数

O:表示代码的执行时间T(n)与f(n)表达式是等价无穷大的关系

大O时间复杂度表示代码执行时间随数据规模增长的变化趋势,由于是讨论变化趋势,所以公式中的低阶、常量、系数这三个不左右增长趋势的部分可以忽略

所以示例中的渐进时间复杂度(简称时间复杂度)为,

T(n) = O(2n + 3) = O(n)

说明1:渐进时间复杂度本质上是反映代码执行时间随数据规模增长的趋势

说明2:省略低阶、常量、系数的数学基础是等价无穷大概念

6.2 时间复杂度分析方法

6.2.1 只关注循环执行次数最多的代码

大O时间复杂度表示法忽略公式中的低阶、常量和系数,只需要记录一个最大阶的量级就可以,对应到实例中就是循环执行次数最多的代码

6.2.2 加法法则:总复杂度等于量级最大的那段代码的复杂度

int cal(int n)
{int sum1 = 0;int sum2 = 0;int sum3 = 0;int i = 1;int j = 1;for (; i <= 10000; ++i) { // 第1段求和sum1 += i;}for (i = 1; i <= n; ++i) { // 第2段求和sum2 += i;}for (i = 1; i <= n; ++i) { // 第3段求和for (j = 1; j <= n; ++j) {sum3 += i * j;}}return sum1 + sum2 + sum3;
}

① 第1段求和代码的执行次数与数据规模无关,所以记为常数阶

由于时间复杂度表示的是一个算法执行的执行时间与数据规模增长的变化趋势,所以无论常量的执行时间多大,都可以被忽略,因为他本身对增长趋势没有影响

注意:其实这段的执行时间对代码的总执行时间是有影响的,只是当数据规模n趋于无穷大时可以忽略;但是当n很小时,此处的执行时间是很可观的,所以忽略都是相对的

② 第2段求和代码的时间复杂度为O(n)

③ 第3段求和代码的时间复杂度为O(n^2)

所以总的时间复杂度为O(n^2)

6.2.3 乘法法则:嵌套代码的复杂度等于嵌套内外代码复杂度的乘积

典型的示例就是嵌套循环

6.3 常见时间复杂度实例

常见时间复杂度如上图所示,其中指数阶O(2^n)和阶乘阶O(n!)称为非多项式量级算法(NP时间复杂度)。当数据规模n增大时,非多项式量级算法的执行时间会急剧增加,是非常低效的算法

不同复杂度的变化趋势如下图所示,从中也可以看出实际算法对时间复杂度的追求,如果能将O(n^2)阶的算法优化到O(nlogn)阶,性能将大幅提升

6.3.1 常量阶O(1)

只要代码执行次数不随数据规模n增长,都记为O(1)

6.3.2 对数阶O(longn)和线性对数阶O(nlongn)

int i = 1;
while (i <= n) {i *= 2;
}

示例中循环的执行次数就是2^x = n的解,也就是次。之所以记为O(logn)是因为根据对数换底公式,

即有,而是一个常数,在渐进时间复杂度中可以忽略

在理解了对数阶O(logn)的算法场景之后,线性对数阶O(nlogn)就是根据乘法法则,一段代码的时间复杂度为O(logn),被循环执行n次。归并排序和快速排序的时间复杂度都是O(nlogn)

6.3.3 O(m+n)和O(m*n)

int cal(int m, int n)
{int sum1 = 0;int sum2 = 0;int i = 1;for (; i <= m; ++i) { // O(m)sum1 += i;}for (i = 1; i <= n; ++i) { // O(n)sum2 += i;}return sum1 + sum2;
}

在上述示例中,时间复杂度与2个数据规模(m和n)有关,由于无法事先评估谁的量级更大,所以均需要保留在表达式中

当然,嵌套代码的乘法法则依然有效

补充:空间复杂度分析

与渐进时间复杂度类似,也有空间渐进复杂度的概念,也就是算法的存储空间与数据规模之间的增长关系

空间复杂度分析相对比较简单,常见的空间复杂度为O(1)、O(n)和O(n^2)。其中空间复杂度为O(1)的算法,称为原地算法

6.4 最好 / 最坏 / 平均复杂度

6.4.1 引入

引例:在个数为n的数组中查找值为x的元素

int find(int *a, int n, int x)
{int i = 0;int pos = -1;for (; i < n; ++i) {if (a[i] == x) {pos = i;break; // 一旦查找到目标则退出循环}}return pos;
}

由于要查找的数x可能不在数组中,也可能在数组的任意位置,所以这段代码在不同情况下的时间复杂度不同(即同一段代码在不同输入的情况下时间复杂度量级可能不同),因此才需要引入最好、最坏、平均时间复杂度

补充:这也说明测试用例数据集的重要性

6.4.2 最好情况复杂度(best case time complexity)

在最理想情况下执行这段代码的时间复杂度

e.g. 要查找的数x正好是数组的第1个元素,即最好情况复杂度为O(1)

6.4.3 最坏情况复杂度(worst case time complexity)

在最糟糕情况下执行这段代码的时间复杂度

e.g. 要查找的数x不在数组中或为最后1个元素,即最坏情况复杂度为O(n)

6.4.4 平均情况时间复杂度(average case time complexity)

考虑不同情况发生概率的加权平均时间复杂度(本质是计算数学期望)

e.g. 要查找的数x在或不在数组中的概率均为1/2,而在数组不同位置的概率为1/n,所以可按如下方式计算平均复杂度,平均情况时间复杂度为O(n)

说明:对于某些算法,输入数据的各种情况数是无限的,分析他的平均时间需要高深的数学基础,因此一般代之以分析最坏情况复杂度

6.5 均摊时间复杂度

6.5.1 引入

int [] array = new int[n];
int count = 0;void insert(int val)
{if (count == array.length){ // 数组已满int sum = 0;int i = 0;// 遍历求和存入数组首个位置并清空其余位置for (i = 0; i < array.length; ++i) {sum += array[i];}array[0] = sum;count = 1;}else{ // 数组未满array[count++] = val;}
}

下面先来分析一下这段代码的最好、最坏、平均时间复杂度,

① 最好时间复杂度:数组中正好有空闲,直接插入,时间复杂度为O(1)

② 最坏时间复杂度:数组已满,需要执行一次遍历求和,时间复杂度为O(n)

③ 平均时间复杂度:根据数据插入的位置不同,共有n种情况,这些情况下时间复杂度为O(1);还有一种情况就是数组中没有空闲,此时的时间复杂度为O(n);而这起情况发生的概率相同,均为1 / (n + 1)

所以可按如下方式计算平均复杂度,平均情况时间复杂度为O(1)

insert函数有如下2个特点,

① insert函数在绝大部分情况下时间复杂度为O(1),只有个别情况下时间复杂度才为O(n)

② insert函数O(1)和O(n)的出现是很有规律的,一般都是一个O(n)插入后紧跟着n - 1个O(1)的插入操作

6.5.2 摊还分析法与均摊时间复杂度

根据insert函数的特殊场景,引入了摊还分析法,而摊还分析法得到的时间复杂度即为均摊时间复杂度

摊还分析法示例:每一次O(n)的插入操作都会跟着n - 1次O(1)的插入操作,所以把耗时较多的那次操作均摊到接下来的n - 1次耗时较少的操作上,均摊下来这组连续操作的均摊时间复杂度为O(1)

均摊分析法适用场景:

① 对一个数据结构进行一组连续操作,其中大部分情况下时间复杂度都很低,只有个别情况时间复杂度很高

② 这组操作之间存在前后连贯的时序关系,能够将耗时较高的操作平摊到其他耗时较少的操作上

说明:在能够应用均摊时间复杂度分析的场合,一般均摊时间复杂度就等于最好情况时间复杂度

数据结构与算法基础01:绪论相关推荐

  1. 数据结构与算法:01 绪论

    绪论 知识结构: 一.什么是数据结构 例1:电话号码薄的查询问题. (a1,b1),(a2,b2),-,(an,bn)(a_1,b_1),(a_2,b_2),\dots,(a_n,b_n) (a1​, ...

  2. 【数据结构与算法基础】哈夫曼树与哈夫曼编码(C++)

    前言 数据结构,一门数据处理的艺术,精巧的结构在一个又一个算法下发挥着他们无与伦比的高效和精密之美,在为信息技术打下坚实地基的同时,也令无数开发者和探索者为之着迷. 也因如此,它作为博主大二上学期最重 ...

  3. 青岛大学-王卓 数据结构与算法基础

    青岛大学-王卓 数据结构与算法基础 内容目录 文章目录 青岛大学-王卓 数据结构与算法基础 内容目录 第一周 1.0前言 1.1数据结构的研究内容 1.2基本概念和术语1 逻辑结构的种类 存储结构的种 ...

  4. 数据结构与算法基础-王卓

    文章预览: 数据结构与算法基础-王卓 第一章绪论 **1.1.1基本概念和术语** 数据 数据元素 数据项 数据对象 1.1.2基本概念和术语 1.数据结构解释 2.数据结构包括三方面内容 3.数据结 ...

  5. java算法概述,Java数据结构与算法基础(一)概述与线性结构

    Java数据结构与算法基础(二)递归算法 Java数据结构与算法基础(一)概述与线性结构 学习目的:为了能更顺畅的读很多底层API代码和拓宽解决问题的思路 一.数据结构概述 1.数据结构是什么?数据与 ...

  6. 【python】一道LeetCode搞懂递归算法!#131分割回文串 #以及刷LeetCode的一点点小心得 [数据结构与算法基础]

    题目:给定一个字符串 s,将 s 分割成一些子串,使每个子串都是回文串.返回 s 所有可能的分割方案. # 示例 输入: "aab" 输出: [["aa",&q ...

  7. python数据结构与算法知识点_数据结构和算法基础知识点(示例代码)

    数据结构和算法基础知识点 链表 1.链表是一种由节点组成的线性数据集合,每个节点通过指针指向下一个节点.它是 一种由节点组成,并能用于表示序列的数据结构. 2.单链表:每个节点仅指向下一个节点,最后一 ...

  8. 数据结构与算法基础-青岛大学-王卓

    数据结构与算法基础(青岛大学-王卓)_哔哩哔哩_bilibili 文章目录: 第一章:数据结构的基本概念 1.逻辑结构的种类 2.存储结构的种类 ​3.抽象数据类型的形式定义 4.Complex抽象书 ...

  9. 【数据结构与算法基础】AOE网络与关键路径

    前言 数据结构,一门数据处理的艺术,精巧的结构在一个又一个算法下发挥着他们无与伦比的高效和精密之美,在为信息技术打下坚实地基的同时,也令无数开发者和探索者为之着迷. 也因如此,它作为博主大二上学期最重 ...

最新文章

  1. 【第三期】如何用Leangoo领歌快速搭建敏捷研发体系分享会
  2. C#Redis列表List
  3. 【机器学习】解决中小微企业的信贷决策问题(一)
  4. java itextsharp_使用 c#中的 itextsharp 以 pdf 格式填充 xml
  5. Get Set的问题解决
  6. Spring MVC遭遇checkbox的问题解决方式
  7. python接口自动化(十)--post请求四种传送正文方式(详解)
  8. 一步步学习SPD2010--附录A--SPD工作流条件和操作(4)--列表操作
  9. 睡觉、吃饭、打豆豆。
  10. 软件配置管理概念-3,CM系统的概念
  11. VMware网络问题排查思路
  12. Hadoop是什么?基本概念
  13. 【论文阅读】水下机器人控制视觉伺服部分
  14. Docker 使用容器数据卷 实现宿主机与容器共享数据 容器数据持久化
  15. 不服来试试,Excel中被吹上天的Ctrl+E,到底有多厉害?
  16. 简单演示程序序列号的破解
  17. 关于AutoCAD 2014的securityload…
  18. python爬去音乐_python爬去音乐
  19. win10系统更新后,网络连接显示正常(能登qq),但是所有浏览器都打不开网页,谷歌火狐显示代理拒接连接。
  20. 2021怀柔一中高考成绩查询入口,北京怀柔县第一职业高中2021年招生录取分数线...

热门文章

  1. SpringCloud使用RabbitMQ报错Rabbit health check failed
  2. Spring Boot整合Swagger3注解@ApiImplicitParam的allowMultiple属性
  3. RandomAccessFile读写txt文件中文乱码
  4. 项目中出现specify @BootstrapWith‘s ‘value‘ attribute or make the default bootstrapper class avail
  5. Spring Cloud中的@EnableDiscoveryClient注解和@EnableEurekaClient注解
  6. 遇到一个php的错误,php初学者常见的几个错误及解决方法
  7. linux 内核编号含义_linux内核(kernel)版本号的意义
  8. mysql数据库断电恢复_MySQL数据库InnoDB引擎下服务器断电数据恢复方法
  9. java三个技术平台_Java的3个平台有什么区别
  10. Idea springboot应用,启动报错:org.yaml.snakeyaml.error.YAMLException: java.nio.charset.MalformedInputExcept