数据结构排序篇上

news2025/6/8 3:36:00

排序的概念及其运用

排序的概念

排序 :所谓排序,就是使一串记录,按照其中的某个或某些关键字的大小,递增或递减的排列起来的操作。
稳定性 :假定在待排序的记录序列中,存在多个具有相同的关键字的记录,若经过排序,这些记录的相对次
序保持不变,即在原序列中, r[i]=r[j] ,且 r[i] r[j] 之前,而在排序后的序列中, r[i] 仍在 r[j] 之前,则称这种排
序算法是稳定的;否则称为不稳定的。
内部排序 :数据元素全部放在内存中的排序。
外部排序 :数据元素太多不能同时放在内存中,根据排序过程的要求不能在内外存之间移动数据的排序。

排序的运用 

 

 常见的排序

 插入排序:直接插入排序

先写直接插入排序。

直接插入排序是一种简单的插入排序法,其基本思想是:
把待排序的记录按其关键码值的大小逐个插入到一个已经排好序的有序序列中,直到所有的记录插入完为 止,得到一个新的有序序列
实际中我们玩扑克牌时,就用了插入排序的思想

一下子写排序是不可取的,排序这个部分,先写单趟,后写整体。

就比如说,我有0~end个数据的下标,我想把该数组外的end+1下标的值插入到现有数据。end在哪里我不清楚,这里只是假设,这里单趟的核心思想就是把一个数往前面的有序区间插入。这里的0~end肯定是有序的。注意注意,这里的end是什么我们并不知道。

这里已经有一个有序区间了。然后我把后一个值往前面插入。

2比5小,所以5得往后挪动,但是一挪动就会覆盖2,所以得先把2存起来。将2保存在一个变量中。比5小挪动,end减减,比3小挪动,end减减,比1大,就放到1的后面。假如要插入的不是2了,而是0,那我还是比1小,1往后挪动,我end减减,然后把0插入在end的后面,所以结束条件为end=-1;

总结:无论哪一种情况,都是放在end的后面。

//单趟插入排序
void InsertSort(int* a, int n)
{
	int end=0;
	int tmp = a[end + 1];
	while (end >= 0)
	{
		if (tmp < a[end])
		{
			a[end + 1] = a[end];
			--end;
		}
		else
		{
			break;
		}
	}
	//这里切记end要加1,否则会出问题,因为我们之前移动后,立马end减去1了。
	a[end + 1] = tmp;
}

上图是完成了一趟了

这个循环有两个出去的条件,一个是你比end对应的值大于或者等于就break跳出,还有end小于0就结束,就是所有的值都比你目标值大,就一直挪动,挪到end等于-1,就将目标值插入到end的后面。这就是一趟走的整体思路。

完成了一趟的数据后,我们就开始写次数来完善程序。

这里我们把end给为0,就想当然把0当成有序,然后继续来走。

所以给的end的其实位置就是0.所以在循环里,这里就给i。

end为0时,即第一个数据有序,end后的数据开始插入,以此类推。

end的结束位置在数组最后位置的前一个。即有n个数据,那么最后一个数据的下标为n-1,再往前就是n-2;

因为这里要经常打印数组,所以这里就写一个相应的函数。

void PrintArray(int* a, int n)
{
	for (int i = 0; i < n; i++)
	{
		printf("%d ", a[i]);
	}
	printf("\n");
}

分析时间复杂度

写代码时,要对其的思路逻辑清楚一点,否则会出现问题。

一定要学会单趟套整体。

这个直接插入排序的时间复杂度为多少?千万不要说两层循环n的平方。简单排序看层数是没问题的。但是排序这里看循环层数来判断n的平方是不对的。判断时间复杂度要看思想。

这个直接插入排序,逆序的时候,时间复杂度是最坏的。就是第一个数有序,第二个数插入一次,第三个数两次,就是等差数列。就是得全部挪动一遍。所以也就是1~n-1,也就是n的平方。

呃呃呃,虽然这个程序是n的平方,但是切记看思想来判断。

这是最坏情况,我们再看一下最好情况,即顺序。就是0(n),就是遍历了一遍。或者说接近有序,这个最好情况再顺序有序或者接近有序时成立。

为什么最好是0(n)呢?就是我给你一个数组,你是不知道他是是否有序的。你不知道他是否有序。没有排序可以做到0(1),最快的排序就是接近0(n)的。当然在一些比较局限的场景里可以做到0(n)。常见的排序n*log(n)就是最好的了。

