六大排序精解

news2024/9/22 1:13:30

排序概念

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

排序的几种分类

常见的排序算法及主要思想:

- 插入排序:每次将一个元素插入到已经排好序的有序序列中,从前向后依次对所有元素进行插入排序。

- 选择排序:每次在待排序的数据元素中选出最小(或最大)的一个元素,然后将其与第一个元素交换位置。

- 冒泡排序:通过相邻元素之间的比较和交换位置的方式,使得每次比较后最大(或最小)的元素都会沉底。

- 希尔排序:是插入排序的一种更高效的改进版本。它利用插入排序在近乎有序的情况下的性能,通过预先部分排序将输入序列分割成几个子序列,分别进行插入排序。

- 归并排序:采用分治法(Divide and Conquer)的思想,将已有序的子序列合并,得到完全有序的序列。

- 快速排序:通过一趟排序将待排记录分割成独立的两部分,其中一部分记录的关键字均比另一部分的关键字小,则可分别对这两部分记录继续进行排序,以达到整个序列有序。

- 堆排序:利用堆这种数据结构来排序。通过构建大顶堆和调整堆的方式,每次都能找到当前序列的最大值。

以上是几种常见的排序算法,它们的时间复杂度和稳定性不同。排序的目的是使数据按某种顺序排列,是算法和数据结构中重要的基础概念。

排序过程与实现

1.冒泡排序

1.1 主要思想及过程

主要思想是通过不断比较相邻的元素并交换它们,使得较大(或较小)的元素逐渐“浮”到数组的一端。具体来说,冒泡排序的主要步骤如下:

  1. 从数组的第一个元素开始,依次比较相邻的两个元素,如果顺序不对则交换它们,使得较大(或较小)的元素向后移动。
  2. 继续对数组中的每一对相邻元素进行比较和交换,直到所有元素都被遍历一次。这样一次遍历之后,最大(或最小)的元素就会“冒泡”到数组的末尾。
  3. 重复以上步骤,每次遍历都会将当前未排序部分的最大(或最小)元素“冒泡”到相应位置,直到整个数组有序。

冒泡排序的时间复杂度为O(n2),其中n为数组的长度。尽管冒泡排序简单直观,但对于大规模数据集来说效率较低,通常不适用于大型数据排序。

下图是冒泡排序的过程动图。 

1.2 代码实现 

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

运行结果 

2. 选择排序 

2.1 主要思想及过程 

主要思想是在未排序部分中选择最小(或最大)的元素,然后将其放到已排序部分的末尾。

选择排序的主要步骤如下:

  1. 从数组中选择最小(或最大)的元素,将其与数组的第一个元素交换位置,此时第一个元素就是已排序部分的最小(或最大)元素。
  2. 在剩余未排序的部分中继续选择最小(或最大)的元素,将其与已排序部分的末尾元素交换位置,将其加入已排序部分。
  3. 重复以上步骤,每次选择出未排序部分的最小(或最大)元素并加入已排序部分,直到整个数组排序完成。

选择排序的时间复杂度也为O(n2),其中n为数组的长度。虽然选择排序比冒泡排序稍微高效一些,但仍然不适用于大规模数据排序。和冒泡排序一样,选择排序是一种简单但不够高效的排序算法。

动图如下:

2.2 代码实现 

这里的代码思想相较上图有所改进,遍历一次同时记录未排序部分的最大与最小值,而后交换至未排序部分的首尾处。 

void SelectSort(int* a, int n)
{
	int begin = 0, end = n - 1;//从首尾同时开始
	while (begin < end)
	{
		int max_i = end, min_i = begin;//先假定max与min所在位置
		for (int i = begin; i <= end; i++)//每一趟遍历都找到一个max与min
		{//这里不能对begin与end做修改
			if (a[i] < a[min_i])
			{
				min_i = i;//更新min的位置
			}
			if (a[i] > a[max_i])
			{
				max_i = i;//更新max的位置
			}
		}
		Swap(&a[begin], &a[min_i]);//交换min与begin处的值
		if (begin == max_i)//如果此时begin与max在同一位置,那么之前的交换就将max交换到了min处
		{
			max_i = min_i;//这种情况下更新max位置
		}
		Swap(&a[end], &a[max_i]);
		--end;
		++begin;
	}
}

 运行结果

3. 插入排序 

3.1 主要思想及过程 

主要思想是将未排序部分的元素逐个插入到已排序部分的合适位置,从而逐步构建有序序列。

