草庐IT

【数据结构功法】第2话 · 一篇文章带你彻底吃透·算法复杂度

kikokingzz 2024-04-25 原文

🌕写在前面


Hello🤗大家好啊,我是kikokingzz,名字太长不好记,大家可以叫我kiko哦~

从今天开始,我将正式开启一个新的打卡专题——【数据结构·水滴计划】,没错!这是今年上半年的一整个系列计划!本专题目的是通过百天刷题计划,通过题目和知识点串联的方式刷够1000道题完成对数据结构相关知识的全方位复习和巩固;同时还配有专门的笔记总结和文档教程哦!想要搞定,搞透数据结构的同学

🎉🎉欢迎订阅本专栏🎉🎉

🍊博客主页:kikoking的江湖背景🍊


🌟🌟往期必看🌟🌟

🔥【水滴计划】第一话·数据结构入门竟如此简单?🔥

目录

🌕写在前面

🍺知识点2:算法及其评价

🥝2.1 算法的基本概念

🍊1.什么是算法?

🍊2.数据结构与算法有什么关系?

🍊3.算法具有什么特性呢?

🍊4.怎样算一个好的算法?

🍊5.什么是算法的效率?

🥝2.2 算法的时间复杂度

🍊1.什么是时间复杂度?

🍊2.大O的渐进表示法

🍊3.时间复杂度有哪3种情况?

🍊4.计算复杂度的两条规则

📜实战案例

🥝2.3 算法的空间复杂度

🍊1.什么是空间复杂度?

📝LeetCode之消失的数字

📝LeetCode之旋转数组

📜水滴石穿

🌕写在最后

热爱所热爱的, 学习伴随终生,kikokingzz与你同在!❥(^_-)

🍺知识点2:算法及其评价

🥝2.1 算法的基本概念


🍊1.什么是算法?

算法是对特定问题求解步骤的一种描述,它是指令的有限序列,其中每条指令表示一个或多个操作。


🍊2.数据结构与算法有什么关系?

程序 = 数据结构 + 算法

  • 数据结构:如何用数据正确地描述现实世界的问题(逻辑结构),并存入计算机(存储结构)。
  • 算法:如何高效地处理上述这些数据,以解决实际问题。

可见数据结构是将现实问题转化为电脑可以处理的数据,而算法则是求解问题的步骤;因此针对同一数据结构,求解问题的步骤方法可以不同,因此使用的算法也可以不同。


🍊3.算法具有什么特性呢?

(1)有穷性:一个算法必须总在执行有穷步后结束,且每一步都可在有穷时间内完成。

  • 注:算法必须是有穷的,而程序可以是无穷的,如手机上的CSDN是程序,而不是算法。

(2)确定性:算法中每条指令必须有确切的含义,对于相同的输入只能得到相同的输出。

(3)可行性:算法中描述的操作都可以通过已经实现的基本运算执行有限次来实现。

(4)输入:一个算法有零个或多个输入,这些输入取自于某个特定的对象的集合。

(5)输出:一个算法有一个或多个输出,这些输出是与输入有着某种特定关系的量。


🍊4.怎样算一个好的算法?

(1)正确性:算法能够正确地解决求解问题。

(2)可读性:算法应具有良好的可读性,以帮助人们理解。

(3)健壮性:输入非法数据时,算法能适当地做出反应或进行处理,而不会产生莫名其名的输出结果。

(4)高效率与低存储需求:时间复杂度低,空间复杂度低。


🍊5.什么是算法的效率?

江湖中,传闻,算法效率有时空之分,具体来说便是时间效率与空间效率之分:

  • 时间效率被称为时间复杂度——衡量一个算法的运行速度
  • 空间效率被称为空间复杂度——衡量一个算法所需的额外空间

在计算机发展早期,计算机存储容量很小,所以很在意空间复杂度;但是时光流逝,如今计算机的江湖之中,存储容量已到达极之巅峰,我们已无需特别关注算法复杂度了。


📜007.题目难度 ⭐️

