数据结构与算法 五大算法

news2024/12/23 18:24:34

文章目录

1,时间复杂度与空间复杂度

2,插入排序

3,希尔排序

4,选择排序

1,单趟排序

2,选择排序PLUS版本

5,冒泡排序

6,快速排序

1,hoare版本

2,挖坑法


前言

本期将学习五种基本的排序方法,学完c语言的基本知识就可以学习这个算法思想,我们会以空间复杂度和时间复杂度来对比这几个算法,我们应该要学会这些算法的思想来帮助我们来破解一些算法的题目得出最优的解法


一,时间复杂度与空间复杂度

时间复杂度的计算(描述算法执行的时间随输入数据的规模增长而增长的变化趋势)通常用大写的字母O进行表示

计算时间复杂度的步骤如下:

1,确定基本操作:

找出算法中最关键的步骤,找到他执行的次数最多的操作(一般为循环和递归的深度)

2,计算基本操作执行的次数:

根据输入的数据的规模N,计算机基本操作执行的次数,这可能涉及到循环和递归中的操作

3,最后用O进行标记,将基本操作的执行的次数用O进行标记,忽略常数项,低阶项,保留最大项


这里我们那插入排序来举一个里子怎么计算时间复杂度即可

以最坏的情况来举例子,也就是完全逆序,循环的外层是需要执行的次数,内存循环执行的是用来移动元素来插入

最坏的打算,完全逆序

内存循环需要执行i次(i是从1~n-1)这个是随着循环次数逐步增加的,所以我们来算内存循环执行的次数就是用等差数列的公式即可,算出的答案为(n-1)n/2,我们忽略常数项和低阶项,所以得出来为n的二次方则空间复杂度则为O(N的二次方)

那为什么这个外出循环不算进去呢?这不也是有次数嘛?其实呀这个为常数时间复杂度就被忽略了,我们来学习常数时间复杂度

O(1)为常数时间复杂度,通常有着几个情况:

1,固定循环的次数,这是固定的次数

2,基本的操作,如赋值运算,四则运算,这也是固定的次数

3,访问数组的元素和列表的元素,通过索引直接访问数组和列表的元素,时间为常数,因为数组和列表元素,在内存是连续储存的,可以通过计算偏移量来访问数组的元素

4,递归调用的栈空间

5,访问哈希表

以最好的情况来举例子,顺序是完全有顺序的

我们可以知道,这个只是遍历一次的,因为后面那个去一个一个去找空根本不用找,直接就是固定在原地的,所以就是n次,所以时间复杂度就是O(N)

一般情况下插入排序不会出现这个最后的情况,哪有全是顺序的呢?所以一般都是O(n的二次方)


空间复杂度

空间复杂度是衡量一个算法在运行过程中占用存储空间大小的度量,它与时间复杂度类似,都是用来描述算法的效率,空间复杂度关注的是算法执行过程中临时占用的存储空间,通常用输入规模的函数来表示

计算空间复杂度的步骤如下:

1. 确定基本单位:首先确定算法中占用空间的基本单位,比如变量、数据结构等

2. 分析变量:分析算法中的变量,包括局部变量、全局变量等,确定它们的占用空间

3. 分析数据结构:分析算法中使用到的数据结构,如数组、链表、树、图等,确定它们的占用空间

4. 考虑递归:如果算法是递归的,需要考虑递归调用时的栈空间占用

5. 考虑输入输出:有时算法的输入输出也会影响空间复杂度,但通常不考虑输入输出本身占用的空间

6. 确定空间复杂度:将以上所有占用的空间加起来,得到算法的空间复杂度

空间复杂度通常用大O表示法来表示,例如O(1)表示常数空间复杂度,O(n)表示线性空间复杂度,O(n^2)表示平方空间复杂度等


二,插入排序

1,步骤(从小到大排序):

1.需要一个有序的数列来进行插入,所以我们默认把第一个元素视为有序的一个数列

