十大排序:插入/希尔/选择/堆/冒泡/快速/归并/计数/基数/桶排序 汇总(C语言)

目录

  • 前言
  • 非线性时间比较类
    • 插入排序
      • (1) 直接插入排序
      • (2) 希尔排序
    • 选择排序
      • (3) 选择排序优化版
      • (4) 堆排序
    • 交换排序
      • (5) 冒泡排序
      • (6) 快速排序
        • hoare版本
        • 挖坑版
        • 前后指针版
        • 非递归版
    • 归并排序
      • (7) 归并排序
        • 递归版
        • 非递归版
  • 线性时间比较类
      • (8) 计数排序
      • 基数排序与桶排序
  • 总结

前言

在这里插入图片描述
在计算机科学中,排序算法是一种重要的算法类别,用于将一组元素按照特定的顺序进行排列。排序算法的应用非常广泛,从日常生活中的字典排序到大规模数据处理中的并行排序,都离不开排序算法的支持。

本博客将介绍十种常见的排序算法,包括冒泡排序、插入排序、选择排序、快速排序、归并排序、堆排序、希尔排序、计数排序、(桶排序和基数排序,稍作了解)。每种算法都会详细讲解其原理、时间复杂度、空间复杂度等关键知识点,以及对比不同算法的优劣势。

通过学习这十种常见的排序算法,读者将能够深入理解算法设计和分析的思想,提升自己的编程能力和解决问题的能力。无论是面试、竞赛还是实际项目开发,掌握好排序算法都是非常有帮助的。

希望本博客能对读者有所帮助,让大家能够更好地应用排序算法解决实际问题。如果对于排序算法还有疑问或者建议,欢迎留言交流。让我们一起进入排序算法的世界,开拓自己的算法视野!

博客主页: 酷酷学!!! 感谢关注! 您的支持是我的极大动力

非线性时间比较类

插入排序

更多详情点击: 博客链接

(1) 直接插入排序

在这里插入图片描述

时间复杂度:O(N^2)
最坏:逆序
最好:顺序有序,O(N)

// 插入排序
void InsertSort(int* a, int n)
{
	//默认升序
	for (int i = 0; i < n - 1; i++)//最后一次将最后一个元素记录下来,就不要循环到n
	{
		//int end = 0;//先写内层循环,定义下标end,假设第一个元素有序
		int end = i;//进行改写,假设前i个位置有序
		int tmp = a[end + 1];//记录后一个位置的元素
		while (end >= 0)//从end下标位置开始依次比较
		{
			if (tmp < a[end])
			{
				a[end + 1] = a[end];
				end--;
			}
			else
			{
				break;
			}
		}
		a[end + 1] = tmp;//此时a[end+1]位置就是需要插入的位置,跳出循环再插入是为了防止end=0时,
		                 //循环无法进入,此时无法进行赋值
	}
}

(2) 希尔排序

希尔排序是一种排序算法,属于插入排序的一种改进版本。它通过将数组分成若干个子序列,对每个子序列进行插入排序,然后逐步减少子序列的长度,最终完成排序。希尔排序的核心思想是将数组按照一定间隔分组,然后对每组进行插入排序。这样可以减少比较和交换的次数,从而提高排序的效率。

时间复杂度: O(N ^ 1.3)

// 希尔排序
void ShellSort(int* a, int n)
{
	int gap = n;
	while (gap > 1)
	{
		gap = gap / 3 + 1;//每次缩小三倍效率是比较高的,+1是为了防止gap==0循环进不来
		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;
		}
	}
}

选择排序

更多详情点击: 博客链接

(3) 选择排序优化版

这里直接给出优化版代码, 采用双指针法, 同时选出到最大与最小的元素位置.

void Swap(int* a, int* b)
{
	int tmp = *a;
	*a = *b;
	*b = tmp;
}

// 选择排序
void SelectSort(int* a, int n)
{
	int begin = 0, end = n - 1;
	while (begin < end)
	{
		//双指针法
		int min = begin, max = begin;//假设a[begin]为最大和最小值
		for (int i = begin + 1; i <= end; i++)//选出最大最小元素,保存下标
		{
			if (a[i] < a[min])
			{
				min = i;
			}
			if (a[i] > a[max])
			{
				max = i;
			}
		}
		Swap(&a[min], &a[begin]);
		if (max == begin)//如果begin位置还是max,最大值就被交换到了min位置,故需要判断
		{
			max = min;
		}
		Swap(&a[max], &a[end]);
		begin++;
		end--;
	}
}