007.一个算法应该是( )。
A.程序
B.问题求解步骤的描述
C.要满足五个基本特性
D.A和C

🍊详细题解:

A. 程序是一组计算机能识别和执行的指令,运行于电子计算机上,其不一定满足有穷性,如死循环、操作系统等。

C. 是算法的特性而不是它的基本定义。

算法:对特定问题求解步骤的一种描述,它是指令的有限序列,其中每条指令表示一个或多个操作;算法代表对问题求解步骤的描述,而程序则是算法在计算机上的实现。

✅正确答案:B 

 ✨✨✨我是分割线✨✨✨

🥝2.2 算法的时间复杂度


🍊1.什么是时间复杂度?

算法的时间复杂度是一个函数,它定量描述了该算法的运行时间。一个算法所花费的时间与其中语句的执行次数成正比,算法中的基本操作的执行次数,为算法的时间复杂度。

Q1:可以使用“算法先运行,事后统计运行时间”的方法来估算时间开销吗?

A1:使用如此方法是不客观的,主要有以下几个原因:

  • 机器性能越强,开销越少;如:超级计算机 vs 单片机。
  • 编程语言越高级,执行效率越低;如:Java写的程序要比用C写的效率低一些。
  • 和编译程序产生的机器指令质量有关。
  • 有些算法是不能事后统计的,如:导弹精准控制算法

🍊2.大O的渐进表示法

实际中我们计算时间复杂度只需要计算大概执行次数,那么我们使用大O的渐进表示法。

大O符号:用于描述函数渐进式行为的数学符号

通过上面我们会发现大O的渐进表示法去掉了那些对结果影响不大的项,简洁明了的表示出了执行次数。


🍊3.时间复杂度有哪3种情况?

最坏情况:任意输入规模的最大运行次数(上界)。

平均情况:任意输入规模的期望运行次数。

最好情况:任意输入规模的最小运行次数(下界) 。


🍊4.计算复杂度的两条规则

(1)加法规则:多项相加,只保留最高阶的项,且系数变为1。

  • T(n,m) = T1(n) + T2(n) = O [ max ( f(n), g(m) ) ]

(2)乘法规则:多项相乘,都保留。

  • T(n,m) = T1(n) * T2(m) = O [ f(n) * g(m) ]

 记忆方式:常 < 对 < 幂< 指 < 阶


📜008.题目难度 ⭐️⭐️

008.某算法的时间复杂度为O(n^2)表明该算法的( )。
A.问题规模是(n^2)
B.执行时间等于(n^2)
C.执行时间与(n^2)成正比
D.问题规模与(n^2)成正比

🍊详细题解:

