C语言---数据结构(1)--时间复杂和空间复杂度计算

news2024/10/7 4:28:18

 





1.什么是时间复杂度和空间复杂度

1.1算法效率

算法效率分为时间效率和空间效率

时间效率被称为时间复杂度,而空间效率被称作空间复杂度。 时间复杂度主要衡量的是一个算法的运行速度,而空间复杂度主要衡量一个算法所需要的额外空间,在计算机发展的早期,计算机的存储容量很小。所以对空间复杂度很是在乎。但是经过计算机行业的迅速发展,计算机的存储容量已经达到了很高的程度。所以我们如今已经不需要再特别关注一个算法的空间复杂度,现在主要关注的是空间效率

1.2时间复杂度的概念

时间复杂度的定义:在计算机科学中,算法的时间复杂度是一个函数,它定量描述了该算法的运

行时间。一个算法执行所耗费的时间,从理论上说,是不能算出来的,只有你把你的程序放在机

器上跑起来,才能知道。但是我们需要每个算法都上机测试吗?是可以都上机测试,但是这很麻

烦,所以才有了时间复杂度这个分析方式。一个算法所花费的时间与其中语句的执行次数成正比

例,算法中的基本操作的执行次数,为算法的时间复杂度。

1.3 空间复杂度的概念

空间复杂度是对一个算法在运行过程中临时占用存储空间大小的量度 。空间复杂度不是程序占用

了多少bytes的空间,因为这个也没太大意义,所以空间复杂度算的是变量的个数。空间复杂度计

算规则基本跟实践复杂度类似,也使用大O渐进表示法。

2.如何计算常见算法的时间复杂度和空间复杂度

时间复杂度不算时间,算次数,空间复杂度不算空间,算变量个数

时间复杂度的计算

实际中我们在计算时间复杂度时,我们其实并不一定要计算精确的执行次数,只需要大概执行次数,那么我们这里就使用大O的渐进表示法

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

推导大O阶方法:

1、用常数1取代运行时间中的所有加法常数。

2、在修改后的运行次数函数中,只保留最高阶项。

3、如果最高阶项存在且不是1,则去除与这个项目相乘的常数。得到的结果就是大O阶。

使用大O的渐进表示法以后,

另外有些算法的时间复杂度存在最好、平均和最坏情况:

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

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

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

例如:在一个长度为N数组中搜索一个数据x

最好情况:1次找到

最坏情况:N次找到

平均情况:N/2次找到

在实际中一般情况关注的是算法的最坏运行情况,所以数组中搜索数据时间复杂度为O(N)

比如后面的计算strchr的时间复杂度

// 请计算一下Func1基本操作执行了多少次?
void Func1(int N)
{
    int count = 0;
    for (int i = 0; i < N; ++i)
    {
        for (int j = 0; j < N; ++j)
        {
            ++count;
        }
    }
    //对于这个循环来说,因为这是一个嵌套的循环,两层循环,外面执行N次,里面执行N次
    //所以这个循环总共执行N*N次
    for (int k = 0; k < 2 * N; ++k)
    {
        ++count;
    }
    //这个循环的循环次数是2*N
    int M = 10;
    while (M--)
    {
        ++count;
    }
    printf("%d\n", count);
}
//因为M被初始化为10,那么这个while循环会执行10次
int main()
{
    int n=0;
    scanf("%d", &n);
    Func1(n);
    return 0;

}
//所以看来这个准确的次数是:N*N+2*N+10
//F(N)=N^2+2*N+10
//N=10F(N)=130
//N=100F(N)=10210
//N=1000F(N)=1002010
//随着N的增大,这个表达式中N^2对结果的影响是最大的

//时间复杂度是一个估算,是去看表达式中影响最大的那一项

//时间复杂度用到一个
//大O的渐进表示法,估算

//时间复杂度:O(N^2)

Func1的时间复杂度为:O(N6^2)

我们会发现大O的渐进表示法去掉了那些对结果影响不大的项,简洁明了的表达了代码执行的次数

// 计算Func2的时间复杂度?
void Func2(int N)
{
    int count = 0;
    for (int k = 0; k < 2 * N; ++k)
    {
        ++count;
    }

    int M = 10;
    while (M--)
    {
        ++count;
    }
    printf("%d\n", count);
}