(4) 堆排序

堆排序(Heap Sort)是一种效率较高的排序算法,它的基本思想是将待排序的序列构建成一个大顶堆,然后将堆顶元素与末尾元素交换,再重新调整堆,直到整个序列有序
在这里插入图片描述

//向上调整算法,假设建小堆
//比如插入一个新元素,还需要保证是堆的结构就需要进行调整
void AdjustUP(int* a, int child)
{
	//首先需要找到它的父亲结点
	int parent = (child - 1) / 2;//不管是左孩子还是右孩子都能算出父节点
	while (child > 0)//这里用child进行条件判断,用parent<=0会进入死循环,然后巧合结束,不规范
	{
		if (a[child] < a[parent])
		{
			Swap(&a[child], &a[parent]);
			child = parent;//让父节点等于孩子结点,继续找父节点
			parent = (child - 1) / 2;
		}
		else
		{
			break;
		}
	}
}
// 堆排序
//如果要删除堆顶元素,不可以直接删除,这样会破坏堆的结构,应该先把堆顶数据与最后一个数据交换
//然后删除最后一个数据,此时再将堆顶元素进行向下调整,直到满足堆的性质,调整要保证左右子树也都是堆
void AdjustDwon(int* a, int n, int root)
{
	//排升序,建大堆
	//先假设左孩子大
	int child = root * 2 + 1;
	while (child < n)//到最后一个孩子就结束
	{
		//右孩子存在且比左孩子大
		if (child + 1 < n && a[child + 1] > a[child])
		{
			child = child + 1;
		}
		if (a[child] > a[root])
		{
			Swap(&a[child], &a[root]);
			root = child;
			child = root * 2 + 1;
		}
		else
		{
			break;
		}
	}
}
//这里用向下调整建堆,效率更高
void HeapSort(int* a, int n)
{
	//从最后一个非叶子结点开始建堆
	for (int i = (n - 1 - 1) / 2; i >= 0; i--)
	{
		AdjustDwon(a, n, i);
	}
	//建堆完毕,将第一个元素与最后一个元素交换,再次调整
	int end = n - 1;
	while (end > 0)
	{
		Swap(&a[end], &a[0]);
		AdjustDwon(a, end, 0);//此时调整最后一个元素之前的数组
		end--;
	}
}

交换排序

更多详情点击: 博客链接

(5) 冒泡排序

冒泡排序是一种简单的交换排序算法,它通过不断地比较相邻的元素,如果顺序不对就交换它们的位置,直到整个列表或数组排好序。

快速排序是一种高效的交换排序算法,它通过选择一个基准元素,将小于基准元素的元素放在它的左边,大于基准元素的元素放在它的右边,然后再对左右两部分进行递归调用快速排序,直到整个列表或数组排好序。

交换排序的时间复杂度通常是O(n^2),但在最好情况下,快速排序的时间复杂度可以达到O(nlogn)

//冒泡排序
void BubbleSort(int* a, int n)
{
	//先写内层循环
	//先找出最大的
	for (int i = 0; i < n - 1 ; i++)
	{
		int flag = 1;
		//两两比较,先找最大的,然后找次大的
		for (int j = 0; j < n - 1 - i; j++)//i代表找到了几个最大的
		{
			if (a[j] > a[j + 1])
			{
				flag = 0;
				Swap(&a[j], &a[j + 1]);
			}
		}
		if (flag == 1)//如果flag==1说明没有进行交换则说明已经有序了
			break;
	}
}

(6) 快速排序

hoare版本

在这里插入图片描述

int GetMidi(int* a, int left, int right)
{
	int midi = (right - left) / 2;
	if (a[left] < a[midi])
	{
		if (a[midi] < a[right])
		{
			return midi;
		}
		else if (a[left] < a[right])
		{
			return right;
		}
		else
		{
			return left;
		}
	}
	else//a[left] > a[midi]
	{
		if (a[left] < a[right])
		{
			return left;
		}
		else if (a[midi] > a[right])
		{
			return midi;
		}
		else
		{
			return right;
		}
	}
}