交换排序:冒泡排序

体现素养的小细节:

写个冒泡,呜呜,遇到友人了。

BubbleSort.(命名要规范,否则面试出大问题)。

规范:代码里面不要有拼音,除非没有对应的单词。这个关乎面试官对你的代码素养。

冒泡排序 是一种交换思想,如果前一个大于后一个就交换,这样以来,一轮之后,最大的值就到最后了。然后再前一个根后一个交换,把次大的值换到倒数第二个位置了。

我们还按照先写单趟,再写整体。

这里先写一个交换函数,因为之后可以复用。

//单趟冒泡排序
void Swap(int* p1, int* p2)
{
	int tmp = *p1;
	*p1 = *p2;
	*p2 = tmp;
}

void BubbleSort(int* a, int n)
{
	for (int i = 1; i < n; i++)
	{
		if (a[i - 1] > a[i])
		{
			Swap(&a[i - 1], &a[i]);
		}
	}
}

代码比的是细节。要控制住细节。如果你觉得细节控制的不是太好,那一定是画图画少了。

这里for循环条件也可以给i为0,这样接得写i<n-1了,这样得控制尾部的结束条件了。当然,怎么写都是可以的。

我们这样写的就是一前一后进行交换。

到这里第一次记冒好了,第一次就确定了最大值,所以第二趟就冒到n-1就行了。当<1时,冒泡就结束。所以一共冒泡n-1次就行。

void Swap(int* p1, int* p2)
{
	int tmp = *p1;
	*p1 = *p2;
	*p2 = tmp;
}

void BubbleSort(int* a, int n)
{
	for (int j = 0; j < n - 1; j++)
	{
		for (int i = 1; i < n; i++)
		{
			if (a[i - 1] > a[i])
			{
				Swap(&a[i - 1], &a[i]);
			}
		}
	}
}

 这里第一层次数循环是到n-2结束,第二层for循环进行每一次需要的趟数到小于n-(n-2)结束,即小于2就结束,也就是到1,我们分析就是到1就继续,正好0和1那里比较了,然后就结束,思路是这样的。

到这里,冒泡就写好了,但是其实还是可以优化的。

冒泡空间有可优化的空间,就是顺序可能或者基本有序,就不冒一趟没有发现数据交换,就不用再继续走了,这里给个标志。

void BubbleSort(int* a, int n)
{
	for (int j = 0; j < n - 1; j++)
	{
		int exchange = 0;

		for (int i = 1; i < n; i++)
		{
			if (a[i - 1] > a[i])
			{
				Swap(&a[i - 1], &a[i]);
				exchange = 1;
			}
		}

		if (exchange == 0)
			break;
	}
}

冒泡排序的时间复杂度是n的平方。这个时候的最坏的情况不是说逆序了,逆序只是其中一种情况,不一定是逆序,很多情况都是n的平方。最好的顺序就是接近有序从而达到0(n)。

它和插入排序看起来没什么区别,但其实不一样。

冒泡排序的特性总结:
1. 冒泡排序是一种非常容易理解的排序
2. 时间复杂度: O(N^2)
3. 空间复杂度: O(1)
4. 稳定性:稳定

 对比直接插入排序和冒泡排序

// 测试排序的性能对比
void TestOP()
{
	srand(time(0));
	//开100000个空间
	const int N = 100000;
	int* a1 = (int*)malloc(sizeof(int) * N);
	int* a2 = (int*)malloc(sizeof(int) * N);
	int* a3 = (int*)malloc(sizeof(int) * N);
	int* a4 = (int*)malloc(sizeof(int) * N);
	int* a5 = (int*)malloc(sizeof(int) * N);
	int* a6 = (int*)malloc(sizeof(int) * N);
	//每个数组放一样的数
	for (int i = 0; i < N; ++i)
	{
		a1[i] = rand();
		a2[i] = a1[i];
		a3[i] = a1[i];
		a4[i] = a1[i];
		a5[i] = a1[i];
		a6[i] = a1[i];
	}
	//计算时间
	int begin1 = clock();
	InsertSort(a1, N);
	int end1 = clock();
	int begin2 = clock();
	BubbleSort(a2, N);
	int end2 = clock();
	/*int begin3 = clock();
	SelectSort(a3, N);
	int end3 = clock();
	int begin4 = clock();
	HeapSort(a4, N);
	int end4 = clock();
	int begin5 = clock();
	QuickSort(a5, 0, N - 1);
	int end5 = clock();
	int begin6 = clock();
	MergeSort(a6, N);
	int end6 = clock();*/
	printf("InsertSort:%d\n", end1 - begin1);
	printf("BubbleSort:%d\n", end2 - begin2);
	/*printf("SelectSort:%d\n", end3 - begin3);
	printf("HeapSort:%d\n", end4 - begin4);
	printf("QuickSort:%d\n", end5 - begin5);
	printf("MergeSort:%d\n", end6 - begin6);*/
	free(a1);
	free(a2);
	/*free(a3);
	free(a4);
	free(a5);
	free(a6);*/
}
int main()
{
	/*int a[] = { 5,4,3,2,1 };
	BubbleSort(a, sizeof(a) / sizeof(a[0]));
	PrintArray(a, sizeof(a) / sizeof(a[0]));*/
	TestOP();

	return 0;
}