2.取下一个元素tem,从已经排好的元素从后面往前排

3.该的元素大于tem的话那么tem就要往后面移动,知道找到比他小的元素

4.找到之后就直接插入到这个小的元素的前面


思想:

插入排序是必须需要一个有序的数列的,然后从无序的数列进行逐个在有序的数列进行插入,所以我们就默认数列里面的第一个元素为有序的数列

我们来举一个例子

这样进行逐个的插入就可以了接下来我们就来用代码实现一下


#include<stdio.h>
void InsertSort(int *arr,int n) {
	for (int i = 0; i < n-1; i++) {
		int end = i;
		int tem = arr[end + 1];
		while (end >= 0) {
			if (tem < arr[end]) {
				arr[end + 1] = arr[end];
				end--;
			}
			else
				break;
		}
		arr[end + 1] = tem;
	}
}
int main() {
	int a[6] = { 8,7,5,3,4,1};
	int n = sizeof(a)/sizeof(a[0]);
	InsertSort(a, n);
	for (int i = 0; i < 6; i++) {
		printf("%d ", a[i]);
	}
}

我们根据这个代码来看看怎么实现这个插入排序的 

对main函数的写法,想必大家都已经熟练掌握了,但是这个插入排序呢?

int end = i;
		int tem = arr[end + 1];
		while (end >= 0) {
			if (tem < arr[end]) {
				arr[end + 1] = arr[end];
				end--;
			}
			else
				break;
		}
		arr[end + 1] = tem;

1,定义:这里定义了一个end,这个是用来整有序序列最后一个值的,然后tem就是在有序数列后面那个待插入的元素

2,while循环:这里是利用end>=0来当条件,当tem小于的话则执行if语句里面的语句,这个意思就是把元素往后面移动,然后进行end--,如果不是的话,则执行else语句,注意这个插入排序是一个有序的数列,所以有一次不符合if语句的条件就可以直接跳出来了,因为后面都不符合,是有序的

3,为什么最后一个要加一个1,因为这个加一个1是在当前这个较小的元素前面进行插入,所以要+1


代码总结

1,我们需要有一个变量保留最后一项这样就方便逐个排序

2,我们用一个tem来表示这个end后面的一个元素,用这个来逐个判断

3,循环我们要知道这个前面插入的是一个有序的序列,所以我们只要if语句那个不成立,后面也就是一样的,直接跳出循环来进行赋值

4,外层循环记得要n-1


时间复杂度:

最坏的情况就是O(N的2次方),此时待排序的是逆序,或者接近逆序

最好的情况就是O(N的1次方),此时待排序的是顺序,或者接近逆序


三,希尔排序

 步骤:

这里比较抽象,我们结合图来讲,如果在网上看动图,如果没有看懂也没关系,我们来仔细分析一下

这里是希尔排序的详细解释,我们可以理解一下,这里的gep是任意取的,但是我们用一个除法,进行有规律的解更好,也很具有可读性,编写代码的时候也是十分有逻辑的,下面我们用代码实现一下这个希尔排序


#include<stdio.h>
void ShellSort(int A[],int n) {
	int gep, j, i;
	int num=0;
	for (gep = n / 2; gep <= 1; gep = gep / 2) {
		for (i = gep; gep <= n; gep++){
			if (A[i] > A[i - gep]) {
				num = A[i];
			}
			for (j = i - gep; num < A[j] && j>0; j = j - gep) {
				A[j + gep] = A[j];
				A[j] = num;
			}
		}
	}
}
int main() {
	int a[6] = { 8,7,5,3,4,1};
	int n = sizeof(a)/sizeof(a[0]);
	ShellSort(a, n);
	for (int i = 0; i < 6; i++) {
		printf("%d ", a[i]);
	}
}

这里又是一个也有很多的难点,我们逐步来分析

第一个循环是每一个gep的取值都要详细的说明,所以为什么要有规律的取gep就是因为这样的话你的代码具有很强的可读性

第二个循环是针对每一组的数据的调序的