插入排序的主要步骤如下:

1. 将数组视为两部分:已排序部分和未排序部分。初始时,已排序部分只包含数组的第一个元素,而未排序部分包含剩余的元素。
2. 从未排序部分取出第一个元素,将其插入到已排序部分的合适位置,使得插入后仍然保持有序。
3. 继续从未排序部分取出元素,逐个插入到已排序部分的合适位置,直到未排序部分为空,所有元素都被排序。

插入排序的时间复杂度为O(n^2),最好情况下是O(n),其中n为数组的长度。插入排序在处理小型数据集或部分有序的数据时表现良好,因为它的内循环在有序部分中的操作次数较少。因此,插入排序通常用于对小型数据集进行排序,或作为其他排序算法的一部分。

 动图如下:

3.2 代码实现 

void InsertSort(int* a, int n)
{
	for (int i = 0; i < n-1; i++)
	{
		int end = i;//已排序部分的最后一个
		int tmp = a[end + 1];//未排序元素
		while (end >= 0)
		{
			if (a[end] > tmp)//已排序部分的末位大于tmp
			{
				a[end + 1] = a[end];//元素后移
				end--;//end左移
			}
			else//找到合适位置,退出循环
			{
				break;
			}
		}
		a[end + 1] = tmp;//将tmp插入
	}	
}

运行结果

 4. 希尔排序

4.1 主要思想及过程

希尔排序(Shell Sort)是一种改进的插入排序算法,也被称为“缩小增量排序”。希尔排序通过将数组分割成若干个子序列,对这些子序列分别进行插入排序,最后再对整个数组进行一次插入排序,从而实现对整个数组的排序。

希尔排序的主要步骤如下:

1. 选择一个增量序列,通常为n/2,n/4,n/8,...直到增量为1。
2. 对每个增量进行插入排序,即将数组分成若干个子序列,对每个子序列进行插入排序。
3. 逐渐减小增量,重复进行插入排序,直到增量为1。
4. 最后对整个数组进行一次插入排序。

希尔排序的时间复杂度取决于增量序列的选择,一般情况下在O(n\log n)到O(n^2)之间。希尔排序相比于插入排序有更好的性能,尤其适用于中等规模的数据集。希尔排序是一种高效的排序算法,尽管不如快速排序或归并排序那样高效,但在某些情况下仍然是一个不错的选择。

动图如下:

 4.2 代码实现

这里采取增量每次缩小三分之一的思想,最终的增量会变成1。