//2*N+10
//时间复杂度就是O(N)
//那么为什么不是O(2N)呢?

//根据大O阶推导的方法三中提到:
//3、如果最高阶项存在且不是1,则去除与这个项目相乘的常数。得到的结果就是大O阶。

//使用大O的渐进表示法以后,

//因为我们的N逐渐变大,前面的2对结果的影响不大

//所以这个题目的时间复杂度就是O(N)

我们要求去掉N前面的2,随着N的变大,前面的2对结果的影响不是很大,所以去掉

那么这个代码的时间复杂度就是O(N)

// 计算Func3的时间复杂度?
void Func3(int N, int M)
{
    int count = 0;
    for (int k = 0; k < M; ++k)
    {
        ++count;
    }
    for (int k = 0; k < N; ++k)
    {
        ++count;
    }

    printf("%d\n", count);
}

//这个代码的时间复杂度就是O(N+M)
//因为我们现在不知道N和M的大小,现在对于我都是未知数

//所以我们在计算时间复杂度的时候,可能遇到的不止一个未知数,可能有多个未知数

//一般情况下只有1个未知数的


//但是这个题如果有个条件:M远大于N,那么这个代码的时间复杂度就是O(M)

//假设M和N差不多大,那么时间复杂度就是O(M)或者O(N)

这个代码存在多个未知的值,M和N,那么这个复杂度就要根据这个M和N的大小进行比较了

// 计算Func4的时间复杂度?
void Func4(int N)//这个N我们没有用到
{
    int count = 0;
    for (int k = 0; k < 100; ++k)
    {
        ++count;
    }
    printf("%d\n", count);
}
//因为这个代码给的N我们没有用到
//那么这个代码的时间复杂度是多少呢?
//是O(1)

//为什么呢
/*
根据推导大O阶方法1我,们可以知道
1、用常数1取代运行时间中的所有加法常数。

因为这个循环的次数是100,是常数,那么我们的这个时间复杂度就用1来替换了

//那么我们最终就得到了O(1)

所以我们在以后遇到的常数次都是O(1)


不管这个常数次是多大,N永远都是不变的,N的效率是固定的*/

因为这个代码是没有用到未知数的,循环的次数仅仅只是一个常数,那么这个题的时间复杂度我们就用O(1)表示,将常量用1来替换

// 计算strchr的时间复杂度?
const char* strchr(const char* str, char character)
{
    //遍历字符串中'\0'之前的字符,
    while (*str != '\0')
    {
        if (*str == character)//将这个指针指向的字符和传过来的字符进行判断
            //如果是一样的字符,那么我们就返回这个字符的位置
            return str;

        ++str;//指针++,换下一个字符进行判断
    }

    return NULL;//走到最后都没找到,我们就直接返回一个空指针
}
//这个函数是我们在字符串里面找到我们想要的字符
//那么这个题的时间复杂度怎么说呢?
/*
* 假设这个字符串的长度是N
那么就存在三种可能性:最好、最坏、平均
最坏:就是运行N次才找到                   O(N)
平均:进行到一半才找到                    O(N/2)
最好:一个常数下,假如5次、1次就找到了    O(1)


但是在实际中一般情况关注的是算法的最坏运行情况
所以数组中搜索数据的这个题的时间复杂度是O(N)

我们做出最坏的打算,但是这里也是最靠谱的
*/



/*
做出拓展
1.我们现在给出一个字符串,是长还是短,这个字符串的长度都是不变的
那么这个题时间复杂度就是O(1),效率是不变的


2.如果时间复杂度是O(N)的话,是表达的什么呢?
N就是字符串的长度,随着字符串的变长,这个题目的效率也线性的变长了


*/

这里我们用到了最坏运行情况,在这个字符串中找了N次才找到我们想要的字符

// 计算BubbleSort的时间复杂度?
void BubbleSort(int* a, int n)
{
    assert(a);
    for (size_t end = n; end > 0; --end)
    {
        int exchange = 0;
        for (size_t i = 1; i < end; ++i)
        {
            if (a[i - 1] > a[i])
            {
                Swap(&a[i - 1], &a[i]);
                exchange = 1;
            }
        }
        if (exchange == 0)
            break;
    }
}

