数据结构:直接插入排序,希尔排序,选择排序,堆排序,冒泡排序,快速排序,归并排序,计数排序(C实现)

news2024/10/2 14:30:05

在这里插入图片描述

个人主页 : 个人主页
个人专栏 : 《数据结构》 《C语言》

文章目录

  • 前言
  • 一、插入排序
    • 1.直接插入排序
    • 2.希尔排序
  • 二、选择排序
    • 1. 选择排序
    • 2.堆排序
  • 三、交换排序
    • 1.冒泡排序
    • 2.快速排序(递归)
      • a.hoare版(PartSort1)
      • b.挖坑法(PartSort2)
      • c.前后指针法(PartSort3)
    • 3.快速排序(非递归)
  • 四、归并排序
    • 归并排序(递归)
    • 归并排序(非递归)
  • 五、计数排序
  • 总结


前言

排序:使一串数据,按照其中的某个或某些关键字的大小,递增或递减的排列起来的操作。
在这里插入图片描述


一、插入排序

插入排序的思路:把待排序数组,逐个插入到已经排好序的有序数组中,直到所有待排序数组插入完成,的到一个新的有序数组。

1.直接插入排序

假如要排序为升序数组。
遍历待排序数组,将待排序数组元素与已排序数组元素比较,如果已排序数组元素大于待排序数组元素,已排序数组元素后移,待排序数组再次于前一个已排序数组比较,直到遍历完已排序数组或待排序数组元素大于已排序数组元素。
在这里插入图片描述

// 插入排序
//遍历待排序数组,每次选择数组元素 与 已排序数组元素比较,如果该数组元素小于已排序数组元素,已排序元素后移
//直到该数组元素遍历到首或大于已排序数组元素,插入该位置。
void InsertSort(int* a, int n)
{
	for (int i = 0; i < n - 1; i++)
	{
		int j = i;
		int tmp = a[i + 1];
		while (j >= 0)
		{
			if (tmp < a[j])
			{
				a[j + 1] = a[j];
			}
			else
			{
				break;
			}

			j--;
		}

		a[j + 1] = tmp;
	}
}
  • 时间复杂度:O(N^2)
  • 空间复杂度:O(1)
  • 稳定性:稳定

2.希尔排序

我们要知道 待排序数组越接近有序,直接插入排序算法的时间效率越高
那么我们如果使一个待排序数组快速变成接近有序的数组,再对接近有序的数组进行一次直接插入排序,就是希尔排序

  • 那对于希尔排序的一个问题,如何使待排序数组快速变成接近有序数组

这就要使用gap(增益变量),对待排序数组每隔gap的元素进行直接插入排序,再对待排序数组每隔(gap/2)的元素进行直接插入排序,再对待排序数组每隔(gap/2)的元素进行直接插入排序…
直到gap为1时,待排序数组已经接近有序数组。在对待排序数组直接插入排序即可。

如下:对数组{9,1,2,5,7,4,8,6,3,5}进行希尔排序
在这里插入图片描述

// 希尔排序
//1、使待排序数组变成接近有序的数组   2、对接近有序的数组直接插入排序  O(n)
//使用gap(增益变量)来使待排序数组快速变成接近有序的数组
void ShellSort(int* a, int n)
{
	int gap = n;

	while (gap > 1)
	{
		gap = gap / 3 + 1; // + 1 保证最后一次排序一定是插入排序 or gap /= 2
		for (int i = 0; i < n - gap; i++)
		{
			int j = i;
			int tmp = a[j + gap];
			while (j >= 0)
			{
				if (a[j] > tmp)
				{
					a[j + gap] = a[j];
				}
				else
				{
					break;
				}

				j -= gap;
			}

			a[j + gap] = tmp;
		}
	}
}
  • 时间复杂度:O(N^1.3)
  • 空间复杂度:O(1)
  • 稳定性:不稳定

二、选择排序

选择排序的思想:每次从待排序数组中选择出最大or最小的元素,放入已排序数组后,直到待排序数组中没有元素时,数组完成排序。

1. 选择排序

在这里插入图片描述
每次从待排序数组中选择最小的元素,与已排序数组的后一个元素交换,直到待排序数组中没有元素结束。