malloc个多个数组,产生一个随机值。然后将数组1赋值给别的数组,就是说这6个数组的值都是一样的。 

这里begin减去end就是排序所消耗的时间。

clock是电脑运行启动到调用这个函数是所消耗的毫秒数,所以两个clock之差就是中间的排序消耗掉的时间。

这里进行测试时,debug可能优化没有全开,测性能用release。

下图是realease的。

跑十万个值进行的比较。

所以明显的感觉到这两个不一样。不能单看时间复杂度来看这里的问题。

时间复杂度用来算他是属于哪一个量级的。这两个属于同一个档次的排序。同一个学校,是统一档次,但出来的不同同学有不同。

所以不能单一时间复杂度来评估。

选择排序:堆排序

堆排序 (Heapsort) 是指利用堆积树(堆)这种数据结构所设计的一种排序算法,它是选择排序的一种。它是
通过堆来进行选择数据。 需要注意的是排升序要建大堆,排降序建小堆。

 

 

直接选择排序的特性总结:
1. 堆排序使用堆来选数,效率就高了很多。
2. 时间复杂度: O(N*logN)
3. 空间复杂度: O(1)
4. 稳定性:不稳定

 

void HeapSort(int* a, int n)
{
	//a数组直接建堆 0(N)
	for (int i = (n - 1 - 1) / 2; i >= 0; --i)
	{
		AdjustDown(a, n, i);
	}

	//O(N*logN)
	int end = n - 1;
	while (end > 0)
	{
		Swap(&a[0], &a[end]);
		AdjustDown(a, end, 0);
		printf("%d ", a[end]);
		--end;
	}
	printf("%d", a[0]);
}
int main()
{
	int a[] = { 5,4,3,2,1 };
	HeapSort(a, sizeof(a) / sizeof(a[0]));
	//PrintArray(a, sizeof(a) / sizeof(a[0]));
	//TestOP();

	return 0;
}

 

排序和排序直接真的有差距啊。

插入和冒泡属于同一类,但效率差很多的重要的点在,插入具有很强的适应性。

冒泡不再冒的条件是很苛刻的,就是不能有任何一个交换,没有一个条件交换,就是已经有序了,这个条件是很难达成的。

插入的适应性在哪里呢?只要由一个靠后的数据比前面数据都小,那就挪动n次。但是这是非常极端的,一般来说这个数据可能在偏中间一点的位置,即只挪动了一半的数据就达到了目的。

 

这个堆冒泡是常态,但对于插入排序来说,他只要每个数据都要挪满时才会出现这种情况。但是对插入排序来说,他的中间或许可能会局部有序,他不需要;一直挪。随机的场景更多的是局部有序。

时间复杂度不在同一个量级就没有可比性,在同一个量级的也有差异。冒泡在随机数是都是比满。

插入排序:希尔排序

 

希尔觉得插入排序非常的不错,如果有序接近有序,插入有序就非常nb了。它要改革直接插入排序。如果能把数据接近有序,那就很快乐。

所以他分为两个步骤:

预排序 目标:接近有序;

他觉得你挪动的太慢了。它想让挪动的快一些。也就是分组插入排序。目标:大的更快换到后面的位置,小的数更快换到前面的位置。

就是以gap为间距来一一分组。

希尔排序法又称缩小增量法。希尔排序法的基本思想是: 先选定一个整数,把待排序文件中所有记录分成个
组,所有距离为的记录分在同一组内,并对每一组内的记录进行排序。然后,取,重复上述分组和排序的工
作。当到达 =1 时,所有记录在统一组内排好序

 