/*
我们先来归纳一下冒泡排序的思想:
在这个数组中,如果第一个数大于第二个数,那么就将这两个数的位置进行交换
将大的数字放后面,小的数字放前面


第一趟冒泡N
第二趟冒泡N-1
第三趟冒泡N-2

第N趟冒泡1


那么这里的次数就是首项+尾项乘以项数除以二
(N+1)*N/2=(N*N+N)/2
上面就是这道题准确的次数

但对于结果影响最大的一项是N^2,因为上面将表达式分解了,所以最大影响的是N方

那么表达就是O(N^2)


这个是阶乘,我们将阶乘的每一项加起来就是这个准确次数了

*/

这个是阶乘,我们将阶乘的每一项加起来就是这个准确次数了,

不是说一层循环就是O(N),两层循环就是O(N^2)

具体看程序,最好通过过程去分析

// 计算BinarySearch的时间复杂度?

//二分查找
//二分查找的前提是数组是有序的
int BinarySearch(int* a, int n, int x)
{
    assert(a);
    int begin = 0;
    int end = n;
    while (begin < end)
    {
        int mid = begin + ((end - begin) >> 1);
        if (a[mid] < x)
            begin = mid + 1;
        else if (a[mid] > x)
            end = mid;
        else
            return mid;
    }
    return -1;
}

/*
最好的情况:O(1)

假设找了x次
1*2*2*2*2*2.....找了多少次就乘了多少次2
最后的结果就是这整个数组的长度

2^x=N
所以次数x就是log2N--以2为底N的对数

那么对于这个题的话
算法的复杂度计算,喜欢省略写成logN,将2省略掉,因为很多地方不好写底数

有些书本,或者网上资料会写成O(lgN),严格来说这个是不对的,因为
这个底数就是10,不符合

那么时间复杂度就是O(logN)
*/
// 计算阶乘递归Factorial的时间复杂度?
//这道题实现阶乘递归
long long Factorial(size_t N)
{
    return N < 2 ? N : Factorial(N - 1) * N;
}
/*
整个次数就是1*2*3*4*5*6*7*8*9*10
就是10的阶乘
那么这个时间复杂度是多少呢?
递归调用了N次,每次递归运算是O(1)
那么整体就是O(N)
*/

常见的时间复杂度:O(N^2) O(N) O(logN) O(1)

复杂度对比

 

O(1)就是随着这个数量的增加,他是一直都是不变的

二分查找,在一个中国有14亿人中找一个人,最多找几次

31次就行 2的30次方是10亿,那么2的31次方就是20亿人

空间复杂度的计算

空间复杂度是对一个算法在运行过程中临时占用存储空间大小的量度 。空间复杂度不是程序占用

了多少bytes的空间,因为这个也没太大意义,所以空间复杂度算的是变量的个数。空间复杂度计

算规则基本跟实践复杂度类似,也使用大O渐进表示法,类似时间复杂度的方式,也是估算

总结:时间复杂度不算时间,算次数,空间复杂度不算空间,算变量个数

// 计算BubbleSort的空间复杂度?
void BubbleSort(int* a, int n)
{
    assert(a);
    for (size_t end = n; end > 0; --end)
    {
        int exchange = 0;
        for (size_t i = 1; i < end; ++i)
        {
            if (a[i - 1] > a[i])
            {
                Swap(&a[i - 1], &a[i]);
                exchange = 1;
            }
        }
        if (exchange == 0)
            break;
    }
}
/*
size_t end = n
int exchange = 0
size_t i = 1
三个变量
因为这里的3是常数,那么我们就用1将3代替
那么空间复杂度就是O(1)

循环走了N次,重复利用的是一个空间
*/
// 计算Fibonacci的空间复杂度?
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;
}
/*
size_t n
fibArray
fibArray[0] = 0;
fibArray[1] = 1;
i

这里是5个变量,但是那里有一个malloc,开辟了一个N+1个元素的数组,有n+1个
所以总共是N+6个,但是随着N的增大,6对结果的影响不大
所以这里的空间复杂度就是O(N)

大多数情况之下我们遇到的空间复杂度都是O(1)
因为变量都是常数个
*/