// 快速排序hoare版本
int PartSort1(int* a, int left, int right)
{

	//三数取中,取中等的值作为基准值
	int midi = GetMidi(a, left, right);
	Swap(&a[left], &a[midi]);

	int keyi = left;
	int begin = left, end = right;
	while (begin < end)
	{
		//要保证keyi的值小于相遇位置,所以end先走
		while (begin < end && a[end] >= a[keyi])
		{
			end--;
		}
		while (begin < end && a[begin] <= a[keyi])
		{
			begin++;
		}
		Swap(&a[begin], &a[end]);
	}
	Swap(&a[begin], &a[keyi]);//相遇位置与keyi交换此时这个位置就排好了
	return begin;
}

为了方便, 我们单独将hoare版本写为函数PartSort1,需要使用的时候直接调用

// 快速排序递归实现
void QuickSort(int* a, int left, int right)
{
	if (left >= right)
	{
		return;
	}

	if ((right - left + 1) < 10)
	{
		InsertSort(a + left, right - left + 1);
	}

	//int keyi = left;//选取基准值
	//int begin = left, end = right;
	//begin找找大,end找小,然后交换

	//小区间优化,优化递归
	//if ((right - left + 1) < 10)
	//{
	//	InsertSort(a + left,right - left + 1);
	//}
	//else
	//{
	//	//三数取中,取中等的值作为基准值
	//	int midi = GetMidi(a, left, right);
	//	Swap(&a[left], &a[midi]);

	//	int keyi = left;
	//	int begin = left, end = right;
	//	while (begin < end)
	//	{
	//		//要保证keyi的值小于相遇位置,所以end先走
	//		while (begin < end && a[end] >= a[keyi])
	//		{
	//			end--;
	//		}
	//		while (begin < end && a[begin] <= a[keyi])
	//		{
	//			begin++;
	//		}
	//		Swap(&a[begin], &a[end]);
	//	}
	//	Swap(&a[begin], &a[keyi]);//相遇位置与keyi交换此时这个位置就排好了
	//	keyi = begin;
	//	QuickSort(a, left, keyi - 1);
	//	QuickSort(a, keyi + 1, right);
	//}
	//int keyi = PartSort1(a, left, right);
	//int keyi = PartSort2(a, left, right);
	int keyi = PartSort3(a, left, right);
	QuickSort(a, left, keyi - 1);
	QuickSort(a, keyi + 1, right);
}
挖坑版

在这里插入图片描述

// 快速排序挖坑法
int PartSort2(int* a, int left, int right)
{
	//三数取中
	int midi = GetMidi(a, left, right);
	Swap(&a[left], &a[midi]);

	int keyi = left;
	int begin = left, end = right;

	//先挖个坑,保存a[keyi]的值
	int tmp = a[keyi];
	while (begin < end)
	{
		//让对面先走,找小
		while (begin < end && a[end] >= a[keyi])
		{
			end--;
		}
		a[keyi] = a[end];
		keyi = end;
		while (begin < end && a[begin] <= a[keyi])
		{
			begin++;
		}
		a[keyi] = a[begin];
		keyi = begin;
	}
	//相遇之后把tmp填坑
	a[keyi] = tmp;
	return keyi;
}
前后指针版

在这里插入图片描述

// 快速排序前后指针法
int PartSort3(int* a, int left, int right)
{
	//三数取中
	int midi = GetMidi(a, left, right);
	Swap(&a[left], &a[midi]);
	int keyi = left;

	//定义前后指针,这样不需要考虑是begin先走还是end先走
	//初始prev在前,cur在后一个位置,如果cur小于keyi则与++prev进行交换
	int prev = left;
	int cur = prev + 1;
	while (cur <= right)
	{
		if (a[cur] < a[keyi] && ++prev != cur)//如果在同一个位置就不需要交换
		{
			Swap(&a[cur], &a[prev]);
		}
		cur++;
	}
	Swap(&a[prev], &a[keyi]);
	return prev;
}
非递归版

可以使用队列进行存储区间