希尔排序的特性总结:
1. 希尔排序是对直接插入排序的优化。
2. gap > 1 时都是预排序,目的是让数组更接近于有序。当 gap == 1 时,数组已经接近有序的了,这样就 会很快。这样整体而言,可以达到优化的效果。我们实现后可以进行性能测试的对比。
3. 希尔排序的时间复杂度不好计算,因为 gap 的取值方法很多,导致很难去计算,因此在好些树中给出的 希尔排序的时间复杂度都不固定

 《数据结构(C语言版)--- 严蔚敏

 《数据结构-用面相对象方法与C++描述》--- 殷人昆

稳定性:不稳定

 

预排序和原数组相比: 

 

他有序了一点,但不是很多。

我们先写单趟。

我们接下来以下图这个数组为例开始排

 

//单次希尔排序
void ShellSort(int* a, int n)
{
	int gap = 3;
	int end=0;
	int tmp = a[end + gap];
	while (end >= 0)
	{
		if (tmp < a[end])
		{
			a[end + gap] = a[end];
			end -= gap;
		}
		else
		{
			break;
		}
	}
	a[end + gap] = tmp;
}

比完5和2了,然后比5和3时,不是上述代码,写的,得先在上图再套一层才能写,这里先继续写。

这里跟插入排序很像,无非就是将加1换成了加gap。

刚才完成的只是把一个数往前插入,如果我们要排一组数据,那么该如何排。

 for(int i=0;i<n;i+=gap)

 上图这里再套一层循环。但是这里有问题,如果i等于在5的位置时(即进行了交换之后),再加上gap来进入循环,这个时候就越界了。

所以外层循环应该写为上图:

这个时候就帮助我们帮红色这一组就排完了,但是我们想排整体,该如何呢?间距为gap,就有gap组。gap是几就有几组。所以再次套一层循环。

//一个gap进行的希尔排序
void ShellSort(int* a, int n)
{
	int gap = 3;
	for (int i = 0; i < n-gap; i += gap)
	{
		int end=i;
		int tmp = a[end + gap];
		while (end >= 0)
		{
			if (tmp < a[end])
			{
				a[end + gap] = a[end];
				end -= gap;
			}
			else
			{
				break;
			}
		}
		a[end + gap] = tmp;
	}
}

所以外层循环应该写为上图:

这个时候就帮助我们帮红色这一组就排完了,但是我们想排整体,该如何呢?间距为gap,就有gap组。gap是几就有几组。所以再次套一层循环。

//完整的希尔排序
void ShellSort(int* a, int n)
{
	int gap = 3;
	for (int j = 0; j < gap; j++)
	{
		for (int i = 0; i < n - gap; i += gap)
		{
			int end = i;
			int tmp = a[end + gap];
			while (end >= 0)
			{
				if (tmp < a[end])
				{
					a[end + gap] = a[end];
					end -= gap;
				}
				else
				{
					break;
				}
			}
			a[end + gap] = tmp;
		}
	}
}

总结一下:希尔排序分为预排序他的目的是分组插入排序

预排序的目标是:大的更快换到后面的位置,小的数更快换到前面的位置。

到这里,其实上图完整的希尔排序也可以简化为2层。

void ShellSort(int* a, int n)
{
	int gap = 3;
	/*for (int j = 0; j < gap; j++)
	{
		for (int i = 0; i < n - gap; i += gap)
		{*/
	for (int i = 0; i < n - gap; i++)
	{
		int end = i;
		int tmp = a[end + gap];
		while (end >= 0)
		{
			if (tmp < a[end])
			{
				a[end + gap] = a[end];
				end -= gap;
			}
			else
			{
				break;
			}
		}
		a[end + gap] = tmp;
	}
	/*	}
	}*/
}

希尔排序是初始的是什么呢,是一组排完排另一组。是排完红色,再排绿色,再排紫色。

一组一组排。

但是按照上图来说,先比较换了2和5,然后不一整组一整组比较,而是最外层的i++。这个方法是gap组数据,交替完成分组插入排序。

gap大于1就是预排,等于1就是快速排序。gap越大,数据跳的越快,大的更快到前面为止,小的更快到后面,但是越不接近有序。

gap越小,数据跳的越慢,但是越接近有序,gap==1就是插入后就是有序。

 

继续深入;