这里就不同了,因为我们使用malloc开辟了一个n+1个元素的空间,原本的变量就有5个,所以总共的变量就是N+6,但是6对结果的影响不大,所以这个题的空间复杂度就是O(N)

// 计算阶乘递归Factorial的空间复杂度?
long long Factorial(size_t N)
{
    return N < 2 ? N : Factorial(N - 1) * N;
}
/*
递归调用了N层,每次调用简历一个栈帧使用了常数个空间,那么每一层就是O(1)
有N个栈帧,空间复杂度就是O(N)

空间复杂度看的是我们最多的时候占了多少空间,也就是看最坏的情况之最大空间是多少


对于递归,调用时建立栈帧,返回时就会销毁栈帧

*/

空间复杂度看的是我们最多的时候占了多少空间,也就是看最坏的情况的时候我们用了最大空间是多少

复杂度计算在算法中的意义

3.有复杂度要求的算法题练习

找到消失的数字--类似单身狗问题

重点:0跟任何数异或那么得到的就是任何数

//数组nums包含从0到n的所有整数,但其中缺了一个。请编写代码找出那个缺失的整数。你有办法在O(n)时间内完成吗?
/*
思路一:给数组排序,我们现将数组排成有序数列,再进行判断,看看两个数之间相差的大小是不是1
但是不符合时间复杂度,存在问题,用快速排序的时间复杂度都是O(N*logN),那么其他的排序的时间复杂度更大了
排序直接将时间都消耗完了,所以这个题目排序是不行的


思路二:将原本不缺少数字的数组内的数字相加得到S1,再将缺少了一个数字的数字内的元素全加,得到了S2
那么S2-S1得到的就是缺少的数字


思路三:使用异或*(相同就为0,相异为1)
2^3
00000010
00000011
00000001---异或的结果

相同的数异或就是0    1^1=0   2^2=0
那么我们将两个数组内的数依次进行异或
一个数组不差数字
一个数组差一个数字
两个数组内的元素进行异或,最后出现两次的数就抵消为0,那么最后的结果就是只出现一个的那个数
*/
int missingNumber(int*nums,int numsSize)//numsSize是这个却数字的数组的元素个数
{
    int x=0;//创建变量x并赋值为0,因为0跟任何数异或得到的都是任何数
    for(int i=0;i<numsSize;i++)
    {
        x^=nums[i];//将数组内的值进行累异或
    }
    for(int j=0;j<numsSize+1;j++)//因为上面传的是一个差了一个数的数组,那么我们现在要将不差数字的那个数组进行累异或操作,所以这个数组的大小是nmusSize+1
    {
        //这里的x最开始是上面缺数字的那个数组累异或的结果
        x^=j;//从0开始累异或,0和任何数异或得到的就是那个任何数,
    }
    return x;


}

旋转数组

/*
给定一个整数数组 nums,将数组中的元素向右轮转 k 个位置,其中 k 是非负数。
输入: nums = [1,2,3,4,5,6,7], k = 3
输出: [5,6,7,1,2,3,4]
解释:
向右轮转 1 步: [7,1,2,3,4,5,6]
向右轮转 2 步: [6,7,1,2,3,4,5]
向右轮转 3 步: [5,6,7,1,2,3,4]

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

要求空间复杂度为O(1)
*/

第一种方法:

跑不过去,存在漏洞,不符合题目要求,测试用例中给了一个非常大的数字