void ShellSort(int* a, int n)
{
	int gap = n;
	while (gap > 1)
	{
		gap =gap/3+1;//gap每次缩小三倍,直到为1进行一次直接插入排序
		for(int i=0;i<n-gap;i++)
		{
			int end = i;
			int tmp = a[end + gap];//以gap为单位,序列内相隔gap的元素为一组进行插入排序
			while (end >= 0)
			{
				if (a[end] > tmp)
				{
					a[end + gap] = a[end];//切记gap
					end-=gap;
				}
				else
				{
					break;
				}
			}
			a[end + gap] = tmp;
		}
	}

运行结果

5. 堆排序 

5.1 主要思想及过程 

堆排序(Heap Sort)是一种利用堆数据结构进行排序的算法,它利用了堆的性质来实现排序。堆是一种特殊的二叉树结构,分为最大堆和最小堆,其中最大堆满足父节点的值大于等于子节点的值,最小堆则相反。

堆排序的主要步骤如下:
1. 将待排序的数组构建成一个最大堆(或最小堆)。
2. 将堆顶元素(最大值或最小值)与堆的最后一个元素交换位置,然后对剩余的元素重新构建最大堆(或最小堆)。
3. 重复上述步骤,直到所有元素都被取出并排好序。

堆排序的时间复杂度为O(n*log n),其中n为数组的长度。堆排序是一种原地排序算法,不需要额外的空间,但由于其涉及到堆的构建和调整,实现起来较为复杂。堆排序适用于大规模数据集的排序,效率较高。

5.2 代码实现

这里我们建堆的过程使用向上调整算法,排序时使用向下调整算法

void BigADjustUP(int* a, int child)//大堆的向上调整,从子节点向上调整
{
	int parent = (child - 1) / 2;//寻找子节点的父亲
	while (child >= 0)
	{
		if (a[child] > a[parent])//如果孩子大于父亲,
		{
			Swap(&a[child], &a[parent]);//交换父子的位置
			child = parent;//更新孩子节点
			parent = (parent - 1) / 2;//更新父亲节点
		}
		else
			break;
	}
}
void BigADjustDown(int* a, int size, int parent)//大堆的向下调整
{
	int child = parent * 2 + 1;//找到父亲的孩子
	while (child < size)//孩子在size范围内
	{
		if (child + 1 < size && a[child] < a[child + 1])//左孩子小于右孩子
		{
			child = child + 1;//更新最大的孩子位置
		}
		if (a[child] > a[parent])//孩子大于父亲
		{
			Swap(&a[child], &a[parent]);//交换
			parent = child;//更新父亲与孩子的位置
			child = parent * 2 + 1;
		}
		else
			break;
	}
}

void HeapSort(int* a, int n)
{
	for (int i = 0; i < n; i++)
	{
		BigADjustUP(a,i);//建堆
	}
	//for (int i = 0; i < n; i++)
	while (n > 0)//每次找到一个最大值放在最后面
	{
		Swap(&a[0], &a[n - 1]);//交换最后的节点与根节点位置
		BigADjustDown(a, n - 1, 0);//向下调整
		n--;//每次调整完最后一个节点不再参与排序
	}
}

 运行结果

6. 快速排序 

快速排序有很多种方法,这里介绍四种:霍尔排序法、挖坑法、前后指针法、非递归法。 即前三种都是递归完成的。

 6.1 霍尔法

6.1.1 主要思想及过程

霍尔方法(Hoare Partition Scheme)是快速排序算法中一种常用的分区方案,由Tony Hoare提出。霍尔方法通过选择一个基准值(key),将数组分为两部分,使得左边的元素都小于等于基准值,右边的元素都大于等于基准值,然后递归地对左右两部分进行排序。

霍尔方法的主要步骤如下:
1. 选择一个基准值(通常是数组的第一个元素)作为key。
2. 设置两个指针,一个指向数组的起始位置,一个指向数组的末尾。
3. 移动右指针,直到找到一个小于等于key的元素;移动左指针,直到找到一个大于等于key的元素;如果左指针小于右指针,则交换这两个元素。
4. 重复步骤3,直到左指针大于等于右指针。
5. 将key与左指针所指的元素交换位置,此时key左边的元素都小于等于key,右边的元素都大于等于key。
6. 递归地对左右两部分进行排序。

动图:

6.1.2 代码实现 
int Getmidi(int* a, int begin, int end)//三数取中
{
	int midi = (begin + end) / 2;
	if (a[begin] < a[midi])
	{
		if (a[begin] > a[end])
			return begin;
		else if (a[midi] < a[end])
		{
			return midi;
		}
		else
			return end;
	}
	else
	{
		if (a[begin] < a[end])
			return begin;
		else if (a[midi] > a[end])
		{
			return midi;
		}
		else
			return end;
	}
}


int HoareQsort(int* a, int begin, int end)
{
	int mid_i = Getmidi(a, begin, end);//这里使用三数取中法来获取基准值,比之以首元素为基准值效率有所提升
	Swap(&a[mid_i], &a[begin]);
	int key_i = begin;//此时begin为三数的中间数
	int left = begin, right = end;//定义左右指针
	while (left < right)//两指针不能相遇
	{
		while (left < right && a[right] >= a[key_i])//右边先走,找小
		{
			right--;
		}
		while (left < right && a[left] <= a[key_i])//左边再走,找大
		{
			left++;
		}
		Swap(&a[left], &a[right]);//左右都停下,交换
	}
	Swap(&a[left], &a[key_i]);//此时左右指针相遇,交换指针与key_i处的值
	return left;//返回此时的keyi,此时keyi左边都比他小,右边都比他大,即位置已经固定
}



void HoareQuickSort(int* a, int begin, int end)//霍尔方法的递归
{
	if (begin >= end)//递归至每个区间只有一个元素,返回
		return;
	int key_i = HoareQsort(a, begin, end);//返回霍尔方法得出的固定位置
	HoareQuickSort(a, begin, key_i - 1);//以此位置为分割,分别递归左右方的区间
	HoareQuickSort(a, key_i + 1, end);
}

6.2 挖坑法 

6.2.1 主要思想及过程 

快速排序的挖坑法(Partition方法)是一种常用的快速排序算法,其主要思想是通过选取一个基准值(通常是数组的第一个元素),将数组分为两部分,一部分比基准值小,另一部分比基准值大,然后递归地对这两部分进行排序。

具体过程如下:
1. 选取一个基准值(通常是数组的第一个元素)作为比较标准。
2. 设置两个指针,一个指向数组的起始位置(一般是左指针),一个指向数组的末尾位置(一般是右指针)。
3. 从右边开始,找到第一个小于基准值的元素,将其填入左指针的位置,左指针向右移动。
4. 从左边开始,找到第一个大于基准值的元素,将其填入右指针的位置,右指针向左移动。
5. 重复步骤3和步骤4,直到左指针和右指针相遇。
6. 将基准值填入左指针和右指针相遇的位置,此时基准值左边的元素都小于基准值,基准值右边的元素都大于基准值。
7. 递归地对基准值左边的部分和右边的部分进行相同的操作,直到排序完成。

通过不断地将数组分割为两部分并对每部分进行排序,最终可以得到一个有序的数组。挖坑法是快速排序中常用的一种分区方法,可以高效地对数组进行排序。

事实上挖坑法与霍尔方法思想上差不多,每趟排序都会确定一个基准值的最终位置,也就是左右指针相遇的位置。

6.2.2 代码实现
int Getmidi(int* a, int begin, int end)//三数取中
{
	int midi = (begin + end) / 2;
	if (a[begin] < a[midi])
	{
		if (a[begin] > a[end])
			return begin;
		else if (a[midi] < a[end])
		{
			return midi;
		}
		else
			return end;
	}
	else
	{
		if (a[begin] < a[end])
			return begin;
		else if (a[midi] > a[end])
		{
			return midi;
		}
		else
			return end;
	}
}


int DigHoleQsort(int* a, int begin, int end)
{
	int mid_i = Getmidi(a, begin, end);//三数取中
	Swap(&a[mid_i], &a[begin]);//交换中间数至begin处
	int hole_i = begin;//在begin处挖坑
	int key = a[hole_i];//记录基准值
	int left = begin, right = end;
	while (left < right)//左右指针相遇即终止
	{
		while (left < right && a[right] >= key)//右边先走,找小
		{
			right--;
		}
		a[hole_i] = a[right];//找到小的填入坑内
		hole_i = right;
		while (left < right && a[left] <= key)//左边再走,找大
		{
			left++;
		}
		a[hole_i] = a[left];//找到大的填入坑内
		hole_i = left;
	}
	a[hole_i] = key;//将基准值填入坑内
	return hole_i;
}



void DigHoleQuickSort(int* a, int begin, int end)
{
	if (begin >= end)
		return;
	int key_i = DigHoleQsort(a, begin, end);
	DigHoleQuickSort(a, begin, key_i - 1);
	DigHoleQuickSort(a, key_i + 1, end);
}

6.3 前后指针法 

6.3.1 主要思想及过程 

 前后指针法是快速排序的另一种常用的分区方法,也称为双指针法或荷兰国旗问题。

具体过程如下:
1. 选取一个基准值(通常是数组的第一个元素)作为比较标准。
2. 设置两个指针,一个指向数组的起始位置(一般是左指针),一个指向数组的末尾位置(一般是右指针)。
3. 左指针向右移动,直到找到一个大于等于基准值的元素。
4. 右指针向左移动,直到找到一个小于等于基准值的元素。
5. 如果左指针小于右指针,交换两个指针所指向的元素。
6. 重复步骤3和步骤4,直到左指针大于等于右指针。
7. 将基准值与右指针所指向的元素交换位置,此时基准值左边的元素都小于基准值,基准值右边的元素都大于基准值。
8. 递归地对基准值左边的部分和右边的部分进行相同的操作,直到排序完成。

前后指针法通过左右指针的移动,实现了对数组的原地分区,可以高效地对数组进行排序。

6.3.2 代码实现
int Getmidi(int* a, int begin, int end)//三数取中
{
	int midi = (begin + end) / 2;
	if (a[begin] < a[midi])
	{
		if (a[begin] > a[end])
			return begin;
		else if (a[midi] < a[end])
		{
			return midi;
		}
		else
			return end;
	}
	else
	{
		if (a[begin] < a[end])
			return begin;
		else if (a[midi] > a[end])
		{
			return midi;
		}
		else
			return end;
	}
}
int Prev_LastPointerQSort(int* a, int begin, int end)
{
	//cur找小,找到就停止,与++prev交换,分区:0-prev(小于基准值),prev-cur(大于基准值),cur-end(未排序)
	
	int mid_i = Getmidi(a, begin, end);//三数取中
	Swap(&a[mid_i],&a[begin]);//交换中间数至begin处
	int key_i = begin;//记录基准值下标
	int prev = begin, cur = prev + 1;//定义前后指针

	while (cur <= end)//前面指针越界即停止
	{
		if (a[cur] < a[key_i] && ++prev != cur)//cur处小于基准值,并且prev的下一个不等于cur
		{
			Swap(&a[cur], &a[prev]);//交换cur与prev的值
		}
		++cur;//cur++
	}
	Swap(&a[prev], &a[key_i]);//循环结束,交换基准值与prev处元素
	key_i = prev;//此时基准值在prev处
	return key_i;//返回已确定元素的位置
}


void Prev_LastPointerQuickSort(int* a, int begin, int end)
{
	if (begin >= end)
		return;
	int key_i = Prev_LastPointerQSort(a, begin, end);
	Prev_LastPointerQuickSort(a, begin, key_i - 1);
	Prev_LastPointerQuickSort(a, key_i + 1, end);
}

6.4 快排的非递归实现 

6.4.1 主要思想及过程 

非递归法是指在实现快速排序时,不使用递归调用的方法来进行分区和排序。一种常见的非递归快速排序方法是使用栈来模拟递归调用的过程,实现分区和排序。

具体过程如下:
1. 将数组的起始位置和结束位置入栈,表示整个数组需要排序。
2. 循环执行以下步骤,直到栈为空:
   a. 出栈得到当前子数组的起始位置和结束位置。
   b. 选取一个基准值(通常是数组的第一个元素)作为比较标准。
   c. 使用前后指针法或挖坑法对当前子数组进行分区,将数组分为两部分。
   d. 将分区后的左右子数组的起始位置和结束位置入栈,表示需要对这两部分进行排序。
3. 循环结束后,整个数组就被排序完成。

通过使用栈来模拟递归调用的过程,非递归快速排序可以避免递归调用带来的额外开销,提高排序的效率。这种方法在实际应用中也是比较常见的一种实现方式。

6.4.2 代码实现

在c语言中,这里的栈是需要我们自己实现接口的。

void NonRecQsort(int* a, int begin, int end)
{
	Stack s;
	StackInit(&s);
	StackPush(&s, end);
	StackPush(&s, begin);//区间入栈
	while (StackEmpty(&s))//直到栈为空,所有区间出栈完成
	{
		int left = StackTop(&s);//区间出栈
		StackPop(&s);
		int right = StackTop(&s);
		StackPop(&s);
		int keyi = Prev_LastPointerQSort(a, left, right);//对区间进行一次排序,取keyi(左边的都比他小,右边的都比他大)
		if (left < keyi - 1)//左区间元素个数大于一
		{
			StackPush(&s, keyi - 1);
			StackPush(&s, left);
		}
		if (right > keyi + 1)//右区间元素个数大于1
		{
			StackPush(&s, right);
			StackPush(&s, keyi + 1);
		}

	}
	StackDestroy(&s);

}

各大排序效率比较 

这里是100000个随机数的排序

void Test01()
{
	srand(time(0));
	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);
	int* a8 = (int*)malloc(sizeof(int) * N);
	int* a9 = (int*)malloc(sizeof(int) * N);
	int* a10 = (int*)malloc(sizeof(int) * N);
	for (int i = 0; i < N; i++)
	{
		a1[i] = rand() + i;
		a2[i] = a1[i];
		a3[i] = a2[i];
		a4[i] = a3[i];
		a5[i] = a4[i];
		a6[i] = a5[i];
		a7[i] = a6[i];
		a8[i] = a7[i];	
		
	}

	int begin1 = clock();
	BubbleSort(a1, N);
	int end1 = clock();
	printf("BubbleSort() :  %d\n", end1-begin1);

	int begin2 = clock();
	InsertSort(a2, N);
	int end2 = clock();
	printf("InsertSort :  %d\n", end2 - begin2);

	int begin3 = clock();
	ShellSort(a3, N);
	int end3 = clock();
	printf("ShellSort :  %d\n", end3 - begin3);

	int begin4 = clock();
	SelectSort(a4, N);
	int end4 = clock();
	printf("SelectSort :  %d\n", end4 - begin4);

	int begin5 = clock();
	HoareQuickSort(a5, 0,N-1);
	int end5 = clock();
	printf("HoareQuickSort :  %d\n", end5 - begin5);

	int begin6 = clock();
	NonRecQsort(a6, 0, N - 1);
	int end6 = clock();
	printf("NonRecQsort :  %d\n", end6 - begin6);

	int begin7 = clock();
	DigHoleQuickSort(a7, 0, N - 1);
	int end7 = clock();
	printf("DigHoleQuickSort :  %d\n", end7 - begin7);

	int begin8 = clock();
	Prev_LastPointerQuickSort(a8, 0, N - 1);
	int end8 = clock();
	printf("Prev_LastPointerQuickSort :  %d\n", end8 - begin8);

	int begin9 = clock();
	HeapSort(a9,N);
	int end9 = clock();
	printf("HeapSort :  %d\n", end9 - begin9);
}

 

 

 

 

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

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