这里还有人怎么给呢?到这里就已经变为怎么给gap了。

 这样就能控制gap了,我第一次间距给上50,gap大不接近有序,没关系啊,我gap在缩小,我除以2最后一趟一定是1.

 

这里希尔排序每一组都在接近有序。

呜呜呜呜,开始这个排序让你爱答不理,最后让我高攀不起。呜呜呜呜!

 

有人觉得除3更好,但是除3不能保证最后余数为1.
代码能力是练出来的。需要消化的数据才是有含量的。

若有收获,就点个赞吧

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

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

相关文章

分类预测 | Matlab实现基于迁移学习和GASF-CNN-Mutilhead-Attention格拉姆角场和卷积网络多头注意力机制多特征分类预测/故障识别

分类预测 | Matlab实现基于迁移学习和GASF-CNN-Mutilhead-Attention格拉姆角场和卷积网络多头注意力机制多特征分类预测/故障识别 目录 分类预测 | Matlab实现基于迁移学习和GASF-CNN-Mutilhead-Attention格拉姆角场和卷积网络多头注意力机制多特征分类预测/故障识别分类效果基…

动态规划原理及其在优化问题中的应用解析

动态规划原理及其在优化问题中的应用解析 一、最优子结构二、重叠子问题三、何时使用动态规划法四、伪代码示例五、C代码示例七、详细说明动态规划原理7.1、最优子结构7.2 重叠子问题7.3 动态规划的实现 八、结论 动态规划是一种解决优化问题的方法&#xff0c;它通过将原问题分…

神经网络--反向传播算法推导

神经网络–反向传播算法推导 文章目录 神经网络--反向传播算法推导概述神经网络模型反向传导算法 概述 以监督学习为例&#xff0c;假设我们有训练样本集 ( x ( i ) , y ( i ) ) (x^{(i)},y^{(i)}) (x(i),y(i))&#xff0c;那么神经网络算法能提供一种复杂且非线性的假设模型 …

滚雪球学Java(75):Java零基础,轻松学会文件读写技巧

咦咦咦&#xff0c;各位小可爱&#xff0c;我是你们的好伙伴——bug菌&#xff0c;今天又来给大家普及Java SE相关知识点了&#xff0c;别躲起来啊&#xff0c;听我讲干货还不快点赞&#xff0c;赞多了我就有动力讲得更嗨啦&#xff01;所以呀&#xff0c;养成先点赞后阅读的好…

mp3怎样才能转换成wav格式?音频互相转换的方法

一&#xff0c;什么是WAV WAV&#xff0c;全称为波形音频文件&#xff08;Waveform Audio File Format&#xff09;&#xff0c;是一种由微软公司和IBM公司联合开发的音频文件格式。自1991年问世以来&#xff0c;WAV格式因其无损的音频质量和广泛的兼容性&#xff0c;成为了多…

【Godot4.2】CanvasItem绘图函数全解析 - 7.自定义节点TextBoard

概述 之前发布的几篇文章几乎阐述了CanvasItem绘图函数最基础的内容。 本篇结合draw_style_box()和TextParagraph类&#xff0c;自定义了一个可以自适应宽高显示多行文本&#xff0c;且带有一个样式盒作为背景的文字板节点TextBoard。 系列目录 0.概述1.绘制简单图形2.设定绘…

kali工具----域名IP及路由跟踪

域名IP及路由跟踪 测试网络范围内的IP地址或域名也是渗透测试的一个重要部分。通过测试网络范围内的IP地址或域名&#xff0c;确定是否有人入侵自己的网络中并损害系统。不少单位选择仅对局部IP基础架构进行渗透测试&#xff0c;但从现在的安全形势来看&#xff0c;只有对整个I…

RHCE--dns正反向解析小实验

一、准备工作 1.关闭防火墙 [rootserver ~]# setenforce 0 [rootserver ~]# systemctl stop firewalld 2.安装软件 [rootserver ~]# yum install bind -y 二、正向解析 服务端IP客户端IP网址192.168.203.128192.168.203.130www.openlab.com 服务端配置静态ip [root…

人工智能|机器学习——基于机器学习的信用卡办卡意愿模型预测项目

一、背景介绍 在金融领域&#xff0c;了解客户的信用卡办卡意愿对于银行和金融机构至关重要。借助机器学习技术&#xff0c;我们可以根据客户的历史数据和行为模式预测其是否有办理信用卡的倾向。本项目通过Python中的机器学习库&#xff0c;构建了两个常用的分类模型&#xff…