第三个循环是利用一个插入排序来求解的,num<A[ j ]这个玩意就是如果有这个的话就是一直我那个后面进行移动元素,然后把num放到那个元素里面去


代码总结

我们子啊写这个代码的时候,我们要融入插入排序的思想,进行排序,然后有一个循环控制gep,一个循环控制每一组,一个循环控制排序

时间复杂度平均:O(N^1.3)
空间复杂度:O(1)


四,选择排序

1,单趟选择排序法

步骤:

先取一个元素,然后在其他元素里面去寻找找到最值,放到取到的元素里面

思想:

先取a[ 0 ],然后在a[ 1 ]~a[ n ]去寻找到的最值(这里看用户的需求,是按照从小到大还是从大到小,如果是从小到大就是寻找到最小值,然后把最小值放到a[ 0 ]处)

再取a[ 1 ],然后在a[ 2 ]~a[ n ]取寻找最值,然后把最值放入到a[ 1 ],然后后面就是重复上面的动作了

这个图就是十分简单了,所以这里只用理解这个思想和步骤即可


我们再来看一下代码该怎么写,用这个思想

这里有两种代码,一个是我写的,一个是网上的,我们来看看这两个代码有什么不同之处

我写的代码

#include<stdio.h>
void SelectSort(int A[],int n) {
	int k=0,i=0;
	for(k=0;k<=n-1;k++) {
		int idenx = k;
		for (i = k + 1; i <= n-1; i++) {
			if (A[i] < A[idenx]) {
				idenx = i;
			}
	      }
		int temp = A[k];
		A[k] = A[idenx];
		A[idenx] = temp;
     }
}
int main() {
	int a[6] = { 5,2,3,7,6,4};
	int n = sizeof(a)/sizeof(a[0]);
	SelectSort(a, n);
	for (int i = 0; i < 6; i++) {
		printf("%d ", a[i]);
	}
}

这个代码我就把这个思想转换到代码里面来实现了,我这里使用下角标来寻址,首先用一个外循环来定位每一个就是a【0】,a【1】等等,然后用一个内循环来寻找最小值的下角标,然后进行换值操作

这个是网上的代码

#include<stdio.h>
#include<utility>
using namespace std;
void SelectSort(int A[],int n) {
	for (int i = 0; i < n; i++) {
		int start = i;
		int min = i;
		while (start < n) {
			if (A[min] > A[start]) {
				min = start;
			}
			start++;
		}
		swap(A[i], A[min]);
	}
}
int main() {
	int a[6] = { 5,2,3,7,6,4};
	int n = sizeof(a)/sizeof(a[0]);
	SelectSort(a, n);
	for (int i = 0; i < 6; i++) {
		printf("%d ", a[i]);
	}
}

这个是利用c++这个的函数swap,这个是用来交换这个值的,我们先用start和min来存储这个下角标,然后用while循环来寻找这个i值存储到min,最后用swap来交换这个值 


我们来对代码进行一下总结,我们要用一个数组遍历这个次数,就是有n个元素,要遍历n-1次,然后再用另外一个循环来寻找这个最值的下角标,最后进行交换即可

时间复杂度:最坏情况:O(N^2)
      最好情况:O(N)
空间复杂度:O(1) 


2,选择排序PLUS版本

我们在序列中依次找到最大值和最小值,然后放入头和尾

#include<stdio.h>
#include<utility>
using namespace std;
void SelectSortPLUS(int A[],int n) {
	int begin = 0; int end = n - 1;
	while (end > begin) {
		int Maxi = begin;
		int Endi = begin;
		for (int i = begin + 1; i <= end; i++) {
			if (A[i] > A[Maxi]) {
				Maxi = i;
			}
			if (A[i] < A[Endi]) {
				Endi = i;
			}
		}
		swap(A[begin], A[Endi]);
		if (begin == Maxi) {
			Maxi = Endi;
		}
		swap(A[end], A[Maxi]);
		++begin;
		--end;
	}
}
int main() {
	int a[6] = { 5,2,3,7,6,4};
	int n = sizeof(a)/sizeof(a[0]);
	SelectSortPLUS(a, n);
	for (int i = 0; i < 6; i++) {
		printf("%d ", a[i]);
	}
}