相关文章

Python 基于 OpenCV 视觉图像处理实战 之 OpenCV 简单实战案例 之四 简单复古怀旧照片效果

Python 基于 OpenCV 视觉图像处理实战 之 OpenCV 简单实战案例 之四 简单复古怀旧照片效果 目录 Python 基于 OpenCV 视觉图像处理实战 之 OpenCV 简单实战案例 之四 简单复古怀旧照片效果 一、简单介绍 二、简单复古怀旧照片效果实现原理 三、简单复古怀旧照片效果案例实现…

开源Thinkphp核心在线网页音乐播放php源码,附带系统搭建教程

安装教程 环境要求&#xff1a;apachePHP7.0Thinkphp伪静态 安装教程&#xff1a;修改Application目录下的database.php信息 导入根目录下的install.sql到数据库 修改Static目录下的player目录下的player.js文件的第140行的“域名”为你的域名 修改Static目录下的player2目录下…

Godot 学习笔记(4):一切以场景为中心

文章目录 前言场景搭建新建子场景最简单的按钮事件 手动控制场景手动加载场景添加多个场景对象更快速的获取脚本对象 删除多个场景对象脚本命名的问题 总结 前言 Godot的场景是C#与Godot最后的中间连接。我们解决了场景的加载&#xff0c;我们基本可以保证C#和godot之间的彻底…