// 选择排序
//遍历待排序数组,每次选择最小的待排序数组元素,与待排序数组首元素交换。
void SelectSort(int* a, int n)
{
	for (int i = 0; i < n; i++)
	{
		int minIndex = i;
		for (int j = i + 1; j < n; j++)
		{
			if (a[minIndex] > a[j])
			{
				minIndex = j;
			}
		}
		swap(&a[minIndex], &a[i]);
	}
}
  • 时间复杂度:O(N^2)
  • 空间复杂度:O(1)
  • 稳定性:稳定

2.堆排序

堆排序详解
堆排序就是将待排序数组,构建为大堆(升序)or小堆(降序),然后将堆顶元素与待排序数组最后元素交换,删除堆最后的数据,再次选择新的堆顶元素。重复上述操作即可。

如下: 对数组 {16, 72, 31, 94, 53, 23}降序
在这里插入图片描述
在这里插入图片描述

// 堆排序
//升序建大堆
void AdjustDwon(int* a, int n, int parent)
{
	int child = parent * 2 + 1;
	while (parent < n)
	{
		//选择左右孩子较大值
		if (child + 1 < n && a[child] < a[child + 1])
		{
			child++;
		}

		if (child < n && a[parent] < a[child])
		{
			swap(&a[parent], &a[child]);
			parent = child;
			child = parent * 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[0], &a[end]);
		AdjustDwon(a, end, 0);
		end--;
	}
}
  • 时间复杂度:O(N*logN)
  • 空间复杂度:O(1)
  • 稳定性:不稳定

三、交换排序

交换排序思想:根据待排序数组中两个元素的比较结果交换两个元素在待排序数组中的位置。

1.冒泡排序

在这里插入图片描述
从待排序数组中每次比较相邻的两个元素,如果前一个元素大于后一个元素,交换两个元素。如果前一个元素小于等于后一个元素,不变。继续向后比较相邻的两个元素。

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

// 冒泡排序
void BubbleSort(int* a, int n)
{
	for (int i = 0; i < n; i++)
	{
		int flag = 1;
		for (int j = 0; j < n - i - 1; j++)
		{
			if (a[j] > a[j + 1])
			{
				flag = 0;
				swap(&a[j], &a[j + 1]);
			}
		}
		//如果flag == 1表示这趟比较,并未交换元素,表示数组已经有序
		if (flag == 1)
		{
			break;
		}
	}
}
  • 时间复杂度:O(N^2)
  • 空间复杂度:O(1)
  • 稳定性:稳定

2.快速排序(递归)

快速排序(递归)思路:任取待排序数组中的某个元素为基准值,以该基准值为标准,将待排序数组分成左右两个子序列,左子序列都小于基准值,右子序列都大于该基准值,然后左右子序列重复该操作,直到左右子序列只有一个元素or没有元素结束,此时数组有序。

//类似于二叉树的先序遍历
void QuickSort(int* a, int left, int right)
{
	if (left >= right)
		return;

	int pivot = PartSort3(a, left, right);
	//int pivot = PartSort2(a, left, right);
	//int pivot = PartSort1(a, left, right);
	//区间[left, pivot - 1]  pivot  [pivot + 1, right]

	QuickSort(a, left, pivot - 1);
	QuickSort(a, pivot + 1, right);
}

那么快排是如何以基准值来区分左右子序列?

a.hoare版(PartSort1)

以待排序数组第一个元素为基准值,定义两个变量(left,right)分别指向待排序数组的左右边界。
先移动right,找到小于基准值的元素,right停止移动。移动left,找到大于基准值的元素,left停止移动,交换left 与 right的元素。重复上述操作,直到left 与 right 指向同一个元素,交换此时基准值 与 left指向的元素。就完成了以基准值为标准,将数组分成左右子数组。

如下:对数组{6,1,2,7,9,3,4,5,10,8}以6为基准值,来划分左右子序列
在这里插入图片描述
注意

如何保证left 与 right 相遇的位置值一定小于基准值?

left 与 right相遇有两种情况:

  • left 遇到 right ,此时right已经停止移动,代表right已经找到了小于基准值的元素,left 与 right相遇的值小于基准值
  • right 遇到 left,上一次left 与 right 都找到相应元素并交换 or 此时left指向的就是数组最左边,此时left指向元素小于等于基准值,left 与 right相遇的值小于基准值

这是以右边界为基准值为列。如果以左边界为基准值,要保证left 与 right相遇元素小于基准值,要left先移动。