/*
一次右旋就是将数组中最后的一个数保留,再将前面的数字往后挪一位,再把最后的那个数放到第一位

*/
void rotate(int* nums, int numsSize, int k)
{
  //当前算法时间复杂度是:O(N*K),内循环走了N次,外循环走了k次,那么总的次数就是N*K
    while(k--)
    {
        int tmp=nums[numsSize-1];//创建一个临时变量将数组中最后一个元素进行保存,总共numsSize个数,那么最后一个数下标就是numsSize-1
        for(int end=numsSize-2;end>=0;--end)//创建临时变量end,让end指向这个数组的倒数第二个元素的位置,下标就是numsSize-2
        {//循环从这个数组的倒数第二个元素开始,我们每次将数组中两个相邻的数字中的后面一位上的数字赋值为前面的数字
    //就是相当于将前面的数字往后挪了一位
            nums[end+1]=nums[end];
        }
        nums[0]=tmp;//将数组内的元素整体向后移了一位,那么第一位的数字我们就将之前赋值上的最后一位数组放过去
    //那么现在第一位上面就是上次右旋最后一位数字了
    //那么上面的代码就是第一次旋转的代码了,如果像旋转k次的话,那我们就将这个旋转一次的代码放到while循环里面去
    }
}
//但是这个方法对于这个题是跑不过的,所以我们得换方法

第二种方法:

以空间换时间

/*
思路二:以空间换时间
将数组中的后k个放到前面开,将前面的剩下的N-K个放到后面去

这种的话时间复杂度是O(N),空间复杂度是O(N),但是这样就不满足题目的要求了,题目要求空间复杂度为O(1)
*/

void rotate(int* nums, int numsSize, int k)
{

}
#include <stdio.h>

void rotate(int nums[], int n, int k) {
    // 计算实际需要轮转的位数,因为 k 可能大于数组长度
    k = k % n;
    int temp[k]; // 创建临时数组存储 k 个元素

    // 将数组的后 k 个元素存储到临时数组
    for (int i = 0; i < k; i++) {
        temp[i] = nums[n - k + i];
    }

    // 将数组的前 n-k 个元素向后移动 k 个位置
    for (int i = n - 1; i >= k; i--) {
        nums[i] = nums[i - k];
    }

    // 将临时数组中的元素复制到数组的前 k 个位置
    for (int i = 0; i < k; i++) {
        nums[i] = temp[i];
    }
}

第三种方法:

将后K个逆置,前N-K个逆置,再整体逆置

创建逆置的函数,我们再将具体的区间传上去进行逆置

/*
思路三:将后K个逆置,前N-K个逆置,再整体逆置
1   2   3   4   5   6   7
1   2   3   4   7   6   5
4   3   2   1   7   6   5         将4 5 对换位置,6 3对换位置  2 7对换位置
5   6   7   1   2   3   4----这就是旋转3步的结果
*/

/*
假设k=3
假设数组是1 2 3 4 5 6 7
我们现在要旋转k次,那么我们先旋转数组后K个
最后一个元素7的下表是N-1,那么5的下标就是N-K
将N-K到N-1这个范围的元素先进行逆置

我们再将前面剩下的N-K个元素进行逆置
数组首元素的下标是0,4的下标是N-K-1

最后我们就将整体进行逆置就好了

*/
//有可能K大于这个数组的大小,那么就会存在越界的情况,
/*
假如k是13,但是数组元素是7,那么我们应该怎么办呢?
k是13相当于我们旋转了6次,因为旋转7次相当于不变,因为旋转了7次的结果和原来是一样的,
那么我们就要进行判断,如果k>=numsSize,旋转次数大于数组元素个数的话,我们就将k的值取模
*/