代码总结:

我们这里定义一个 begin  end来存放这个开头和结尾,定义一个Maxi  Endi来存放这个最大值和最小值,然后要考虑一个情况,当我们把这个最小值和数组的0下角标互换之后,这个最大值如果在0那个位置,就要把Maxi的位置改为Endi,然后再进行互换 


五,冒泡排序

这个冒泡排序非常的简单,这个就是把值逐渐冒泡冒上来

由于过于简单所以直接上代码看

#include<stdio.h>
#include<utility>
using namespace std;
void SortPLUS(int A[],int n) {
	for (int i = 0; i < n - 1; i++) {
		for (int j = 0; j < n - 1 - i; j++) {
			if (A[j] > A[j + 1]) {
				int temp = A[j];
				A[j] = A[j + 1];
				A[j + 1] = temp;
			}
		}
	 }
}
int main() {
	int a[6] = { 5,2,3,7,6,4};
	int n = sizeof(a)/sizeof(a[0]);
	SortPLUS(a, n);
	for (int i = 0; i < 6; i++) {
		printf("%d ", a[i]);
	}
}

这里的冒泡排序这里的j<n-1-i,因为这里是因为没冒泡一次就是固定了一个数据,所以每次就是减少一个数据,然后进行互换值,注意这个if语句,这个if语句,里面是如果一直大于的话就一直把这个值冒泡上去,如果不是则为该j的值来进行冒泡,把最大的冒泡上去

六,快速排序 

1,hoare版本

步骤

这个是选出一个key的值(一般选最左边和最右边,也可以任意取,但是最左边和最右边更加方便)

然后定义一个begin和end,begin从左往右走,end从右往左走

然后让begin找到比key大的数字,让end找到比key小的数字进行互换,注意选取最左边,end先走,选取最右边最右边先走

我们以一个例子来分析一下这个hoare版本

这个是分析序列的方法,利用快速排序的方法,来解决这个排序的问题 ,这里就是如果取走最右边的值作为key,那么end先动,end那边都是寻找相比于key要小的数字,因为我们要有序嘛,当找到之后,begin再动,寻找到相比于key大的值,然后于end进行交换,然后呢就是在让end再动重复上述过程,知道begin于end相撞之后,就直接把相撞位置的值与key互换,然后在相撞的位置提出来,变成两个子序列,然后再对两个子序列进行重复的操作

接下来我们看代码来理解 

//快速排序   hoare版本(左右指针法)
void QuickSort(int* arr, int begin, int end)
{
	//只有一个数或区间不存在
	if (begin >= end)
		return;
	int left = begin;
	int right = end;
	//选左边为key
	int keyi = begin;
	while (begin < end)
	{
		//右边选小   等号防止和key值相等    防止顺序begin和end越界
		while (arr[end] >= arr[keyi] && begin < end)
		{
			--end;
		}
		//左边选大
		while (arr[begin] <= arr[keyi] && begin < end)
		{
			++begin;
		}
		//小的换到右边,大的换到左边
		swap(&arr[begin], &arr[end]);
	}
	swap(&arr[keyi], &arr[end]);
	keyi = end;
	//[left,keyi-1]keyi[keyi+1,right]
	QuickSort(arr, left, keyi - 1);
	QuickSort(arr,keyi + 1,right);
}

这里用到了递归,我们来仔细分析一下

这个就是递归的基准情形,在机械工业革命出版的数据结构预算法中,这个是一定要有的,要不然将陷入无线的递归,这个基准情形就是我们在平时那种的写法,让他不递归(这里是结束的条件当只有一个数字或者没有区间则直接跳出)