left要不要从基准值的位置开始移动?

  • left必须从基准值的位置开始移动,假设对数组{0,2,5,9,1,3}进行快排,如果以0为基准值,left从2的位置开始移动,会导致2到0的左边去,使数组变为{2,0,5,9,1,3}。就不符合快排的划分。
//三数取中  针对已经有序的数组
int GetMiddle(int* a, int left, int right)
{
	int mid = (right - left) / 2 + left;

	if (a[mid] > a[left])
	{	
		if (a[mid] < a[right])
		{
			//left < mid < right
			return mid;
		}
		else if(a[left] > a[right])
		{
			//right < left < mid
			return left;
		}
		else
		{
			//left < right = mid
			return right;
		}
	}
	else
	{
		if (a[right] > a[left])
		{
			//mid < left < right
			return left;
		}
		else if (a[mid] < a[right])
		{
			//mid < right < left
			return right;
		}
		else
		{
			//right <= mid <= left
			return mid;
		}
	}
}

// 快速排序hoare版本
//注意1. 如何保证每次left == right时的值,小于等于keyi的值
//结束时两种情况  a.right遇left停,上一次循环结束时,right 与 left的值互换,此时left的值为小于等于keyi的值
//                b.left遇right停,这次循环right结束时,此时right的值小于等于keyi的值
//注意2. left开始要从keyi的位置起步
//如果left从keyi+1的位置起步,假如数组所有元素大于keyi的值,循环结束交换left与keyi的值,回造成keyi左右的值都大于keyi
int PartSort1(int* a, int left, int right)
{
	int keyi = GetMiddle(a, left, right);
	swap(&a[keyi], &a[left]);
	keyi = left;

	while (left < right)
	{
		while (left < right && a[right] > a[keyi])
		{
			right--;
		}

		while (left < right && a[left] <= a[keyi])
		{
			left++;
		}

		swap(&a[left], &a[right]);
	}
	swap(&a[keyi], &a[left]);

	return left;
}

b.挖坑法(PartSort2)

挖坑法与hoare的思路类似,保存基准值位置的元素(key),使right找小于等于key的元素,left找大于key的元素,只不过left 与 right每次找到元素时,直接赋值到hole(坑位)处。不需要等left 与 right 都找到元素,才进行操作。

在这里插入图片描述

//三数取中
int GetMiddle(int* a, int left, int right)
{
	int mid = (right - left) / 2 + left;

	if (a[mid] > a[left])
	{	
		if (a[mid] < a[right])
		{
			//left < mid < right
			return mid;
		}
		else if(a[left] > a[right])
		{
			//right < left < mid
			return left;
		}
		else
		{
			//left < right = mid
			return right;
		}
	}
	else
	{
		if (a[right] > a[left])
		{
			//mid < left < right
			return left;
		}
		else if (a[mid] < a[right])
		{
			//mid < right < left
			return right;
		}
		else
		{
			//right <= mid <= left
			return mid;
		}
	}
}


// 快速排序挖坑法  
//每找到一个不符合要求的数,交换
int PartSort2(int* a, int left, int right)
{
	int keyi = GetMiddle(a, left, right);
	swap(&a[keyi], &a[left]);

	int key = a[left];
	int hole = left;
	while (left < right)
	{
		while (left < right && a[right] > key)
		{
			right--;
		}
		swap(&a[hole], &a[right]);
		hole = right;

		while (left < right && a[left] <= key)
		{
			left++;
		}
		swap(&a[hole], &a[left]);
		hole = left;
	}

	a[hole] = key;
	return hole;
}

c.前后指针法(PartSort3)

前后指针法也就是双指针法,一个指针cur遍历待排序数组,一个指针prev指向小于等于基准值(key)的最后一个元素。如果cur指向元素小于等于key,使prev先移动,在交换cur 与 prev指向的元素。如果cur指向元素大于key,cur移动,prev不动。直到cur遍历完数组,交换prev指向元素 与
key.。即可将数组分成小于key key 大于key的三部分。

在这里插入图片描述