Mistral AI突围:开源大模型Mixtral 8x22B颠覆行业格局

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

Spark-Scala语言实战(16)

在之前的文章中&#xff0c;我们学习了三道任务&#xff0c;运用之前学到的方法。想了解的朋友可以查看这篇文章。同时&#xff0c;希望我的文章能帮助到你&#xff0c;如果觉得我的文章写的不错&#xff0c;请留下你宝贵的点赞&#xff0c;谢谢。 Spark-Scala语言实战&#x…

开发板仿真网站(wokwi)初次上手指南(Arduino UNO项目)

在本篇文章中将详细介绍在开发板仿真网站&#xff08;wokwi&#xff09;上实现Arduino UNO控制LED灯亮灭。 将学习到如何连接部件、编写代码并在线模拟Arduino项目&#xff01; 开发板仿真网站&#xff08;wokwi&#xff09;简介 可参考《一个免费的在线的开发板仿真网站&#…

IEDA 启动项目时出现 java: java.lang.OutOfMemoryError: GC overhead limit exceeded 异常

问题 通过Idea启动项目时&#xff0c;出现java: java.lang.OutOfMemoryError: GC overhead limit exceeded 内存溢出问题&#xff1b; 解决方案 错误是发生在编译阶段&#xff0c;而不是运行阶段&#xff1a; 【1】idea编译Java项目使用的虚拟机和idea软件自身使用的虚拟机是…

【Linux】应用层协议:HTTP

URL 在之前的文章中我们实现了一个网络版本的计算器&#xff0c;在那个计算器中揉合了协议定制以及序列化反序列化的内容&#xff0c;我们当时也自己定制了一套协议标准&#xff0c;比如请求和响应的格式应该是什么&#xff1f;如何读到一个完整的报文&#xff1f;支持的运算符…

无人机巡检技术革命性变革光伏电站运维管理

在中国广袤的大地上&#xff0c;光伏电站如雨后春笋般崛起&#xff0c;晶体硅组件板在阳光下熠熠生辉&#xff0c;为人们带来了源源不断的绿色能源。然而&#xff0c;随着光伏产业的迅猛发展&#xff0c;电站运维管理面临着前所未有的挑战。而无人机巡检技术的引入&#xff0c;…

MySQL进阶-合

目录 1.使用环境 2.条件判断 2.1.case when 2.2.if 3.窗口函数 3.1.排序函数 3.2.聚合函数 3.3.partiton by ​​​​​​​3.4.order by 4.排序窗口函数 5.聚合窗口函数 1.使用环境 数据库&#xff1a;MySQL 8.0.30 客户端&#xff1a;Navicat 15.0.12 MySQL进阶…

Spring Boot | Spring Boot 整合 “Servlet三大组件“ ( Servlet / Filter / Listene )

目录: Spring Boot 整合 "Servlet三大组件" &#xff1a;1. 使用 "组件注册" 的方式 "整合Servlet三大组件" ( 实际操作为 : 创建自定义的"三大组件"对象 结合刚创建"的自定义组件对象"来 将 XxxRegistrationBean对象 通过…

桥接模式:解耦抽象与实现的设计艺术

在软件设计中&#xff0c;桥接模式是一种结构型设计模式&#xff0c;旨在将抽象部分与其实现部分分离&#xff0c;使它们可以独立地变化。这种模式通过提供更加灵活的代码结构帮助软件开发人员处理不断变化的需求&#xff0c;特别是在涉及多平台应用开发时。本文将详细介绍桥接…

Unet++(pytorch实现)

Unet网络 Dense connection Unet继承了Unet的结构&#xff0c;同时又借鉴了DenseNet的稠密连接方式&#xff08;图1中各种分支&#xff09;。 作者通过各层之间的稠密连接&#xff0c;互相连接起来&#xff0c;就像Denset那样&#xff0c;前前后后每一个模块互相作用&#xf…

Ubuntu20.04版本命令行设置挂载磁盘,并设置开机自动挂载

最近部署应用 系统是Ubuntu20.4版本的Linux系统&#xff0c;加了数据盘&#xff0c;需要格式化后挂载&#xff0c;记录下&#xff1a; Linux 数据盘挂载(采用 parted 分区工具)-格式化为 ext4 1. 初始化 Linux 数据盘 挂载数据盘后或者随实例创建时一并创建的数据盘&#xff…