这个是我们根据上面那个思想来设置的变量,定义一个keyi,left,right,这里的keyi是选择左边的,所以我们的移动方式是要从右边开始,这里的left是保存值,然后让begin和end移动

这个代码我们看到end--,说明一开始的循环是先找到右边的最想只,然后里面的条件就是end>key对应的数组的值,然后下面也一样,当两个都通过循环找到了,我们就可以用这个两个下架表通过swap函数来进行交换了

这个代码就是把相撞的那个值与key进行互换,但是这个key为什么要等于end呢,就是我们我们在递归的时候就更加具有可读性,而且也把我们的思想体现出来,因为我们是根据key来分左右子序列的,我们来看,一开始的把left存进去,key-i存进去,这个就是一个左边一个右边,那么下面那个也是一样的,这个就可以对子序列进行操作了

代码总结:这个就是我们先要存储这个left和right这样递归才可以找到对应的值,然后利用begin和end来进行移动找值,需要注意的就是begin先动还是left先动然后再进行互换值,直到相撞之后与key互换值,然后注意递归的写法即可


挖坑法就是多练一个变量而已,就是把a[ 0 ]空出来了用来存放值,然后不断的进行互换

//快速排序法  挖坑法
void QuickSort1(int* arr, int begin, int end)
{
	if (begin >= end)
		return;
	int left = begin,right = end;
	int key = arr[begin];
	while (begin < end)
	{
		//找小
		while (arr[end] >= key && begin < end)
		{
			--end;
		}
		//小的放到左边的坑里
		arr[begin] = arr[end];
		//找大
		while (arr[begin] <= key && begin < end)
		{
			++begin;
		}
		//大的放到右边的坑里
		arr[end] = arr[begin];
	}
	arr[begin] = key;
	int keyi = begin;
	//[left,keyi-1]keyi[keyi+1,right]
	QuickSort1(arr, left, keyi - 1);
	QuickSort1(arr, keyi + 1, right);
}

我们也来分析一下吧

这个就是基准情形和一些变量的定义,这个key存储了arr[ begin ],那么arr[ begin ]那么这个就是一个坑位了

这里无非就是,先end起手,因为从左边开始的,找到之后把end放入坑里面(a[ 0 ]),放入后后面再到begin找到,找到之后就是把begin放到end里面去,这个时候begin开始空了然后再去end里面找较小的值,找到放入到begin中,然后begin开始找,找到之后放入end里面,这个过程始终是有一个坑的,然后就是相撞之后,把key填入到那个坑即可


总结

我们学习了各种各样的算法来解决问题,我们要熟练掌握每个方法

1,插入排序就是要的一个end来逐步的进行元素的下角标的减少,然后根据end+1来进行插入,这里需要注意的是前面为有序的数列

2,希尔排序就是要gep,外围的循环就是要用来gep的计算,内部的循环就是第一个是要用来分组的用gep,然后最后一个循环就是一个插入排序,这里的for循环写入一个a[j]>num,这个是由于前面为有序的序列,然后里面就是就是要不断的推进与赋值

3,选择排序就是要有一个起始的下角标,然后用循环找到最值的下角标,然后进行互换即可,PLUS版本就是多了一个if和一个判断如果最值在最开始的地方的话就要取走end的值

4,冒泡排序就是要逐步冒泡上去注意第二个循环要-i,把固定的元素给减掉,if语句的互换是可以判断最值的,因为在排序的过程中,我们如果符合if语句就一定暂时是最值,不成立,下一次就是另外一个了

5,快速排序就是要把那个key学会找和begin和end是怎么移动的,所以我们要好好理解这个begin和end是怎么进行移动的才可以正确理解这个

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

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

相关文章

数据链路层总结

- - 链路、物理链路&#xff1a;两节点间物理线路&#xff08;有线、无线&#xff09;&#xff0c;中间没有任何其他的交换节点 数据链路、逻辑链路&#xff1a; 链路 协议需要的硬件、软件 网络适配器(网卡)&#xff1a;包含物理层、数据链路层 网络适配器软件驱动程…