//三数取中
int GetMiddle(int* a, int left, int right)
{
	int mid = (right - left) / 2 + left;

	if (a[mid] > a[left])
	{	
		if (a[mid] < a[right])
		{
			//left < mid < right
			return mid;
		}
		else if(a[left] > a[right])
		{
			//right < left < mid
			return left;
		}
		else
		{
			//left < right = mid
			return right;
		}
	}
	else
	{
		if (a[right] > a[left])
		{
			//mid < left < right
			return left;
		}
		else if (a[mid] < a[right])
		{
			//mid < right < left
			return right;
		}
		else
		{
			//right <= mid <= left
			return mid;
		}
	}
}

//思路类似于,在数组中删除val的值。
int PartSort3(int* a, int left, int right)
{
	int keyi = GetMiddle(a, left, right);
	swap(&a[keyi], &a[left]);

	keyi = left;
	int prev = left;
	for (int cur = left + 1; cur <= right; cur++)
	{
		//不能判断为 prev + 1 != cur 如果9,1,2,3,4,5,6。此时keyi的值为9。cur遍历到2时,会使9与2交换,使keyi的值发生改变
		if (a[cur] < a[keyi] && ++prev != cur)
		{
			//prev++;
			swap(&a[prev], &a[cur]);
		}
	}

	swap(&a[prev], &a[keyi]);
	return prev;
}

3.快速排序(非递归)

用栈的先进后出模拟递归。
先将此时数组元素范围[0,sz]压栈,然后将栈顶数据出栈,定为start 与 end。在以start 与 end为区间,选取基准值(key),划分左子序列,右子序列。再将左子序列,右子序列的区间分别入栈。重复上述过程,如果左右子区间不存在就不入栈,直到栈中没有数据,此时数组已完成排序。

如下:
在这里插入图片描述

栈的代码在这里

//三数取中
int GetMiddle(int* a, int left, int right)
{
	int mid = (right - left) / 2 + left;

	if (a[mid] > a[left])
	{	
		if (a[mid] < a[right])
		{
			//left < mid < right
			return mid;
		}
		else if(a[left] > a[right])
		{
			//right < left < mid
			return left;
		}
		else
		{
			//left < right = mid
			return right;
		}
	}
	else
	{
		if (a[right] > a[left])
		{
			//mid < left < right
			return left;
		}
		else if (a[mid] < a[right])
		{
			//mid < right < left
			return right;
		}
		else
		{
			//right <= mid <= left
			return mid;
		}
	}
}

//思路类似于,在数组中删除val的值。
int PartSort3(int* a, int left, int right)
{
	int keyi = GetMiddle(a, left, right);
	swap(&a[keyi], &a[left]);

	keyi = left;
	int prev = left;
	for (int cur = left + 1; cur <= right; cur++)
	{
		//不能判断为 prev + 1 != cur 如果9,1,2,3,4,5,6。此时keyi的值为9。cur遍历到2时,会使9与2交换,使keyi的值发生改变
		if (a[cur] < a[keyi] && ++prev != cur)
		{
			//prev++;
			swap(&a[prev], &a[cur]);
		}
	}

	swap(&a[prev], &a[keyi]);
	return prev;
}


// 快速排序 非递归实现
//借助栈的先进后出,先进左区间,再进右区间。
void QuickSortNonR(int* a, int left, int right)
{
	Stack s;
	StackInit(&s);

	StackPush(&s, left);
	StackPush(&s, right);
	while (!StackEmpty(&s))
	{
		int end = StackTop(&s);
		StackPop(&s);
		int stark = StackTop(&s);
		StackPop(&s);

		int pivot = PartSort3(a, stark, end);
		// [start, pivot - 1]  pivot  [pivot + 1, end]
		//左区间
		if (stark < pivot - 1)
		{
			StackPush(&s, stark);
			StackPush(&s, pivot - 1);
		}
		//右区间
		if (pivot + 1 < end)
		{
			StackPush(&s, pivot + 1);
			StackPush(&s, end);
		}
	}

	StackDestroy(&s);
}

  • 快排的时间复杂度:O(NlogN)
  • 快排的空间复杂度:O(logN)
  • 稳定性:不稳定
  • 如果是对一组元素相同的数据处理,那么快排的时间复杂度就退化为O(N^2),三路划分可以解决这类问题。

四、归并排序

归并排序思路:先将待排序数组分解为有序数组,再两两合并有序数组。

归并排序(递归)

在这里插入图片描述
如上图,我们对数组{10,6,7,1,3,9,4,3}进行分解,直到每个区间只有一个元素时(保证每个区间都是有序的),再两两合并区间(需要借助额外的数组tmp来保存合并的数组,再将tmp数组copy置原数组中)。[类似于二叉树的后序遍历]

