插入排序(一)——直接插入排序与希尔排序

news2024/11/12 5:21:22

fe594ea5bf754ddbb223a54d8fb1e7bc.gif

目录

一.前言

二.排序的概念及其运用

1.1排序的概念

1.2 常用排序算法

三.常用排序算法的实现

3.1 插入排序

3.1.1 基本思想

3.1.2 直接插入排序

3.1.3 希尔排序(缩小增量排序)

四.全部代码

sort.c

sort.h

test.c

五.结语


8fb442646f144d8daecdd2b61ec78ecd.png一.前言

本文我们开始进入数据结构的难点——排序,当我们初步学习排序后就可以写出更高效的代码~。码字不易,希望大家多多支持我呀!(三连+关注,你是我滴神!)

二.排序的概念及其运用

1.1排序的概念

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

1.2 常用排序算法

三.常用排序算法的实现

3.1 插入排序

3.1.1 基本思想

直接插入排序是一种简单的插入排序法,其基本思想是:

把待排序的记录按其关键码值的大小逐个插入到已经排好序的有序序列中,直到所有的记录插入完为止,得到一个新的有序序列。

实际中我们玩扑克牌时,就用了插入排序的思想

3.1.2 直接插入排序

当插入第i(i>=1)个元素时,前面的arr[0], arr[1]....arr[i-1]已经排行序,此时用arr[i]的排序码与arr[i],arr[i-1],arr[i-2]....的排序码顺序进行比较,找到插入位置即将arr[i]插入,原来位置上的元素顺序后移。

在学习该排序之前我们先完成一个简单的单趟排序。我们对两个有序数组分别插入5和1来分析。

当我们要插入5时,对比最后一位数字,如果该数字比5大则往后挪一位,与此同时end--往前移动继续与5比较,以此类推直到end指向4(比5小)的时候停下,然后在end的后面插入5.

接下来对于1也是同理,当对比完发现end指向-1时1成功插入(1为最小)。

基于这两个图例我们来开始写这个单趟代码:

首先要在有序数组插入数字的时候,那么5的位置肯定是end+1位,其次我们需要用tmp来保存5因为当9往后挪动的时候会覆盖5的位置,要想让5继续与前面数字进行比较就得用存储5的tmp。

void InsertSort(int* arr, int n)
{
	//单趟排序
	int end = n - 2;
	int tmp = arr[end + 1];
	while (end >= 0)
	{
		if (tmp < arr[end])//如果遇到比tmp大的数
		{
			arr[end + 1] = arr[end];//往后挪
		}
		else
		{
			break;//退出循环,在外面插入
		}
		end--;
	}
	arr[end + 1] = tmp;
}

int main()
{
	int arr[] = { 3,4,2,1,7,8,5 };
	InsertSort(arr, 7);
	
	return 0;
}

有一点需要注意,当我们在可以插入的时候不能选择在循环里面插入而是用break跳出循环,再写插入的代码。

之所以这样是因为如果tmp保存的值比数组中所有的值都要小,那么它只能是等到循环结束,是不能在循环里进行插入的。

 

既然我们控制了单趟有序,怎么样控制整体有序呢? 

我们只需要控制end的位置就可以做到整体有序,因为这就像是一个在有序数组里不断插入的过程,而end的起始位置作用就是隔离有序数组。

所以end的范围起始是0结束应该是n-2。在n个数中,end指向倒数第2个,把倒数第一个当作要插入的数字即可完成所有的排序。

void InsertSort(int* arr, int n)
{
	int i = 0;
	for (i = 0; i < n - 1; i++)
	{
		//单趟排序
		int end = i;
		int tmp = arr[end + 1];
		while (end >= 0)
		{
			if (tmp < arr[end])//如果遇到比tmp大的数
			{
				arr[end + 1] = arr[end];//往后挪
			}
			else
			{
				break;//退出循环,在外面插入
			}
			end--;
		}
		arr[end + 1] = tmp;
	}
	
}





int main()
{
	int arr[] = { 3,4,2,1,7,8,5 };
	InsertSort(arr, 7);
	
	return 0;
}

时间复杂度:

最坏情况(逆序时):O(N^2)

最好情况(顺序有序时):O(N) 

直接插入排序的特性总结:

  1. 元素集合越接近有序,直接插入排序算法的时间效率越高
  2. 时间复杂度:O(N^2)
  3. 空间复杂度:O(1),它是一种稳定的排序算法
  4. 稳定性:稳定

3.1.3 希尔排序(缩小增量排序)

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

希尔排序前景:

  1. 先预排序
  2. 直接插入排序

我们通过预排序让数组接近有序再来直接插入排序这样时间复杂度就可以接近O(N)

接着我们要在划分好的组里进行直接插入排序

蓝色组:

紫色组:

红色组:

在外面排完之后可以观察得到,现在这组数虽然不是有序,但对比原有顺序可以说是相对有序(大的数更往后排了,小的数更往前排了)。

接下来我们用代码来实现该思路:

在直接插入的基础上进行修改

以此类推完成排序

void ShellSort(int* a, int n)
{
		//单趟排序
		int gap = 3;
		int end = 0;
		int tmp = a[end + gap];
		while (end >= 0)
		{
			if (tmp < a[end])//如果遇到比tmp大的数
			{
				a[end + gap] = a[end];//往后挪
			}
			else
			{
				break;//退出循环,在外面插入
			}
			end = end - gap;
		}
		a[end + gap] = tmp;

}

我们可以发现如果gap为1时,那就是直接插入排序了~

这样就控制了蓝色一组

void ShellSort(int* a, int n)
{
	int gap = 3;
	for (int i = 0; i < n ; i += gap)
	{
		//单趟排序
		int end = i;
		int tmp = a[end + gap];
		while (end >= 0)
		{
			if (tmp < a[end])//如果遇到比tmp大的数
			{
				a[end + gap] = a[end];//往后挪
			}
			else
			{
				break;//退出循环,在外面插入
			}
			end = end - gap;
		}
		a[end + gap] = tmp;
	}


}

那么按照这个代码,最后end一定要落到这个位置上吗? 

如果落到这个位置,那最后tmp再取end+1就越界了,而且按照我们上面学到的插排,end起始排序的位置是要落在插入数字之前的,但目前end的位置在蓝色组中是最后一个数字,使得其tmp取到随机值了。

所以最后我们要选的是n-gap,因为这里条件是i小于,所以最后end的位置才可以落在n-4即8所在的位置,而这在蓝色组的4个数字中排序是最后落到为倒数第二个数字,符合直接插入的规则。

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])//如果遇到比tmp大的数
			{
				a[end + gap] = a[end];//往后挪
			}
			else
			{
				break;//退出循环,在外面插入
			}
			end = end-gap;
		}
		a[end + gap] = tmp;
	}
}

现在我们把蓝色组的预排序处理好了,那另外两组又要如何处理?

再来套个循环去改变它们的起始位置就行了。

void ShellSort(int* a, int n)
{
	int gap = 3;
	for (int j = 0; j < gap; j++)
	{
		for (int i = j; i < n - gap; i += gap)
		{
			//单趟排序
			int end = i;
			int tmp = a[end + gap];
			while (end >= 0)
			{
				if (tmp < a[end])//如果遇到比tmp大的数
				{
					a[end + gap] = a[end];//往后挪
				}
				else
				{
					break;//退出循环,在外面插入
				}
				end = end - gap;
			}
			a[end + gap] = tmp;
		}
	}
	
}

这样子是一组一组排,蓝色走完走紫色,紫色走完走红色。

下面是另一种版本(效果与上面一样):多组并排

void ShellSort(int* a, int n)
{
	int gap = 3;
	for (int i = 0; i < n - gap; ++i)
	{
		//单趟排序
		int end = i;
		int tmp = a[end + gap];
		while (end >= 0)
		{
			if (tmp < a[end])//如果遇到比tmp大的数
			{
				a[end + gap] = a[end];//往后挪
			}
			else
			{
				break;//退出循环,在外面插入
			}
			end = end - gap;
		}
		a[end + gap] = tmp;
	}

}

 