//非递归版
#include"stack.h"
void QuickSortNonR(int* a, int left, int right)
{
	ST st;
	STInit(&st);
	STPush(&st, right);
	STPush(&st, left);
	while (!STEmpty(&st))
	{
		int begin = STTop(&st);
		STPop(&st);
		int end = STTop(&st);
		STPop(&st);

		int keyi = PartSort1(a, begin, end);
		//[begin,keyi-1] keyi [keyi+1,end]
		//先压入右区间
		if (keyi + 1 < end)
		{
			STPush(&st, end);
			STPush(&st, keyi + 1);
		}
		if (begin < keyi - 1)
		{
			STPush(&st, keyi - 1);
			STPush(&st, begin);
		}
	}
	Destroy(&st);
}

归并排序

更多详情点击: 博客链接

归并排序是一种经典的排序算法,它基于分治的思想。
归并排序的时间复杂度是O(nlogn),其中n是待排序数组的元素个数。

归并排序是一种稳定的排序算法,适用于各种数据规模。它的主要缺点是需要额外的空间来存储临时数组。

(7) 归并排序

在这里插入图片描述

递归版
void _MergeSort(int* a, int* tmp, int begin,int end)//传递区间递归调用
{
	if (begin >= end)
	{
		return;
	}
	int mid = (begin + end) / 2;
	_MergeSort(a, tmp, begin, mid);
	_MergeSort(a, tmp, mid + 1, end);

	int begin1 = begin, end1 = mid;
	int begin2 = mid + 1, end2 = end;
	int j = begin;
	while (begin1 <= end1 && begin2 <= end2)
	{
		if (a[begin1] < a[begin2])
		{
			tmp[j++] = a[begin1++];
		}
		else
		{
			tmp[j++] = a[begin2++];
		}
	}
	while (begin1 <= end1)
	{
		tmp[j++] = a[begin1++];
	}
	while (begin2 <= end2)
	{
		tmp[j++] = a[begin2++];
	}
	memcpy(a + begin, tmp + begin, sizeof(int) * (end - begin + 1));
}

// 归并排序递归实现
void MergeSort(int* a, int n)
{
	int* tmp = malloc(sizeof(int) * n);
	if (tmp == NULL)
	{
		perror("malloc fail");
		return;
	}
	_MergeSort(a, tmp, 0, n - 1);

	free(tmp);
	tmp = NULL;
}

非递归版
// 归并排序非递归实现
void MergeSortNonR(int* a, int n)
{
	int* tmp = (int*)malloc(sizeof(int) * n);
	if (tmp == NULL)
	{
		perror("malloc fail");
		return;
	}
	int gap = 1; //11归并
	while (gap < n)
	{
		for (int i = 0; i < n; i += gap*2)
		{

			int begin1 = i, end1 = i + gap - 1;
			int begin2 = i + gap, end2 = i + 2 * gap - 1;
			int j = i;

			if (begin2 >= n)
			{
				break;
			}
			if (end2 >= n)
			{
				end2 = n - 1;
			}

			while (begin1 <= end1 && begin2 <= end2)
			{
				if (a[begin1] < a[begin2])
				{
					tmp[j++] = a[begin1++];
				}
				else
				{
					tmp[j++] = a[begin2++];
				}
			}
			while (begin1 <= end1)
			{
				tmp[j++] = a[begin1++];
			}
			while (begin2 <= end2)
			{
				tmp[j++] = a[begin2++];
			}
			memcpy(a + i, tmp + i, sizeof(int) * (end2 - i + 1));
		}
		gap *= 2;
	}
	free(tmp);
	tmp = NULL;
}

线性时间比较类

(8) 计数排序

时间复杂度:O(N+range)
只适合整数/适合范围集中
空间范围度:O(range)

// 计数排序
void CountSort(int* a, int n)
{
	//找数的范围
	int max = a[0], min = a[0];
	for (int i = 1; i < n; i++)
	{
		if (a[i] < min)
			min = a[i];
		if (a[i] > max)
			max = a[i];
	}
	int range = max - min + 1;//需要开辟的空间大小
	int* count = (int*)calloc(range, sizeof(int));//malloc需要手动初始化,而calloc默认初始化为0
	if (count == NULL)
	{
		perror("calloc fail");
		return;
	}

	//开始计数
	for (int i = 0; i < n; i++)
	{
		count[a[i] - min]++;
	}
	//开始排序
	int j = 0;
	for (int i = 0; i < range; i++)
	{
		while (count[i]--)
		{
			a[j++] = i + min;
		}
	}
	free(count);
}