算法时间复杂度:O[ F(N) 意味着算法在任何情况下,规模为n的前提下,所花费的时间小于等于K*F(N),其中K是与N无关的常数。

A/D. 在评价一个算法的复杂度时,已经默认问题规模为n。

B. 执行时间不是等于(n^2),时间复杂度是该算法的一个上界(即时该算法的最坏情况),应当是小于等于。

C. 算法时间复杂度本身就是一个数量级问题,表示该算法的执行时间小于等于K*(n^2),即与(n^2)成正比。

✅正确答案:C

 ✨✨✨我是分割线✨✨✨ 

📜实战案例


📜案例1——复杂度相加运算

该例中有两个for循环,循环的上限分别为M+1次和N+1次(+1是因为跳出循环时还计算了一次),由大O的渐进表示法可以计算为:O(M+N+2) 近似为O(M+N),本题没有其他条件,不知道M和N的数量级大小,因此O(M+N)可以作为最终答案。

  • 当 M>>N时:时间复杂度为O(M)
  • 当 N>>M时:时间复杂度为O(N)


📜案例2——用1代替所有常数次

该案例中有一个for循环,循环的上限取决于条件判断的常数大小,此处是100,说明最多进行101次循环;如果这里的100改为100000000,也同样是进行常数次循环。因此依照大O的渐进表示法,用1替代所有常数,则其时间复杂度为O(1)

相对的O(1)并不是代表只执行1次,而是代表执行常数次,可以是100次、1000次,也可以是1000万次,不管次数多大,都是常数次!


📜案例3——strchr采用最坏时间复杂度

strchr函数功能为在一个串中查找给定字符的第一个匹配之处。函数原型为:

char *strchr(const char *str, int c);

即在参数 str 所指向的字符串中搜索第一次出现字符 c(一个无符号字符)的位置。


📜案例4——冒泡排序的时间复杂度

最好情况:所有数字已经按序排列,自身有序排列,只需要冒泡排序一遍,由于没有发生交换,因此exchange值不发生改变,仍然为0,最后跳出循环,因此一共就执行了(N-1)次交换,所以其时间复杂度为O(N)。

最坏情况:所有数字倒序排列,每一轮都需要冒泡排序,第一遍冒泡排序(N-1)次,将最大的数字安排到最后一位,然后继续从头开始进行冒泡排序,此时只需要交换(N-2)次,将次大的数安排在倒数第二位,按此顺序一直计算到最后交换1次,此时所有数字排序完成,总共排序了 [(N-1)+(N-2)+·····+ 2 + 1 ] 次,最终计算的时间复杂度为


📜案例5——二分查找的时间复杂度

二分查找法这里假设数组元素呈升序排列,将n个元素分成个数大致相同的两半,取a[n/2]与欲查找的x作比较,如果x=a[n/2]则找到x,算法终止;如 果x<a[n/2],则我们只要在数组a的左半部继续搜索x;如果x>a[n/2],则我们只要在数组a的右 半部继续搜索x。

最好情况:直接1次就找到了,常数次找到,因此时间复杂度为O(1)。

最坏情况:当找不到该数时,需要不断进行折半,一直折半到最后 begin==end 时,退出循环,此时一共执行了 次(具体计算步骤见下图)。

注:时间复杂度中,习惯将log2(N) 简写为 logN


📜案例6——递归阶乘的时间复杂度

(1)单次递归函数调用为O(1)时,就看它递归的次数:

本题在疯狂进行递归,每一次递归中包含了常数次的运算:1次逻辑判断运算和乘法运算,但从时间复杂度角度来看可以近似忽略为O(1)次;而真正占据时间复杂度的应当是其向下递归的次数,其递归次数取决于N,是幂函数,因此其时间复杂度为O(N)。

(2)单次递归函数调用不为O(1)时,就看他递归调用中次数的累加:

long long Fac(size_t N)
{
	if (0 == N)
		return 1;
	for (size_t i = 0; i < N; ++i)
	{
		printf("%d", i);
	}
	printf("\n");
	return Fac(N - 1) * N;
}

对于上面这种变式情况,每次递归调用不是O(1),每次递归调用中的运算次数是变化的,第一次递归时,函数内部进行N次循环;递归到第二次时,函数内部进行N-1次循环;···;递归到第N-1次时,函数内部循环2次;通过计算我们可以得出:


📜009.题目难度 ⭐️

009.【2012统考真题】求整数n (n≥0)的阶乘的算法如下,其时间复杂度是( )。
    int fact(int n) {
        if(n<=1) return 1;
        return n*fact (n-1) ;
    }

A.O(logn)        B.O(n)       C.O(nlogn)        D.O(n^2)

🍊详细题解:

本题就属于上面第(1)种情况,单次递归函数调用为O(1),其只包含了一次乘法运算,因此其时间复杂度就看它向下递归调用的次数,该例有n次递归,因此其时间复杂度为O(n)。

✅正确答案:B


📜案例7——斐波那契数列的时间复杂度

斐波那契数列的递归其实像是一个N-1层金字塔(当然是有残缺的金字塔),但我们计算复杂度时候真正关心的是数量级问题,残缺的那部分根本不会改变数量级,因此可以将其近似看成一个满元素的金字塔,因此从顶向下挨个计算,也就是计算一个等比数列求和,公比为2;最终计算出其时间复杂度为 :


📜案例8——三层循环的时间复杂度

我希望通过这题,可以让大家明白复杂度的核心是数量级的问题,在计算步骤上,只要不改变其最终数量级,可以通过省略和近似的方式来估算其复杂度:

for (i=1 ;i<=n ;i++)
    for(j=1 ;j<=i; j++)
        for(k=1; k<=j; k++)
            x++;

对于上题我们可以从内层向外层来看,首先最内层循环的次数为 j 次,次外层循环为 i 次,此时计算内部两层循环的次数为(1+2+3+4+·····+i)次,即 (1+i)*i/2,这时我们再计算最外层循环,由于最外层循环n次,i的取值范围为(1~n),因此其执行总次数为:

由上述计算过程可得其最后的时间复杂度为O(n^3)。

注意:通过这题我希望大家明白的一个道理是,时间复杂度并不是准确计算出来的一种度量,而是一种算法的最坏情况,或者是算法的一种数量级情况,对于上题,在计算过程中我都采取了局部的省略和近似,这是因为,这些省略和近似并不会改变复杂度的最终数量级,也就是n^3,通过这种省略和近似可以节约复杂度的计算时间。

 ✨✨✨我是分割线✨✨✨

🥝2.3 算法的空间复杂度


🍊1.什么是空间复杂度?

空间复杂度是对一个算法在运行过程中临时占用存储空间大小的量度 。空间复杂度不是程序占用了多少 bytes的空间,因为这个也没太大意义,所以空间复杂度算的是变量的个数。空间复杂度计算规则基本跟时间复杂度类似,也使用大O渐进表示法。


📜案例1——冒泡排序的空间复杂度

空间复杂度计算的是在程序运行过程中,为了满足程序需求,临时创建的空间个数。在下例冒泡排序中,总共开了三个空间,分别是变量end、exchange、i;尽管在这个循环中,exchange这个变量被循环使用,但是用的始终都是exchange这1个空间,只是使用次数在增加,使用的空间个数始终为1,没有发生改变,因此其时间复杂度为O(N),而空间复杂度为O(1)。

注意:使用了常数个空间==空间复杂度为O(1)


📜案例2——斐波那契数列的空间复杂度

下例中,我们单单计算fibArray动态开辟的空间就已经有(n+1)个了,其他剩下的变量开设的都是常数个,因此时间复杂度为O(N);我们这里只需要算一个大概的即可,计算开辟空间数最多的那个即可。

注意:空间复杂度的计算比时间复杂度的简单,一般来说不是O(1)就是O(N)。

// 计算Fibonacci的空间复杂度?
// 返回斐波那契数列的前n项
long long* Fibonacci(size_t n)
 {
     if(n==0)
     return NULL;
 
     long long * fibArray = (long long *)malloc((n+1) * sizeof(long long));
     fibArray[0] = 0;
     fibArray[1] = 1;
     for (int i = 2; i <= n ; ++i)
         {
             fibArray[i] = fibArray[i - 1] + fibArray [i - 2];
         }
     return fibArray;
 }

📜案例3——计算阶乘递归Fac的空间复杂度

long long Fac(size_t N)
 {
     if(N == 0)
         return 1;
     return Fac(N-1)*N; 
}

对于本题,递归出N个栈帧,栈帧开辟的空间是常数个,可以认为是O(1),因此决定其开辟空间个数的主要取决于其递归的次数,本题递归次数为N次,因此空间复杂度为O(N)。


📜案例4——计算斐波那契数列的空间复杂度

long long Fib(size_t N) 
{
     if(N < 3)
         return 1;
 
     return Fib(N-1) + Fib(N-2);
}

上例中我们不断调用,当我们一直递归调用到Fib(2)时,将Fib(2)的值返回给Fib(3),这时Fib(2)栈帧就销毁了,Fib(3)将接着调用Fib(1),这时Fib(1)使用了之前Fib(2)使用的空间,使用了同一块空间;同理在向上返回的时候将不断重复使用销毁过的空间,从Fib(2)到Fib(N)总共建立了N-1个栈帧;而后该开始递归调用Fib(N-2),而这块空间正是之前Fib(N-1)使用过的空间,即空间是可以回收复用的。因此本题的空间复杂度为O(N)。

注意:时间是累计的不可复用,而空间回收之后是可以重复利用的。

程序证明:

当调用完f1( )函数后,将f1中的空间释放;调用f2( )函数,由a和b的地址相同可见,f2( )使用的空间正是刚刚f1释放的空间,证明空间被重复利用了。

void f1()
{
	int a = 0;
	printf("%p\n", & a);
}

void f2()
{
	int b = 0;
	printf("%p\n", & b);
}

int main()
{
	f1(); //调用函数开始会创建栈帧;结束会销毁栈帧
	f2();
	return 0;
}


📜010.题目难度 ⭐️⭐️

010.下面的说法中,错误的是( )。
I.算法原地工作的含义是指不需要任何额外的辅助空间
II.在相同规模n下,复杂度为O(n)的算法在时间上总是优于复杂度为O(2")的算法
III.所谓时间复杂度,是指最坏情况下估算算法执行时间的一个上界
IV.同一个算法,实现语言的级别越高,执行效率越低
A.I                B.I、II            C.I、IV            D.III

🍊详细题解:

I. 算法原地工作是指算法所需的辅助空间是常量,即O(1)个空间。

II. 算法的负责度是一个宏观上的理解,O(n)的算法一定是优于O(2")的算法。

III. 时间复杂度总是考虑最坏情况下的时间复杂度,以保证算法的运行时间不会比它更长。

IV. 越高级的语言,需要层层转换为低级语言给计算机读取,因此执行效率会降低。

✅正确答案:A

 ✨✨✨我是分割线✨✨✨

📝LeetCode之消失的数字



思路1-排序

思路:将这些数字进行挨个排序,如果后一个数字不是前一个数字+1,那么缺的数就是这两个数共同相邻的那个数。例如我们将数字排序后得到{1,2,4},我们从前向后挨个比较相邻两个数,我们发现2后面的数字不等于2+1,因此我们得出缺少的数字是3。

优点:简单易想

缺点:时间复杂度太大,以下算法时间复杂度均未满足题目要求。

  • 采用冒泡排序—— 时间复杂度:
  • 采用快排qsort——时间复杂度:O(N*logN)

思路2-映射方式

思路:建立一个可以完整包含0~n的所有整数的数组并将其初始化为全-1;然后将输入的数字x放到对应下标为[x]的数组空间中(如数字6就放到下标为[6]的空间里);全部放完后,数组中元素值为-1对应的下标,就是缺失的数字。

缺点:这种方式有O(N)的空间复杂度。


思路3-异或^

前情提要:

1.异或运算中顺序发生改变,并不会影响最终结果:

 a^b^c = b^a^c = b^c^a = c^b^a =···

2.两个相同数字异或的最终结果为0;

a^a = b^b = 0

3.0和任意非零数x相异或,其结果等于非零数x;

0 ^ x = x

思路:对于本题,可先对0-n的连续数字异或一遍,接着对含有欠缺数字的数组中的每个数字异或,那么该数组中未欠缺的数字和0-n连续数字会异或2次,结果为0;而因为数组中缺少1位数字,原先0-n的连续数字中必有1位只参与异或1次,因此最后异或计算出的值即为缺失的数字。

代码实现:

int missingNumber(int* nums, int numsSize){
    int sum=0;
    for(int i=0;i<numsSize;++i)
    {
        sum^=nums[i];//计算数列中的异或
    }//时间复杂度为O(N)
    
    for(int j=0;j<numsSize+1;++j)
    {
        sum^=j;//求0-n的异或
    }//时间复杂度为O(N)
 
    return sum;
}

思路4-数列和相减

(0-n计算等差数列的和)-(数组中的值相加)
       O(1)               O(N) 

优点:算法时间复杂度满足√

代码实现:

int missingNumber(int* nums, int numsSize){
    int sum1=0 , sum2=0 ,ret=0;
    for(int i=0;i<numsSize;++i)
    {
        sum2+=nums[i];//计算数列中的和
    }//时间复杂度为O(N)
    sum1=numsSize*(numsSize+1)/2;//计算0-n的等差数列之和
    ret=sum1-sum2;
    return ret;
}

 ✨✨✨我是分割线✨✨✨

📝LeetCode之旋转数组


进阶:

  • 尽可能想出更多的解决方案,至少有三种不同的方法可以解决这个问题。
  • 你可以使用空间复杂度为 O(1) 的原地算法解决这个问题吗?

思路1-依次右移动

思路:右旋K次,依次移动一个;当K=N时,等于数组没有发生旋转,当K=N+1时,等于数组旋转1次,即旋转的次数=(K%N);当(K%N=N-1)时,旋转的次数最多。

时间复杂度:旋转1次需要移动N次,旋转K次就需要移动N*K次,因此为O(K*N);当K的值为N-1时,复杂度为O(N^2),但是由于K也是未知数,因此该算法的时间复杂度为O(N*K)。

空间复杂度:没有额外开数组,用的是原数组,因此为O(1)。


思路2-额外开数组

思路:用空间来换时间,额外建立一个数组,将后K个数拷贝到新建数组的前端,将(n-K)个剩下的数,拷贝到新数组的后端。

时间复杂度:将从前向后挨个计算,将前(n-k)个数拷贝到新数组后(n-k)个位置,再将后k个数拷贝到新数组的前k个位置,计算量即为n,因此时间复杂度为O(N)。

空间复杂度:这时额外开了一个数组,因此空间复杂度为O(N)。


思路3-三轮逆置

思路:用空间来换时间,额外建立一个数组,将后K个数拷贝到新建数组的前端,将(n-K)个剩下的数,拷贝到新数组的后端。

时间复杂度:进行三轮逆置,因此时间复杂度的量级依然取决于元素个数n,时间复杂度为O(N)。

空间复杂度:没有额外开数组,用的是原数组,因此为O(1)。

代码实现:

void reverse(int*a, int left , int right)//创建一个逆置函数
{
    while(left<right)
    {
        int tmp=a[left];
        a[left]=a[right];
        a[right]=tmp;
        ++left;
        --right;
    }
}

void rotate(int* nums, int numsSize, int k){
    k=k%numsSize;
    reverse(nums,0,numsSize-k-1);//step1.逆置前n-k个
    reverse(nums,numsSize-k,numsSize-1);//step2.逆置后k个
    reverse(nums,0,numsSize-1);//step3.逆置整体n个
}

 ✨✨✨我是分割线✨✨✨

📜水滴石穿


📜011.题目难度 ⭐️

011.以下算法的时间复杂度为( )。
void fun(int n) {
	int i = 1;
	while (i <= n)
		i = i * 2;
}
A.O(n)        B.O(n^2)        C.O(nlogn)        D.O(logn)

🍊详细题解:

✅正确答案:D


📜012.题目难度 ⭐️

012.以下算法的时间复杂度为( )。
void fun(int n) {
	int i = 0;
	while (i * i * i <= n)
		i++;
}
A.O(n)        B.O(nlogn)        C.O(³√n)        D.O(√n)

🍊详细题解:

✅正确答案:C


📜013.题目难度 ⭐️

013.以下算法中最后一行语句的执行次数为( )。
	int m = 0, i, j;
	for (i = 1; i <= n; i++)
		for (j = 1; j <= 2 * i; j++)
			m++;
A.n(n+1)        B.n        C.n+1        D.n^2

🍊详细题解:

✅正确答案:A


📜014.题目难度 ⭐️⭐️

014.程序段如下:
	for (i=n-1;i>1;i--)
		for (j=1;j<i;j++)
			if (A[j]> A[j+1])
				A[j]与A[j+1]对换;

其中n为正整数,则最后一行语句的频度在最坏情况下是( )。
A.O(n)        B.O(nlogn)        C.O(n³)        D.O(n²)

🍊详细题解:

✅正确答案:D


📜015.题目难度 ⭐️⭐️

015.【2014统考真题】下列程序段的时间复杂度是( )。
count=0;
for (k=1 ; k<=n ; k*=2)
    for(j=1;j<=n;j++)
        count++;
A.O(logn)        B.O(n)        C.O(nlogn)        D.O(n^2)

🍊详细题解:

✅正确答案:C


📜016.题目难度 ⭐️⭐️⭐️

016.【2017统考真题】下列函数的时间复杂度是( )。
    int func(int n){
        int i=0,sum=0;
        while (sum<n) sum +=++i;
        return i;
    }
A.O(logn)        B.O(√n)        C.O(n)        D.O(nlogn)

🍊详细题解:

✅正确答案:B


 📜017.题目难度 ⭐️⭐️⭐️

🍊详细题解:

🌕写在最后


数据结构的世界是相当丰富的,内容方向繁多,但只要一步一个脚印,跟随【水滴计划】水滴石穿吃透、搞懂、拿捏住数据结构是完全没有问题的!后期该系列还会有视频教程和经验分享,关于更多这方面的内容,请关注本专栏哦!

热爱所热爱的, 学习伴随终生,kikokingzz与你同在!❥(^_-)

有关【数据结构功法】第2话 · 一篇文章带你彻底吃透·算法复杂度的更多相关文章

  1. ruby - 解析 RDFa、微数据等的最佳方式是什么,使用统一的模式/词汇(例如 schema.org)存储和显示信息 - 2

    我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i

  2. ruby - Ruby 有 `Pair` 数据类型吗? - 2

    有时我需要处理键/值数据。我不喜欢使用数组,因为它们在大小上没有限制(很容易不小心添加超过2个项目,而且您最终需要稍后验证大小)。此外,0和1的索引变成了魔数(MagicNumber),并且在传达含义方面做得很差(“当我说0时,我的意思是head...”)。散列也不合适,因为可能会不小心添加额外的条目。我写了下面的类来解决这个问题:classPairattr_accessor:head,:taildefinitialize(h,t)@head,@tail=h,tendend它工作得很好并且解决了问题,但我很想知道:Ruby标准库是否已经带有这样一个类? 最佳

  3. ruby - 我如何添加二进制数据来遏制 POST - 2

    我正在尝试使用Curbgem执行以下POST以解析云curl-XPOST\-H"X-Parse-Application-Id:PARSE_APP_ID"\-H"X-Parse-REST-API-Key:PARSE_API_KEY"\-H"Content-Type:image/jpeg"\--data-binary'@myPicture.jpg'\https://api.parse.com/1/files/pic.jpg用这个:curl=Curl::Easy.new("https://api.parse.com/1/files/lion.jpg")curl.multipart_form_

  4. 世界前沿3D开发引擎HOOPS全面讲解——集3D数据读取、3D图形渲染、3D数据发布于一体的全新3D应用开发工具 - 2

    无论您是想搭建桌面端、WEB端或者移动端APP应用,HOOPSPlatform组件都可以为您提供弹性的3D集成架构,同时,由工业领域3D技术专家组成的HOOPS技术团队也能为您提供技术支持服务。如果您的客户期望有一种在多个平台(桌面/WEB/APP,而且某些客户端是“瘦”客户端)快速、方便地将数据接入到3D应用系统的解决方案,并且当访问数据时,在各个平台上的性能和用户体验保持一致,HOOPSPlatform将帮助您完成。利用HOOPSPlatform,您可以开发在任何环境下的3D基础应用架构。HOOPSPlatform可以帮您打造3D创新型产品,HOOPSSDK包含的技术有:快速且准确的CAD

  5. FOHEART H1数据手套驱动Optitrack光学动捕双手运动(Unity3D) - 2

    本教程将在Unity3D中混合Optitrack与数据手套的数据流,在人体运动的基础上,添加双手手指部分的运动。双手手背的角度仍由Optitrack提供,数据手套提供双手手指的角度。 01  客户端软件分别安装MotiveBody与MotionVenus并校准人体与数据手套。MotiveBodyMotionVenus数据手套使用、校准流程参照:https://gitee.com/foheart_1/foheart-h1-data-summary.git02  数据转发打开MotiveBody软件的Streaming,开始向Unity3D广播数据;MotionVenus中设置->选项选择Unit

  6. 使用canal同步MySQL数据到ES - 2

    文章目录一、概述简介原理模块二、配置Mysql使用版本环境要求1.操作系统2.mysql要求三、配置canal-server离线下载在线下载上传解压修改配置单机配置集群配置分库分表配置1.修改全局配置2.实例配置垂直分库水平分库3.修改group-instance.xml4.启动监听四、配置canal-adapter1修改启动配置2配置映射文件3启动ES数据同步查询所有订阅同步数据同步开关启动4.验证五、配置canal-admin一、概述简介canal是Alibaba旗下的一款开源项目,Java开发。基于数据库增量日志解析,提供增量数据订阅&消费。Git地址:https://github.co

  7. ruby-on-rails - 创建 ruby​​ 数据库时惰性符号绑定(bind)失败 - 2

    我正在尝试在Rails上安装ruby​​,到目前为止一切都已安装,但是当我尝试使用rakedb:create创建数据库时,我收到一个奇怪的错误:dyld:lazysymbolbindingfailed:Symbolnotfound:_mysql_get_client_infoReferencedfrom:/Library/Ruby/Gems/1.8/gems/mysql2-0.3.11/lib/mysql2/mysql2.bundleExpectedin:flatnamespacedyld:Symbolnotfound:_mysql_get_client_infoReferencedf

  8. STM32读取串口传感器数据(颗粒物传感器,主动上传) - 2

    文章目录1.开发板选择*用到的资源2.串口通信(个人理解)3.代码分析(注释比较详细)1.主函数2.串口1配置3.串口2配置以及中断函数4.注意问题5.源码链接1.开发板选择我用的是STM32F103RCT6的板子,不过代码大概在F103系列的板子上都可以运行,我试过在野火103的霸道板上也可以,主要看一下串口对应的引脚一不一样就行了,不一样的就更改一下。*用到的资源keil5软件这里用到了两个串口资源,采集数据一个,串口通信一个,板子对应引脚如下:串口1,TX:PA9,RX:PA10串口2,TX:PA2,RX:PA32.串口通信(个人理解)我就从串口采集传感器数据这个过程说一下我自己的理解,

  9. SPI接收数据异常问题总结 - 2

    SPI接收数据左移一位问题目录SPI接收数据左移一位问题一、问题描述二、问题分析三、探究原理四、经验总结最近在工作在学习调试SPI的过程中遇到一个问题——接收数据整体向左移了一位(1bit)。SPI数据收发是数据交换,因此接收数据时从第二个字节开始才是有效数据,也就是数据整体向右移一个字节(1byte)。请教前辈之后也没有得到解决,通过在网上查阅前人经验终于解决问题,所以写一个避坑经验总结。实际背景:MCU与一款芯片使用spi通信,MCU作为主机,芯片作为从机。这款芯片采用的是它规定的六线SPI,多了两根线:RDY和INT,这样从机就可以主动请求主机给主机发送数据了。一、问题描述根据从机芯片手

  10. 微信小程序通过字典表匹配对应数据 - 2

    前言一般来说,前端根据后台返回code码展示对应内容只需要在前台判断code值展示对应的内容即可,但要是匹配的code码比较多或者多个页面用到时,为了便于后期维护,后台就会使用字典表让前端匹配,下面我将在微信小程序中通过wxs的方法实现这个操作。为什么要使用wxs?{{method(a,b)}}可以看到,上述代码是一个调用方法传值的操作,在vue中很常见,多用于数据之间的转换,但由于微信小程序诸多限制的原因,你并不能优雅的这样操作,可能有人会说,为什么不用if判断实现呢?但是if判断的局限性在于如果存在数据量过大时,大量重复性操作和if判断会让你的代码显得异常冗余。wxswxs相当于是一个独立

随机推荐