这个是挨个排序(蓝紫红蓝紫红,虽然效果跟前面的一样,但前面代码明显更好理解~

预排序意义:大的数更快的到后面去,小的数更快的到前面去。gap越大跳的越快,越不接近有序,gap越小跳的越慢,越接近有序。gap=1,直接有序。 

完整希尔排序 

void ShellSort(int* a, int n)
{
	int gap = n;
	while (gap > 1)
	{
		gap = gap / 2;
		for (int j = 0; j < gap; j++)
		{
			for (int i = j; i < n - gap; i += gap)
			{
				//单趟排序
				int end = i;
				int tmp = a[end + gap];
				while (end >= 0)
				{
					if (tmp < a[end])//如果遇到比tmp大的数
					{
						a[end + gap] = a[end];//往后挪
					}
					else
					{
						break;//退出循环,在外面插入
					}
					end = end - gap;
				}
				a[end + gap] = tmp;
			}
		}
	}
	

}

之所以这样是因为gap不好给固定的值,固定值有时候会不适合n的数量变化,所以我们最开始可以先让gap为n,然后通过/2的方式对数组不断进行预排序,而在最后gap一定是为1,这时候就可以进行整体的排序了。 

有时候为避免预排序过多可以改变一下gap,/3+1是为了保证gap最后能够取到1

接下来我们来测试一下它的性能

这是通过生成100000个随机值测试用的代码片段。

void TestOP()
{
	srand(time(0));
	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);
	int* a7 = (int*)malloc(sizeof(int) * N);

	for (int i = N-1; i >= 0; --i)
	{
		a1[i] = rand();
		a2[i] = a1[i];
		a3[i] = a1[i];
		a4[i] = a1[i];
		a5[i] = a1[i];
		a6[i] = a1[i];
		a7[i] = a1[i];
	}

	int begin1 = clock();
	InsertSort(a1, N);
	int end1 = clock();

	int begin2 = clock();
	ShellSort(a2, N);
	int end2 = clock();

	int begin7 = clock();
	//BubbleSort(a7, N);
	int end7 = 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("ShellSort:%d\n", end2 - begin2);
	printf("BubbleSort:%d\n", end7 - begin7);

	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);
	free(a7);
}

int main()
{
	TestOP();
	//TestBubbleSort();
	//TestHeapSort();
	//TestSelectSort();

	return 0;
}

我们选择调用希尔和插排来对比在10万个随机数中二者排序完成的用时是多少。

我们再来看看1万个数据的效果

可以发现数据量越大越能突显希尔的性能优势。

希尔排序的时间复杂度

一般gap是多少就会划分有多少个组别

gap很大的时候,如n/3 整个数组逆序,n/3组数据,每组比较3次(1+2)间距为gap的这些数据,合计 n/3 *3 ==n

所以我们可以得知红框框住的这两组循环一开始是n次

gap很大的时候,如1 接近有序了 间距为1的这些数据,合计:n

中间会呈现由n变大再变小到n的过程。

我们粗略通过循环比较可以得出时间复杂度N(因为上图中n无法精确计算)*logN(以2为底或以3为底,看gap怎么处理)。

而最终结论是,时间复杂度为O(N^1.3),算法效率略差于n*logn

四.全部代码

sort.c

#define _CRT_SECURE_NO_WARNINGS 1
#include "sort.h"
void InsertSort(int* arr, int n)
{
	int i = 0;
	for (i = 0; i < n - 1; i++)
	{
		//单趟排序
		int end = i;
		int tmp = arr[end + 1];
		while (end >= 0)
		{
			if (tmp < arr[end])//如果遇到比tmp大的数
			{
				arr[end + 1] = arr[end];//往后挪
			}
			else
			{
				break;//退出循环,在外面插入
			}
			end--;
		}
		arr[end + 1] = tmp;
	}

}

//void ShellSort(int* a, int n)
//{
//	int gap = 3;
//	for (int i = 0; i < n ; i += gap)
//	{
//		//单趟排序
//		int end = i;
//		int tmp = a[end + gap];
//		while (end >= 0)
//		{
//			if (tmp < a[end])//如果遇到比tmp大的数
//			{
//				a[end + gap] = a[end];//往后挪
//			}
//			else
//			{
//				break;//退出循环,在外面插入
//			}
//			end = end - gap;
//		}
//		a[end + gap] = tmp;
//	}
//
//
//}