基数排序与桶排序

这两种排序只需要稍作了解, 面试一般没有.

基数排序是一种非比较排序算法,它根据数字的位数进行排序。基数排序的基本思想是将整数按照个位、十位、百位等位数进行排序,最终得到有序的结果。

基数排序的步骤如下:

首先找到待排序数组中的最大值,并确定其位数,记为max_digits。
创建10个桶,分别代表数字0-9。
从个位开始,将所有数字放入对应的桶中。
依次取出桶中的数字,并按照顺序放回原数组中。
重复步骤3和步骤4,直到按照最高位排序完毕。
基数排序的时间复杂度为O(n*k),其中n是待排序数组的长度,k是最大位数。需要注意的是,基数排序只适用于整数排序,且要求待排序数字必须是非负数。
在这里插入图片描述

桶排序是一种排序算法,它将数据按照一定的范围划分为多个桶,然后对每个桶中的数据进行排序,最后将每个桶中的元素按照顺序依次取出来得到有序序列。

具体的桶排序算法如下:

创建一个定量的空桶数组。
遍历输入数据,并将每个元素放入对应的桶中。
对每个非空桶中的元素进行排序。
依次将非空桶中的元素取出,并放入输出序列。
桶排序的时间复杂度取决于对每个桶中的元素进行排序的算法,通常采用的是快速排序或插入排序,所以整体的时间复杂度为O(n+k),其中n为待排序序列的长度,k为桶的数量。

桶排序适用于数据分布较均匀的情况,当数据分布不均匀时,不同的桶中的数据量差别较大,可能会导致某些桶中的数据在排序后仍然不是有序的,因此对于不同的数据分布情况,桶的数量和每个桶的容量需要适当调整。

在这里插入图片描述

总结

在这里插入图片描述
在这里插入图片描述
稳定性 :三稳四不稳
稳定性指的是, 相同的值,其相对位置排序后保持不变,作用一般在排列结构体数据时,比如高考总分排列,但是总分相同,就按照语文成绩高低排列, 此时可以使用稳定排序, 先排语文成绩,在排总成绩.
计数排序,基数排序和桶排序因为排列数据具有局限性,所以这里不探讨其稳定性

选择排序为什么不是稳定的?

比如下列情况
{ 6 , 1 , 1} 这种情况将第二个1换到前面, 相对位置不变
{ 6, 6, 1}但是这种情况相同的6却因为选择发生了变化, 所以是不稳定的.

为什么快速排序具有空间消耗?
因为递归会创建栈帧空间.


冒泡排序:

比较相邻的元素,如果前一个比后一个大,则交换位置,直到将最大的元素移到最后。
时间复杂度:平均O(n^ 2),最好情况O(n),最坏情况O(n^2)。
选择排序:

每次从未排序的元素中选择最小的元素,放到已排序的末尾。
时间复杂度:平均O(n^ 2),最好情况O(n^2),最坏情况O(n ^2)。
插入排序:

将未排序的元素逐个插入到已排序的序列中的正确位置。
时间复杂度:平均O(n^ 2),最好情况O(n),最坏情况O(n^2)。
希尔排序:

根据间隔将序列划分为多个子序列,对子序列进行插入排序,然后缩小间隔直至最后一次插入排序。
时间复杂度:平均O(n log n),最好情况O(n log^ 2 n),最坏情况O(n^2)。
归并排序:

将序列递归地拆分成两个子序列,然后将两个有序子序列合并为一个有序序列。
时间复杂度:平均O(n log n),最好情况O(n log n),最坏情况O(n log n)。
快速排序:

选择一个基准元素,将序列分为两部分,小于基准的放在左边,大于基准的放在右边,然后递归地对两个部分进行快速排序。
时间复杂度:平均O(n log n),最好情况O(n log n),最坏情况O(n^2)。
堆排序:

将序列构建成一个最大堆,然后不断将堆顶元素与最后一个元素交换,并重新调整堆,直到所有元素都有序。
时间复杂度:平均O(n log n),最好情况O(n log n),最坏情况O(n log n)。
计数排序:

统计每个元素的出现次数,然后根据统计结果将元素放回原数组。
时间复杂度:平均O(n+k),最好情况O(n+k),最坏情况O(n+k)。
桶排序:

将元素分到不同的桶中,然后对每个桶进行排序,最后按顺序将元素取出。
时间复杂度:平均O(n+k),最好情况O(n),最坏情况O(n^2)。
基数排序:

根据元素的位数依次进行排序,从最低位到最高位。
时间复杂度:平均O(nk),最好情况O(nk),最坏情况O(n*k)。


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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

昇思25天学习打卡营第16天|文本解码原理——以MindNLP为例

在大模型中&#xff0c;文本解码通常是指在自然语言处理&#xff08;NLP&#xff09;任务中使用的大型神经网络模型&#xff08;如Transformer架构的模型&#xff09;将编码后的文本数据转换回可读的原始文本的过程。这些模型在处理自然语言时&#xff0c;首先将输入文本&#…

自闭症儿童的治疗方法有哪些?

身为星贝育园自闭症儿童康复学校的资深教育者&#xff0c;我深知自闭症谱系障碍&#xff08;ASD&#xff09;儿童的教育与治疗需要一个全面、个性化的方案。在星贝育园&#xff0c;我们致力于为孩子们提供一个充满爱与理解的环境&#xff0c;采用多种科学验证的教育方法&#x…

【Java11】变量的初始化和内存中的运行机制

成员变量的初始化和内存中的运行机制 系统加载类或创建类的实例时&#xff0c;系统自动为成员变量分配内存空间&#xff0c;然后自动为成员变量指定初始值。 class Person {public String name; // 实例变量public static int eyeNum; // 类变量 }var p1 Person(); var p2 …

动态线程池思想学习及实践

引言 在后台项目开发过程中&#xff0c;我们常常借助线程池来实现多线程任务&#xff0c;以此提升系统的吞吐率和响应性&#xff1b;而线程池的参数配置却是一个难以合理评估的值&#xff0c;虽然业界也针对CPU密集型&#xff0c;IO密集型等场景给出了一些参数配置的经验与方案…

MQ:RabbitMQ

同步和异步通讯 同步通讯: 需要实时响应,时效性强 耦合度高 每次增加功能都要修改两边的代码 性能下降 需要等待服务提供者的响应,如果调用链过长则每次响应时间需要等待所有调用完成 资源浪费 调用链中的每个服务在等待响应过程中,不能释放请求占用的资源,高并发场景下…

【后端面试题】【中间件】【NoSQL】MongoDB查询优化2(优化排序、mongos优化)

优化排序 在MongoDB里面&#xff0c;如果能够利用索引来排序的话&#xff0c;直接按照索引顺序加载数据就可以了。如果不能利用索引来排序的话&#xff0c;就必须在加载了数据之后&#xff0c;再次进行排序&#xff0c;也就是进行内存排序。 可想而知&#xff0c;如果内存排序…

【RT-thread studio 下使用STM32F103-学习sem-信号量-初步使用-线程之间控制-基础样例】

【RT-thread studio 下使用STM32F103-学习sem-信号量-初步使用-线程之间控制-基础样例】 1、前言2、环境3、事项了解&#xff08;1&#xff09;了解sem概念-了解官网消息&#xff08;2&#xff09;根据自己理解&#xff0c;设计几个使用方式&#xff08;3&#xff09;不建议运行…

DataWhale-吃瓜教程学习笔记 (七)

学习视频**&#xff1a;第6章-支持向量机_哔哩哔哩_bilibili 西瓜书对应章节&#xff1a; 第六章 支持向量机 - 算法原理 几何角度 对于线性可分数据集&#xff0c;找距离正负样本距离都最远的超平面&#xff0c;解是唯一的&#xff0c;泛化性能较好 - 超平面 - 几何间隔 例…

堆叠的作用

一、为什么要堆叠 传统的园区网络采用设备和链路冗余来保证高可靠性&#xff0c;但其链路利用率低、网络维护成本高&#xff0c;堆叠技术将多台交换机虚拟成一台交换机&#xff0c;达到简化网络部署和降低网络维护工作量的目的。 二、堆叠优势 1、提高可靠性 堆叠系统多台成…

ServiceImpl中的参数封装为Map到Mapper.java中查询