入门pytorch-Transformer

前言 虽然Transformer是2017年由Google推出&#xff0c;如果按照读论文只读近两年的思路看&#xff0c;那它无疑是过时的&#xff0c;但可惜的是&#xff0c;目前很多论文的核心依然是Transformer&#xff0c;或者由其进行改进的&#xff0c;故本文使用pytorch来搭建一下Trans…

PHP中GD库的使用

由于我要用到php的验证码 <?php session_start();// 生成验证码 $random_code substr(md5(uniqid(mt_rand(), true)), 0, 6);// 将验证码保存到 session 中 $_SESSION[captcha] $random_code;// 创建图片 $font 6; $image_width 100; $image_height 40;// 创建图像 $…

【OpenCV】图像转换

理论 傅立叶变换用于分析各种滤波器的频率特性。对于图像&#xff0c;使用 2D离散傅里叶变换&#xff08;DFT&#xff09; 查找频域。快速算法称为 快速傅立叶变换&#xff08;FFT&#xff09; 用于计算DFT。 Numpy中的傅立叶变换 首先&#xff0c;我们将看到如何使用Numpy查…

ThingsBoard规则链节点:RabbitMQ 节点详解

ThingsBoard 是一个开源的物联网平台&#xff0c;允许开发者快速构建IoT产品。它提供了设备连接、数据收集、处理和可视化等功能。为了实现高效的数据处理和消息传递&#xff0c;ThingsBoard 集成了多种消息队列服务&#xff0c;其中就包括了RabbitMQ。 RabbitMQ 是一个广泛使用…

健康管理系统(Koa+Vue3)

系统界面(源码末尾获取) 系统技术 Vue3 Koa Nodejs Html Css Js ....... 系统介绍 系统比较简单,轻轻松松面对结业课堂作业.采用的是基于nodejs开发的Koa框架作为后端,采用Vue框架作为前端,完成快速开发和界面展示. 系统获取 啊啊啊宝/KoaVue3https://gitee.com/ah-ah-b…

Muduo 网络库 入门详解

文章目录 1. 什么是 Muduo 网络库&#xff1f;2. Muduo 的核心架构2.1 EventLoop2.2 Channel2.3 Poller2.4 TimerQueue2.5 TcpServer 和 TcpConnection架构图 3. Muduo 的工作原理4. 部分组件介绍4.1 ProtobufCodec4.2 ProtobufDispatcher4.3 muduo::net::EventLoop4.4 muduo::…

Scratch游戏推荐 | 磁铁与磁场原理模型——探索科学的奥秘!

今天为大家推荐一款既有趣又富有教育意义的Scratch互动作品——《磁铁与磁场原理模型》&#xff01;由ps49student503-25制作&#xff0c;这款作品通过直观的方式展示了磁铁和磁场的相互作用&#xff0c;帮助玩家深入了解磁场的方向与强度。快来拖动磁铁&#xff0c;观察磁场如…

汽车总线协议分析-CAN总线

随着汽车工业的发展&#xff0c;汽车各系统的控制逐步向自动化和智能化转变&#xff0c;汽车电气系统变得日益复杂。许多车辆设计使用CAN、CAN-FD、LIN、FlexRay或SENT在电子控制单元(ECU)之间以及ECU与传感器&#xff0c;执行器和显示器之间进行通信。这些ECU之间的通信允许车…

十四、Pod的升级和回滚

当集群中的某个服务需要升级时,我们需要停止目前与该服务相关的所有Pod,然后下载新版本镜像并创建新的Pod。如果集群规模比较大,则这个工作变成了一个挑战,而且先全部停止然后逐步升级的方式会导致较长时间的服务不可用。Kubernetes提供了滚动升级功能来解决上述问题。 如…

Redis篇-1--入门介绍