ModbusRTU/TCP/profinet网关在西门子博图软件中无法连接PLC的解决方法

ModbusRTU/TCP/profinet网关在西门子博图软件中无法连接PLC的解决方法 在工业生产现场&#xff0c;ModbusRTU/TCP/profinet网关在与西门子PLC连接时&#xff0c;必须要使用西门子的博图软件来进行配置&#xff0c;博图v17是一个集成软件平台&#xff0c;专业版支持300、400、12…

【碳资产管理/精细化能源管控】Acrel-7000企业能源管控平台

工厂企业用能需求 能源管理 安科瑞薛瑶瑶18701709087 生产全过程用能数据监测和分析&#xff1b;完善并落实能源管理制度&#xff0c;使之更有效的运行&#xff1b;量化能效考核kpi&#xff0c;用数据说明问题。 用能安全 完善用能安全监测&#xff0c;保障人身与电气设备…

【计算机】——51单片机

单片机是一种内部包含CPU、存储器和输入/输出接口等电路的集成电路&#xff08;IC芯片&#xff09; 单片机是单片微型计算机&#xff08;Single Chip Microcomputer&#xff09;的简称&#xff0c;用于控制领域&#xff0c;所以又称为微型控制器&#xff08;Microcontroller U…

ubuntu20.04搭建nginx rtmp视频服务到指定位置解决权限不足