void ShellSort(int* a, int n)
{
	int gap = n;
	while (gap > 1)
	{
		gap = gap / 2;
		for (int j = 0; j < gap; j++)
		{
			for (int i = j; i < n - gap; i += gap)
			{
				//单趟排序
				int end = i;
				int tmp = a[end + gap];
				while (end >= 0)
				{
					if (tmp < a[end])//如果遇到比tmp大的数
					{
						a[end + gap] = a[end];//往后挪
					}
					else
					{
						break;//退出循环,在外面插入
					}
					end = end - gap;
				}
				a[end + gap] = tmp;
			}
		}
	}
	

}
//void ShellSort(int* a, int n)
//{
//	int gap = 3;
//	for (int i = 0; i < n - gap; ++i)
//	{
//		//单趟排序
//		int end = i;
//		int tmp = a[end + gap];
//		while (end >= 0)
//		{
//			if (tmp < a[end])//如果遇到比tmp大的数
//			{
//				a[end + gap] = a[end];//往后挪
//			}
//			else
//			{
//				break;//退出循环,在外面插入
//			}
//			end = end - gap;
//		}
//		a[end + gap] = tmp;
//	}
//
//}

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

—————————————————————————————————————————— 

sort.h

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>

void PrintfSort(int* a, int n);

void ShellSort(int* a, int n);

void InsertSort(int* arr, int n);

—————————————————————————————————————————— 

test.c

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include "sort.h"
#include <time.h>
#include <stdlib.h>
//void InsertSort(int* arr, int n)
//{
//	int i = 0;
//	for (i = 0; i < n - 1; i++)
//	{
//		//单趟排序
//		int end = i;
//		int tmp = arr[end + 1];
//		while (end >= 0)
//		{
//			if (tmp < arr[end])//如果遇到比tmp大的数
//			{
//				arr[end + 1] = arr[end];//往后挪
//			}
//			else
//			{
//				break;//退出循环,在外面插入
//			}
//			end--;
//		}
//		arr[end + 1] = tmp;
//	}
//	
//}
void TestShellSort()
{
	int a[] = { 9,1,2,5,7,4,8,6,3,5,1,2,3,5,1,8,3 };
	ShellSort(a, sizeof(a) / sizeof(int));
	PrintfSort(a, sizeof(a) / sizeof(int));
}

void TestOP()
{
	srand(time(0));
	const int N = 10000;
	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);
	int* a7 = (int*)malloc(sizeof(int) * N);

	for (int i = N - 1; i >= 0; --i)
	{
		a1[i] = rand();
		a2[i] = a1[i];
		a3[i] = a1[i];
		a4[i] = a1[i];
		a5[i] = a1[i];
		a6[i] = a1[i];
		a7[i] = a1[i];
	}

	int begin1 = clock();
	InsertSort(a1, N);
	int end1 = clock();

	int begin2 = clock();
	ShellSort(a2, N);
	int end2 = clock();

	int begin7 = clock();
	//BubbleSort(a7, N);
	int end7 = 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("ShellSort:%d\n", end2 - begin2);
	printf("BubbleSort:%d\n", end7 - begin7);

	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);
	free(a7);
}


int main()
{
	//int arr[] = { 3,4,2,1,7,8,5 };
	//InsertSort(arr, 7);
	/*int a[] = {1,5,8,7,4,6,9,85,2,4,1,7 };
	ShellSort(a, sizeof(a) / sizeof(int));
	PrintfSort(a, sizeof(a) / sizeof(int));*/
	TestOP();
	return 0;
}

 

4b12323f94834afd9ec146a3c10df229.jpeg五.结语

插入排序只是排序中的冰山一角,它可以帮助我们处理更庞大的数据,不过由于排序算法有多种,我们得学会在各种情况下运用最佳算法进行排序。最后感谢大家的观看,友友们能够学习到新的知识是额滴荣幸,期待我们下次相见~

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

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

相关文章