1、Redis概述 ‌Redis&#xff08;Remote Dictionary Server&#xff09;&#xff0c;全称为远程字典服务。‌是一个开源的、使用C语言编写的、支持网络交互的、可基于内存也可持久化的Key-Value数据库。 Redis提供了多种数据类型的存储&#xff0c;来适应不同场景下的存储需…

游戏引擎学习第35天

开场介绍 今天的任务是继续改进一个虚拟的瓦片地图系统&#xff0c;使其适合处理更大的世界。我们希望这个系统能管理大范围的游戏世界&#xff0c;其中包含按需存储的小区域。昨天&#xff0c;我们介绍了“内存区域”的概念&#xff0c;用于管理持久性存储。我们计划今天继续…

Apache Echarts和POI

目录 Apache ECharts 介绍 入门 绘制一个简单的图表 Apache POI 介绍 通过POI创建Excel文件并且写入文件内容 通过POI读取Excel文件中的内容 导出Excel表格 Apache ECharts 介绍 Apache ECharts 是一款基于 Javascript 的数据可视化图表库&#xff0c;提供直观&#xf…

怎么配置点击deploy就能把jar包直接打到nexus私库上,以及怎么配置从私库下载jar包

一.怎么配置点击deploy就能把jar包直接打到nexus私库上 方式一:在pom文件配置私库地址 1.第一步&#xff0c;在pom文件配置仓库地址&#xff0c;用于 deploy 上传 releases 对应正式版的仓库 snapshots 对应快照版的仓库 如果你打的jar包是以 -SNAPSHOT 结尾的, 那么就会…

基于最新的Apache StreamPark搭建指南

一、StreamPark 的介绍 官方文档:Apache StreamPark (incubating) | Apache StreamPark (incubating) 中文文档:Apache StreamPark (incubating) | Apache StreamPark (incubating)Github地址:https://github.com/apache/incubator-streampark Apache StreamPark™ 是一个…

数字IC后端实现常见的physical only cell都有哪些?如何添加这些cell?

数字IC后端实现阶段常见功能cell有哪些&#xff1f;比如AND&#xff0c;AOI&#xff0c;NAND等。 physical cell有哪些&#xff1f;都是干什么用的&#xff1f; 数字后端零基础入门系列 | Innovus零基础LAB学习Day9 &#xff08;1&#xff09; well tap cells&#xff1a;防止…

Promise详解-1:初识Promise

最近在回顾ES6的知识&#xff0c;想整理下跟Promise相关的内容。我准备整一个Promise解读的系列&#xff0c;看看能深入到什么程度吧。由浅入深&#xff0c;先认识下Promise。 痛苦的回忆&#xff1a;回调地狱 假如现在让你维护一个“古老”的项目&#xff0c;缺少脚手架的加…

【css】基础(一)

本专栏内容为&#xff1a;前端专栏 记录学习前端&#xff0c;分为若干个子专栏&#xff0c;html js css vue等 &#x1f493;博主csdn个人主页&#xff1a;小小unicorn ⏩专栏分类&#xff1a;css专栏 &#x1f69a;代码仓库&#xff1a;小小unicorn的代码仓库&#x1f69a; &a…

共享GitLab中CICD自动生成的软件包

0 Preface/Foreword 1 分享软件包地址 为了方便给接收对象方便下载固件&#xff0c;在下载固件时候&#xff0c;而无需打开网页&#xff0c;直接输入地址&#xff0c;弹出的对话框是将固件另存为。 或者进入CICD页面&#xff0c;找到job&#xff0c;在Download的标签上单击右键…

【云贝教育Linux技术文章】CentOS停止维护后如何获取redhat 8.0 yum源?详细操作指南!

本文为云贝教育 刘老师 原创&#xff0c;请尊重知识产权&#xff0c;转发请注明出处&#xff0c;不接受任何抄袭、演绎和未经注明出处的转载。 众所周知&#xff0c;centos 7 在2024年6月30日&#xff0c;生命周期结束&#xff0c;官方不再进行支持维护&#xff0c;而很多环境一…