// 归并排序递归实现
void _MergeSort(int* a, int start, int end, int* tmp)
{
	if (start == end)
		return;

	int mid = (end - start) / 2 + start;
	//[start, mid] [mid + 1, end]
	_MergeSort(a, start, mid, tmp);
	_MergeSort(a, mid + 1, end, tmp);

	//合并有序数组
	int begin1 = start, end1 = mid;
	int begin2 = mid + 1, end2 = end;
	int i = begin1;
	while (begin1 <= end1 && begin2 <= end2)
	{
		if (a[begin1] <= a[begin2])
		{
			tmp[i++] = a[begin1++];
		}
		else
		{
			tmp[i++] = a[begin2++];
		}
	}

	while (begin1 <= end1)
	{
		tmp[i++] = a[begin1++];
	}

	while (begin2 <= end2)
	{
		tmp[i++] = a[begin2++];
	}
	//要注意每次copy数组的起始位置
	memcpy(a + start, tmp + start, sizeof(int)*(end - start + 1));
}


//类似于二叉树的后序遍历
void MergeSort(int* a, int n)
{
	int* tmp = (int*)malloc(sizeof(int) * (n + 1));
	if (tmp == NULL)
	{
		perror("malloc:");
		exit(-1);
	}
	
	_MergeSort(a, 0, n - 1, tmp);
	free(tmp);
}

归并排序(非递归)

归并排序的非递归实现并不需要借助栈或队列,只用循环即可完成。
我们先对待排序数组中一个元素与一个元素两两合并,再对数组中两个元素与两个元素两两合并,再对数组中四个元素与四个元素两两合并,直到要合并的元素个数大于数组元素结束,此时数组有序。

在这里插入图片描述

如果在合并最后一组有序数组时,有一下情况要注意:

  • 情况1:end2 > begin2 > end1 > sz(数组元素个数 - 1),begin1 < sz。
  • 情况2:end2 > begin2 > sz(数组元素个数 - 1), begin1 < end1 = sz
  • 情况3:end2 > sz,begin1 < end1 < begin2 < sz
    在这里插入图片描述
    对于情况1,情况2而言,我们只需要结束这次合并即可,因为begin1 到 sz的区间内数组是有序的
    对于情况3而言,我们只需要改变end2即可,使end2 = sz。
// 归并排序非递归实现
void MergeSortNonR(int* a, int n)
{
	int* tmp = (int*)malloc(sizeof(int) * (n + 1));
	if (tmp == NULL)
	{
		perror("malloc:");
		exit(-1);
	}
	
	for (int gap = 1; gap < n; gap *= 2)
	{
		for (int i = 0; i < n; i += 2 * gap)
		{
			int begin1 = i, end1 = i + gap - 1;
			int begin2 = i + gap, end2 = begin2 + gap - 1;

			if (end1 >= n || begin2 >= n)
				break;
			if (end2 >= n)
				end2 = n - 1;

			int j = begin1;
			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));
		}//for (int i = 0; i < n; i += 2 * gap)
	}//for (int gap = 1; gap <= n / 2; gap++)

	free(tmp);
}
  • 时间复杂度:O(NlogN)
  • 空间复杂度:O(N)
  • 稳定性:稳定
  • 归并排序思路更多解决的是外排序问题

五、计数排序

计数排序也就是建立一个映射关系,来进行排序。
我们先在待排序数组中查找最大值(max) 与 最小值(min),再创建一个空间(tmp)大小为(max - min + 1)的数组,将次tmp置0,遍历待排序数组,将每个元素 - min所对应在tmp的位置+1。再遍历tmp空间,如果tmp中元素不为0的,将其加上min,放入待排序数组并将tmp中元素减一。

在这里插入图片描述

// 计数排序
void CountSort(int* a, int n)
{
	int min = a[0], max = a[0];
	for (int i = 0; i < n; i++)
	{
		if (min > a[i])
			min = a[i];
		if (max < a[i])
			max = a[i];
	}

	int* tmp = (int*)malloc(sizeof(int) * (max - min + 1));
	if (tmp == NULL)
	{
		perror("malloc");
		exit(-1);
	}
	memset(tmp, 0, sizeof(int) * (max - min + 1));

	for (int i = 0; i < n; i++)
	{
		tmp[a[i] - min]++;
	}

	int k = 0;
	int i = 0;
	while (i < (max - min + 1))
	{
		if (tmp[i] != 0)
		{
			a[k++] = i + min;
			tmp[i] -= 1;
		}
		else
		{
			i++;
		}
	}

	free(tmp);
}
  • 时间复杂度:O(N)
  • 对于数组元素并不是集中的,会造成空间浪费