Android.mk和Android.bp的区别和转换详解

Android.mk和Android.bp的区别和转换详解 文章目录 Android.mk和Android.bp的区别和转换详解一、前言二、Android.mk和Android.bp的联系三、Android.mk和Android.bp的区别1、语法&#xff1a;2、灵活性&#xff1a;3、版本兼容性&#xff1a;4、向后兼容性&#xff1a;5、编译区…

【数据结构】快速排序,归并排序

快速排序 1.hoare版本 根据动图的演示&#xff0c;整理的思路如下&#xff0c; 1.定义left,right,key。key默认是左边第一个元素&#xff0c;像两个指针&#xff0c;左边找比key大的&#xff0c;右边找比k小的&#xff0c;找到的话&#xff0c;交换二者&#xff0c;往返这个过…

限流算法之流量控制的平滑之道:滑动时间窗算法

文章目录 引言简介优点缺点样例样例图样例代码 应用场景结论 引言 在互联网应用中&#xff0c;流量控制是一个重要的组件&#xff0c;用于防止系统过载和保护核心资源。常见的限流算法包括固定窗口算法和滑动时间窗算法。本文将重点介绍滑动时间窗算法&#xff0c;并分析其优缺…

Spring Boot程序的打包与运行:构建高效部署流程

引言 在现代应用开发中&#xff0c;高效的打包和部署流程对于项目的开发、测试和上线至关重要。Spring Boot作为一种快速开发框架&#xff0c;提供了方便的打包工具和内嵌式的Web服务器&#xff0c;使得打包和运行变得更加简单。本文将研究在Spring Boot应用中如何进行打包&am…

java8 列表通过 stream流 根据对象属性去重的三种实现方法