1.安装依赖 apt-get install build-essential libpcre3 libpcre3-dev libssl-dev2.建一个目录 mldir rtmp_nginx 3.源码下载 wget http://nginx.org/download/nginx-1.21.6.tar.gz wget https://github.com/arut/nginx-rtmp-module/archive/master.zip4.解压缩 tar -xf ng…

RabbitMQ--04--Spring Cloud Stream(消息驱动)

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 1.Spring Cloud Stream1. 基本介绍https://spring.io/projects/spring-cloud-stream#overview 2.Spring Cloud Stream 解决的痛点问题3.设计思想Stream为什么可以统…

游戏平台出海运营有难度吗?

随着全球互联网的飞速发展&#xff0c;游戏产业已经成为了文化娱乐领域的重要支柱。在这个背景下&#xff0c;越来越多的游戏平台开始寻求出海运营&#xff0c;以拓展海外市场&#xff0c;实现更大的商业价值。然而&#xff0c;游戏平台出海运营并非易事&#xff0c;其中涉及到…

【深度学习】最强算法之:深度神经网络(DNN)

深度神经网络 1、引言2、深度神经网络2.1 定义2.2 原理2.3 实现方式2.4 算法公式2.4.1 前向传播公式2.4.2 反向传播公式 2.5 代码示例 3、总结 1、引言 小屌丝&#xff1a;鱼哥&#xff0c;我遇到难题了 小鱼&#xff1a;然后呢 小屌丝&#xff1a;你帮我看看呗&#xff1f; 小…