ServiceImpl中的参数封装为Map到Mapper.java中查询&#xff0c;可以直接从map中获取到key对应的value

【Python机器学习】处理文本数据——多个单词的词袋(n元分词)

使用词袋表示的主要缺点之一就是完全舍弃了单词顺序。因此“its bad&#xff0c;not good at all”和“its good&#xff0c;not bad at all”这两个字符串的词袋表示完全相同&#xff0c;尽管它们的含义相反。幸运的是&#xff0c;使用词袋表示时有一种获取上下文的方法&#…

LeetCode热题100刷题3:3. 无重复字符的最长子串、438. 找到字符串中所有字母异位词、560. 和为 K 的子数组

3. 无重复字符的最长子串 滑动窗口、双指针 class Solution { public:int lengthOfLongestSubstring(string s) {//滑动窗口试一下//英文字母、数字、符号、空格,ascii 一共包含128个字符vector<int> pos(128,-1);int ans 0;for(int i0,j0 ; i<s.size();i) {//s[i]…

全端面试题15(canvas)

在前端开发领域&#xff0c;<canvas> 元素和相关的 API 是面试中经常被提及的主题。下面是一些常见的关于 HTML5 Canvas 的面试问题及解答示例&#xff1a; 1. 什么是 <canvas> 元素&#xff1f; <canvas> 是 HTML5 引入的一个用于图形渲染的标签。它本身并…

能否免费使用Adobe XD?

Adobe XD不是免费的。Adobe 目前XD采用订阅模式&#xff0c;提供订阅模式 7 每天试用期结束后需要付费购买&#xff0c;具体价格根据不同的订阅计划确定&#xff0c;包括每月购买&#xff0c;包括 9.99 美元或每月 99.99 美元&#xff0c;或者选择购买Adobe CreativeCloud整体订…

【qt】如何通过域名获得IP地址?

域名是什么呢?像www.baidu.com的baidu.com就是域名. 域名相当于是网站的门牌号. 域名可以通过 DNS 解析将其转换为对应的 IP 地址. 用我们获取IP地址的方式就可以,但是现在没有可以用另一种方法. 槽函数的实现: void MainWindow::lookupHost(const QHostInfo &hostInf…

Python学习笔记29:进阶篇(十八)常见标准库使用之质量控制中的数据清洗

前言 本文是根据python官方教程中标准库模块的介绍&#xff0c;自己查询资料并整理&#xff0c;编写代码示例做出的学习笔记。 根据模块知识&#xff0c;一次讲解单个或者多个模块的内容。 教程链接&#xff1a;https://docs.python.org/zh-cn/3/tutorial/index.html 质量控制…

RedHat / CentOS安装FTP服务

本章教程,记录在RedHat / CentOS中安装FTP的具体步骤。FTP默认端口:21 1、安装 epel 源 yum install -y epel-release2、安装 pure-ftpd yum -y install pure-ftpd3、修改默认配置 # 默认配置位于 /etc/pure-ftpd/pure-ftpd.conf,在配置文件中找到下面几个参数进行修改:#…

并发、多线程和HTTP连接之间有什么关系?

一、并发的概念 并发是系统同时处理多个任务或事件的能力。在计算中&#xff0c;这意味着系统能够在同一时间段内处理多个任务&#xff0c;而不是严格按照顺序一个接一个地执行它们。并发提高了系统的效率和资源利用率&#xff0c;从而更好地满足用户的需求。在现代应用程序中&…

C++ windows下使用openvino部署yoloV8

目录 准备版本&#xff1a; 准备事项: 选择配置界面&#xff1a; 下载界面&#xff1a; ​编辑 添加VS配置&#xff1a; 准备代码&#xff1a; yolov8.h yolov8.cpp detect.cpp 如何找到并放置DLL&#xff1a; 准备版本&#xff1a; opencv 4.6.0 openvino 2024.0…

深度解读:Etched Sohu与Groq LPU芯片的区别

本文简单讲解一下Etched Sohu与Groq LPU两种芯片的区别。 设计理念的差异 首先&#xff0c;这两款产品在设计理念上完全是两条不同的路线。Etched Sohu芯片的设计理念是围绕Transformer模型进行优化。Transformer模型近年来在NLP任务中表现出色&#xff0c;Etched公司因此为其…