java8 列表通过 stream流 根据对象属性去重的三种实现方法 一、简单去重 public class DistinctTest {/*** 没有重写 equals 方法*/SetterGetterToStringAllArgsConstructorNoArgsConstructorpublic static class User {private String name;private Integer age;}/*** lombo…

梁山泊国潮风礼盒,传承经典,贺礼新春

在春节来临之际&#xff0c;梁山泊隆重推出新年中国红礼盒酒&#xff0c;为您传递新年的祝福与关爱。这款酒以其独特的魅力&#xff0c;为您带来美好的祝愿和愉悦的享受。中国风国潮礼盒采用中国传统红色为主色调&#xff0c;象征着吉祥、喜庆和繁荣。红色的背景上&#xff0c;…

探索curl的高级应用:HTTP请求的大师级技巧

探索curl的高级应用&#xff1a;HTTP请求的大师级技巧 引言高级用法概览1. HTTP请求与响应处理2. 身份验证与安全3. 进阶技巧4. Cookie管理与会话保持5. 脚本自动化 HTTP请求与响应处理1. 自定义请求头2. 发送数据3. 处理响应 身份验证与安全1. 基本认证2. 摘要认证3. HTTPS安全…

禅道使用之项目的过程管理

目录 一.禅道介绍 二.禅道下载 三. 禅道的使用 3.1.禅道管理员管理账号 3.2.禅道管理产品经理角色操作 3.3.禅道管理项目经理角色操作 3.4.禅道管理测试主管角色操作 3.5.禅道管理产品经理发布版本 好啦今天就这里了哦&#xff01;&#xff01;&#xff01;希望能帮到你…

Unity-Arduino Bluetooth Plugin蓝牙插件使用时需要注意的一些事项(附插件下载链接)

一些参考链接 1.Android 无法扫描蓝牙设备踩坑 2.权限相关 1-首先要明确你的蓝牙设备是经典蓝牙还是低功耗&#xff08;BLE)蓝牙&#xff1a; 转载&#xff1a;Android蓝牙开发—经典蓝牙和BLE&#xff08;低功耗&#xff09;蓝牙的区别 2.如果是BLE蓝牙&#xff0c;需要打勾…

Github 2024-01-20开源项目日报 Top10

根据Github Trendings的统计&#xff0c;今日(2024-01-20统计)共有10个项目上榜。根据开发语言中项目的数量&#xff0c;汇总情况如下&#xff1a; 开发语言项目数量Python项目4Jupyter Notebook项目2Lua项目1C项目1PHP项目1Vue项目1非开发语言项目1C项目1 PhotoMaker: 定制逼…

nvm, node.js, npm, yarn 安装配置

文章目录 nvm 安装node.js 安装npm yarn 配置 nvm 安装 nvm 是一个 node.js 管理工具&#xff0c;可以快捷下载安装使用多个版本的node.js linux 命令行输入&#xff1a; curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bashwget -qO- https…

程序员的福利到了,轮转数组,经典算法实战

&#x1f3c6;作者简介&#xff0c;普修罗双战士&#xff0c;一直追求不断学习和成长&#xff0c;在技术的道路上持续探索和实践。 &#x1f3c6;多年互联网行业从业经验&#xff0c;历任核心研发工程师&#xff0c;项目技术负责人。 &#x1f389;欢迎 &#x1f44d;点赞✍评论…

ES框架详解

ES框架详解 1、全文检索的介绍 ​ 那么对于一般的公司&#xff0c;初期是没有那么多数据的&#xff0c;所以很多公司更倾向于使用传统的数据库&#xff1a;mysql&#xff1b;比如我们要查找关键字”传智播客“&#xff0c;那么查询的方式大概就是:select * from table where …

2024WebGIS新手必看学习攻略(2)

上期给大家分享了webgis开发学习的第一期&#xff0c;点这里&#xff1a;2024WebGIS新手必看学习攻略&#xff08;1&#xff09;https://mp.csdn.net/mp_blog/creation/editor/135680818 主要讲了webgis最基本的前置知识&#xff0c;上期我们介绍到学习webGIS的语言&#xff0…

OpenSource - 工具管理器easy-manager-tool

文章目录 功能说明运行配置环境配置启动docker部署 项目安全UI展示 Easy-Manager-Tool 打造软件行业首款集成工具&#xff0c;不管你是程序员&#xff0c;测试&#xff0c;运维等都可以使用该软件来提升自己的工作效率。 Easy-Manager-Tool 的诞生是为了解决软件行业众多参与者…

java发送邮件、接收邮件

邮件协议 SMTP SMTP (Simple Mail Transfer Protocol)&#xff0c;即简单邮件传输协议 默认端口是25&#xff0c;通过SSL协议加密之后的默认端口是465 用户必须首先设置 SMTP 服务器&#xff0c;然后才能配置电子邮件客户端与其连接。完成此操作后&#xff0c;用户按下电子…

YOLOv5改进 | 主干篇 | 华为移动端模型GhostnetV2一种移动端的专用特征提取网络

一、本文介绍 本文给大家带来的改进机制是华为移动端模型Ghostnetv2,华为GhostNetV2是为移动应用设计的轻量级卷积神经网络(CNN),旨在提供更快的推理速度,其引入了一种硬件友好的注意力机制,称为DFC注意力。这个注意力机制是基于全连接层构建的,它的设计目的是在通用硬…

【Qt】对象树与坐标系

需要云服务器等云产品来学习Linux的同学可以移步/-->腾讯云<--/-->阿里云<--/-->华为云<--/官网&#xff0c;轻量型云服务器低至112元/年&#xff0c;新用户首次下单享超低折扣。 目录 一、Qt Creator快捷键 二、对象树 1、对象树的析构 2、自定义类的编写…

K8S--安装Nginx

原文网址&#xff1a;K8S--安装Nginx-CSDN博客 简介 本文介绍K8S安装Nginx的方法。 1.创建Nginx目录及配置文件 mkdir -p /work/devops/k8s/app/nginx/{config,html} 在config目录下创建nginx.conf配置文件&#xff0c;内容如下&#xff1a; # events必须要有 events {wo…

TestCaseAssiant使用说明

目录 说明 工具界面 功能描述 Xmind转测试用例 测试组件 测试用例 用例优先级 用例前提 用例操作步骤 用例期望结果 Excel测试用例转Testlink xml 用例模板 使用技巧: TestLink Xml转Excel测试用例 说明 本文为小编之前博文中介绍的工具使用说明 Xmind转Excel测…