void Reverse(int* nums, int left, int right)//对数组的一段区间进行逆置
{
    /*
    1 2 3 4
    1和4交换,2和3交换,最开始的left指向1,right指向4,交换完成之后,;left++,right--,再进行2和3的交换
    */
    while(left<right)
    {
        //下面的就是交换的代码
        int tmp=nums[left];
        nums[left]=nums[right];
        nums[right]=tmp;
        ++left;
        --right;
    }
}
void rotate(int* nums, int numsSize, int k)
{
    if(k>=numsSize)
    {
        k%=numsSize;
    }
   Reverse(nums,numsSize-k,numsSize-1);//先将后K个进行逆置
   Reverse(nums,0,numsSize-k-1);//将剩下的N-K个元素进行逆置
   Reverse(nums,0,numsSize-1);//将整体进行逆置
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1857062.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

麦肯锡:量子传感究竟在何处可以发光发热

量子传感技术已经提供价值&#xff0c;潜在的应用案例可以塑造多个行业。有四种核心技术具有应用前景&#xff1a;固态自旋、中性原子、超导电路和离子阱&#xff0c;它们具有在广泛的物理属性上的传感能力&#xff0c;包括磁场、电场、旋转、温度、重力、时间和压力。选择哪种…

spring cloud Alibaba 整合 seata AT模式

准备工作&#xff1a; 1、MySQL正常安装并启动 2、nacos正常部署并启动 3、下载 Seata-1.4.2 源码包和 seata-server-1.4.2 服务端源码包&#xff08;版本根据自己的需要选择&#xff0c;我这里选择1.4.2&#xff09; 下载地址&#xff1a; Seata&#xff1a;https://gite…

区间问题——905. 区间选点

目录 区间问题 定义 运用情况 注意事项 解题思路 AcWing 905. 区间选点 题目描述 运行代码 代码思路 改进思路 其它代码 代码思路 区间问题 定义 区间通常是指一个连续的范围&#xff0c;可以用数轴上的一段来表示。 运用情况 在数学中广泛用于表示变量的取值范…

【初阶数据结构】深入解析栈:探索底层逻辑

&#x1f525;引言 本篇将深入解析栈:探索底层逻辑&#xff0c;理解底层是如何实现并了解该接口实现的优缺点&#xff0c;以便于我们在编写程序灵活地使用该数据结构。 &#x1f308;个人主页&#xff1a;是店小二呀 &#x1f308;C语言笔记专栏&#xff1a;C语言笔记 &#x1…

Paimon Trino Presto的关系 分布式查询引擎

Paimon支持的引擎兼容性矩阵&#xff1a; Trino 是 Presto 同项目的不同版本&#xff0c;是原Faceboo Presto创始人团队核心开发和维护人员分离出来后开发和维护的分支&#xff0c;Trino基于Presto&#xff0c;目前 Trino 和 Presto 都仍在继续开发和维护。 Trino 生态系统-客…

YOLOv8改进 | SPPF | 具有多尺度带孔卷积层的ASPP【CVPR2018】

&#x1f4a1;&#x1f4a1;&#x1f4a1;本专栏所有程序均经过测试&#xff0c;可成功执行&#x1f4a1;&#x1f4a1;&#x1f4a1; 专栏目录 &#xff1a;《YOLOv8改进有效涨点》专栏介绍 & 专栏目录 | 目前已有40篇内容&#xff0c;内含各种Head检测头、损失函数Loss、…

基于SSM+Jsp的校园餐厅管理

开发语言&#xff1a;Java框架&#xff1a;ssm技术&#xff1a;JSPJDK版本&#xff1a;JDK1.8服务器&#xff1a;tomcat7数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09;数据库工具&#xff1a;Navicat11开发软件&#xff1a;eclipse/myeclipse/ideaMaven包…

【C语言】函数执行背后的秘密:函数栈帧的创建和销毁超详解

✨个人主页&#xff1a; 熬夜学编程的小林 &#x1f497;系列专栏&#xff1a; 【C语言详解】 【数据结构详解】 目录 1. 什么是函数栈帧 2. 理解函数栈帧能解决什么问题呢&#xff1f; 3. 函数栈帧的创建和销毁解析 3.1 什么是栈&#xff1f; 3.2 认识相关寄存器和汇编指…

感恩父爱 健康同行 宁夏康源父亲节特惠普查

父亲&#xff0c;是那道坚实的屏障&#xff0c;为孩子们挡风遮雨。父亲&#xff0c;是那颗明亮的灯塔&#xff0c;为孩子们指明前进的方向。然而岁月无情&#xff0c;随着年龄的增长&#xff0c;曾经为我们遮风挡雨的父亲如今也逐渐进入了各种疾病的高发期。感恩父爱&#xff0…

selenium前期准备

1. 驱动地址&#xff1a; a. chromedriver:https://googlechromelabs.github.io/chrome-for-testing/ b. https://registry.npmmirror.com/binary.html?pathchromedriver/ 下载好的驱动一般放在Python初始文件夹下&#xff0c;例如&#xff1a;D:\Python3.8 2. selenium原理…

USB2.0学习4--USB包结构和包类型

目录 1. USB包基本结构 1.1 SOP域&#xff08;Start Of Packet&#xff09; 1.2 SYNC域&#xff08;同步域&#xff09; 1.3 PID域&#xff08;标识域&#xff09; 1.4 地址域&#xff08;ADDR&#xff09; 1.5 帧号域&#xff08;Fram&#xff09; 1.6 数据域&#xff…

医卫兰大药学试题及答案,分享几个实用搜题和学习工具 #经验分享#笔记#知识分享

随着信息技术的快速发展&#xff0c;搜题软件应运而生&#xff0c;为大学生提供了便捷的问题解答方式。 1.滑记 你可以选择一个学习类别&#xff0c;部分学习类别包括了多个学习卡包&#xff0c;每个学习卡包提供了简介和目录&#xff0c;每个学习卡包有多张学习卡片。 里面…

如何使用MATLAB写测试(4)重复劳动?TestMethodSetup!

如何使用MATLAB写测试&#xff08;4&#xff09;重复劳动&#xff1f;TestMethodSetup&#xff01; 原文&#xff1a;如何使用MATLAB写测试&#xff08;4&#xff09;重复劳动&#xff1f;TestMethodSetup&#xff01; - 知乎 (zhihu.com) 我们来自俄罗斯的实习生是学Compute…

SmartEDA引领教育革命:创新电路设计,点亮学生实践之路!

在数字化浪潮席卷全球的今天&#xff0c;教育领域的每一次创新都牵动着无数家长与学生的心。特别是在电路设计这一复杂而有趣的领域中&#xff0c;学生们往往因为缺乏实践机会和高效工具而感到迷茫。然而&#xff0c;随着SmartEDA的横空出世&#xff0c;这一切正在悄然发生改变…

通用大模型VS垂直大模型:你更青睐哪一方?

目录 引言 背景介绍 国内外垂直大模型的发展情况 国内外通用大模型的发展情况 哪一路径更为火热&#xff1f; 能力分析 通用大模型的独特能力 垂直大模型的独特能力 两者的差异与互补 难点探究 算力的挑战 数据的挑战 算法的挑战 结论 表格总结 引言 AI大模型的战…

前端开发接单公司做到哪些点,客户才愿意把项目包给你。

作为前端外包接单公司&#xff0c;你知道客户选择和你合作都看中哪些因素吗&#xff1f;单纯是价格吗&#xff1f;未必&#xff0c;本位给大家列举7个要素&#xff0c;并对每个要素做了定位&#xff0c;大家查缺补漏吧。 作为前端外包接单公司&#xff0c;要吸引同行客户将前端…

AI儿童绘本创作

之前分享过AI儿童绘画的项目&#xff0c;但是主要问题是角色一致要花费很长的时间&#xff01; 今天发现了这款&#xff0c;非常奈斯&#xff01; 只需输入故事主题、风格、模板&#xff0c;软件就会自动创作故事内容&#xff0c;自动生成插画配图&#xff0c;自动根据模板生…

29 哈希

目录 unordered系列关联式容器底层结构模拟实现 1. unordered系列关联式容器 在c98中&#xff0c;STL提供了底层为红黑树结构的一系列关联式容器&#xff0c;在查询时效率可达到 l o g 2 N log_2N log2​N&#xff0c;即最差情况下需要比较红黑树的高度次&#xff0c;当树中…

零基础STM32单片机编程入门(一)初识STM32单片机

文章目录 一.概要二.单片机型号命名规则三.STM32F103系统架构四.STM32F103C8T6单片机启动流程五.STM32F103C8T6单片机主要外设资源六.编程过程中芯片数据手册的作用1.单片机外设资源情况2.STM32单片机内部框图3.STM32单片机管脚图4.STM32单片机每个管脚可配功能5.单片机功耗数据…

【云计算 复习】第5节 交互式分析工具Dremel(含大题)

一、概念 1.概述 &#xff08;1&#xff09;数据本身不会产生价值 只有经过分析才有可能产生价值。 &#xff08;2&#xff09;Google的Dremel是第一个在嵌套数据模型基础上实现列存储的系统。 &#xff08;3&#xff09;列存储有其便利之处&#xff0c;因为在不同列中相同位置…