总结

以上就是我对于直接插入排序,希尔排序,选择排序,堆排序,冒泡排序,快速排序,归并排序的理解。感谢支持!!!
在这里插入图片描述

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

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

相关文章

基于引力搜索算法优化的BP神经网络(预测应用) - 附代码

基于引力搜索算法优化的BP神经网络&#xff08;预测应用&#xff09; - 附代码 文章目录 基于引力搜索算法优化的BP神经网络&#xff08;预测应用&#xff09; - 附代码1.数据介绍2.引力搜索优化BP神经网络2.1 BP神经网络参数设置2.2 引力搜索算法应用 4.测试结果&#xff1a;5…

Mr. Cappuccino的第64杯咖啡——Spring循环依赖问题

Spring循环依赖问题 什么是循环依赖问题示例项目结构项目代码运行结果 Async注解导致的问题使用Lazy注解解决Async注解导致的问题开启Aop使用代理对象示例项目结构项目代码运行结果 Spring是如何解决循环依赖问题的原理源码解读 什么情况下Spring无法解决循环依赖问题 什么是循…

nginx部署 vue配置代理服务器 解决跨域问题

为了演示方便使用的是windows部署 1.首先将vue打包 2.打包好的vue放入到nginx-1.24.0\html\下,这里我创建一个big-data文件夹所以放入到big-data方便多项目管理 3.打开nginx.conf的配置文件修改 server {listen 8081;server_name localhost;location /{alias html/big-data…

锐捷校园网使用指南

Linux ubantu linux客户端下载 进入到下载目录解压 进入解压后的文件目录&#xff0c;修改文件权限 开始使用&#xff0c;了解一些命令&#xff0c;查看帮助 连接有线网络 sudo ./rjsupplicant -u 你的校园网账号 -p 你的密码 -d 1 然后输入当前linux ip账户的密码&#xff0c…

19.图,图的两种存储结构

目录 一. 一些基本概念 二. 图的抽象数据类型定义 三. 图的存储结构 &#xff08;1&#xff09;数组表示法&#xff08;邻接矩阵表示法&#xff09; &#xff08;a&#xff09;邻接矩阵 &#xff08;b&#xff09;存储表示 &#xff08;c&#xff09;优缺点分析 &#x…

无限计算力:探索云计算的无限可能性

这里写目录标题 前言云计算介绍服务模型&#xff1a; 应用领域&#xff1a;云计算主要体现在生活中的地方云计算未来发展的方向 前言 云计算是一种基于互联网的计算模型&#xff0c;通过它可以实现资源的共享、存储、管理和处理。它已经成为许多个人、企业和组织的重要技术基础…

变压器绝缘油色谱分析试验

试验目的 分析油中溶解气体的组分和含量是监视充油设备安全运行的最有效措施之一。 该 方法适用于充有矿物质绝缘油和以纸或层压板为绝缘材料的电气设备。 对判断充油电 气设备内部故障有价值的气体包括: 氢气 (H2 )、 甲烷 (CH4 )、 乙烷 (C2 H6 )、 乙烯 (C2H4 )、 乙炔 (C2…

mybatis讲解(2)之动态SQL的运用

目录 经典面试题&#xff1a; 1.mybatis动态sql 2.模糊查询&#xff08;3种方式&#xff09; 3.查询返回结果集 总结&#xff1a; 前言&#xff1a;在我上篇已经学习了Mybatis简介以及如何去连接数据库&#xff0c;具有增删改查的方法。那么我们今天来学习Mybatis的第二节关…

苹果叶病害识别(Python代码,pyTorch框架,预训练好的VGG16模型,也很容易替换为其它模型,带有GUI识别界面)

代码运行要求&#xff1a;Torch>1.13.1即可 1.数据集介绍&#xff1a; Apple Scab类文件夹图片 Black Rot类文件夹图片 Cedar Apple Rust文件夹 healthy文件夹 2.整个项目 data文件夹存放的是未被划分训练集和测试集的原始照片 picture文件夹存放的是经hf.py对data文件夹…

docker 02(docker 命令)

一、docker服务命令 systemctl start docker 启动docker服务 [参考] systemctl status docker 状态 systemctl stop docker 停止docker服务 systemctl restart docker 重启动docker服务 systemctl enable docker 开机自启动docker服务 &#xff0c;无需手动 二、docke…

远程调试环境配置

目录 一、准备工作 二、ssh连接和xdebug配置 1.ssh连接 2.xdebug配置 三、xdebug调试&#xff0c;访问 一、准备工作 1.安装vscode里面的两个扩展 2.安装对应PHP版本的xdebug 去xdebug官方&#xff0c;复制自己的phpinfo源码到方框里&#xff0c;再点击Analyse Xdebug: …

【UML】软件工程中常用图:类图、部署图、时序图、状态图

前言&#xff1a; UML中的很多东西平时都听过、用过&#xff0c;诸如类图、时序图等&#xff0c;本文将详细详细讲一下UML中常用的几类图&#xff0c;并且会引入一个完整的例子来讲解&#xff0c;UML在工程上到底该怎么合理使用。 目录 1.概述 1.1.什么是UML&#xff1f; …

C++入门---vector常用函数介绍及使用

vector的介绍 vector是表示可变大小数组的序列容器。就像数组一样&#xff0c;vector也采用的连续存储空间来存储元素。也就是意味着可以采用下标对vector的元素进行访问&#xff0c;和数组一样高效。但是又不像数组&#xff0c;它的大小是可以动态改变的&#xff0c;而且它的大…

第1章:计算机网络体系结构

文章目录 1.1 计算机网络 概述1.概念2.组成3.功能4.分类5.性能指标1.2 计算机网络 体系结构&参考模型1.分层结构2.协议、接口、服务3.ISO/OSI模型4.TCP/IP模型1.1 计算机网络 概述 1.概念 2.组成 1.组成部分&

docker搭建redis三主三从集群,及其常见问题解决

目录结构 redis.conf主要参数 每个配置文件都要修改对应的端口 bind 0.0.0.0 protected-mode no #每个配置文件都要修改端口 port 6379 tcp-backlog 511 timeout 0 tcp-keepalive 300 supervised no loglevel notice #日志文件路径 #logfile "/mydata/master_redis/log/…

逻辑回归原理,最大化似然函数和最小化损失函数

目录 逻辑回归原理 最大化似然函数和最小化损失函数 一、逻辑回归基本概念 1. 什么是逻辑回归 2. 逻辑回归的优缺点 3. 逻辑回归和多重线性回归的区别 Poisson分布 泊松分布的特点&#xff1a; 泊松分布用途 4. 逻辑回归用途 5. Regression 常规步骤 逻辑回归原理 …

代码随想录 (五)栈和队列

1栈与队列基础知识待看 2.用栈实现队列 题意有说操作是有效的&#xff0c;不用去判断非法的情况 class MyQueue { public:stack<int> stIn;stack<int> stOut; MyQueue() {}void push(int x) {stIn.push(x);}//出队并返回该元素 int pop() {if (stOut.empty()) {…

使用 Nacos 作为 Spring Boot 配置中心

&#x1f337;&#x1f341; 博主猫头虎 带您 Go to New World.✨&#x1f341; &#x1f984; 博客首页——猫头虎的博客&#x1f390; &#x1f433;《面试题大全专栏》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33a; &a…

数据并行(DP)、张量模型并行(TP)、流水线并行(PP)

数据并行 数据集分为n块&#xff0c;每块随机分配到m个设备(worker)中&#xff0c;相当于m个batch并行训练n/m轮&#xff0c;模型也被复制为n块&#xff0c;每块模型均在每块数据上进行训练&#xff0c;各自完成前向和后向的计算得到梯度&#xff0c;对梯度进行更新&#xff0…

【TypeScript】声明文件

在 TypeScript 中&#xff0c;声明文件&#xff08;Declaration Files&#xff09;用于描述已有 JavaScript 代码库的类型信息&#xff0c;以便在 TypeScript 项目中使用这些代码库时获得类型支持。 当你在 TypeScript 项目中引用外部 JavaScript 模块或库时&#xff0c;可能会…