sentinel热点参数流控

1、概念 热点参数限流会统计传入参数中的热点参数&#xff0c;并根据配置的限流阈值与模式&#xff0c;对包含热点参数的资源调用进行限流。热点参数限流可以看做是一种特殊的流量控制&#xff0c;仅对包含热点参数的资源调用生效。 2、示例 2.1、目的 对于如下的/get接口的参…

【CSS】flex弹性盒保持均分

通过Flex布局可以将容器均分&#xff0c;给每个小容器设置相同的flex-grow即可。 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge">&…

Flink入门知识点汇总(一)

具体内容请看b站尚硅谷课程&#xff01; 32_Flink运行时架构_提交流程_Yarn应用模式_哔哩哔哩_bilibili Flink本身有状态机制&#xff0c;状态都存储在Flink内部结构中&#xff0c;无需集成Mysql等对于精确一次Exactly-once&#xff0c;Flink进行了相关的配置&#xff0c;无需像…

综合知识篇15-开发管理考点(2024年软考高级系统架构设计师冲刺知识点总结系列文章)

专栏系列文章: 2024高级系统架构设计师备考资料(高频考点&真题&经验)https://blog.csdn.net/seeker1994/category_12593400.html案例分析篇00-【历年案例分析真题考点汇总】与【专栏文章案例分析高频考点目录】(2024年软考高级系统架构设计师冲刺知识点总结-案例…

CSS隐藏video标签中各种控件

1.edio标签加上controls会出现视频控件&#xff0c;如播放按钮、进度条、全屏、观看的当前时间、剩余时间、音量按钮、音量的控制条等等 <video type"video/mp4" src"" autoplay"" style"width: 400px; height: 300px;" id"e…

springboot-MybatisPlus

mybatisplus是来简化mybatis开发的&#xff0c;其中封装好了各种sql语句&#xff0c;我们直接调用即可&#xff0c;省略了编写mapper.xm映射文件的过程 MybatisPlus怎么来获取数据库表的信息&#xff1f; 默认以类型驼峰转下划线作为表名默认把id字段作为主键默认把变量名驼峰转…

eNSP--vlan技术

思路: 一、配置交换机与路由器, 二、通过DHCP 获取地址 单臂路由,实现访问要求,重点考察对vlan标签的处理和使用。 用到的接口有access,trunk,hybrid三种 (所有配置请以下图为准) 配置: 一、 sw1 sw1接口g0/0/1 指定access接口,属于vlan2; g0/0/2接口我们将它…

C#中解决字符串在编译后无法修改的情况

文章目录 一、配置文件二、使用方式对于.NET Framework应用程序&#xff08;使用app.config&#xff09;对于.NET Core和.NET 5/6应用程序&#xff08;使用appsettings.json&#xff09; 三、应用实例 一、配置文件 在C#等编程语言中&#xff0c;硬编码&#xff08;直接在代码…

#Linux(编写第一个命令)

&#xff08;一&#xff09;发行版&#xff1a;Ubuntu16.04.7 &#xff08;二&#xff09;记录&#xff1a; &#xff08;1&#xff09;编写一个c程序然后将生成的可执行的文件加入环境变量或者放入bin目录中&#xff0c;即可在其他目录下调用&#xff08;之前编写的程序只能在…

深度学习 Lecture 4 Adam算法、全连接层与卷积层的区别、图计算和反向传播

一、Adam算法&#xff08;自适应矩估计&#xff09; 全名&#xff1a;Adapative Moment Estimation 目的&#xff1a;最小化代价函数&#xff08;和梯度下降一样&#xff09; 本质&#xff1a;根据更新学习率后的情况自动更新学习率的值(可能是自动增大&#xff0c;也可能是…