排序(直接插入,希尔,选择,快排)

news2024/11/16 15:50:24

文章目录

  • 插入排序
    • 直接插入排序
    • 希尔排序
  • 选择排序
    • 直接选择排序
    • 堆排序
  • 交换排序
    • 冒泡排序:
    • 快速排序(hoare版本)
      • 快速排序优化(三数取中)
      • 快速排序优化(小区间优化)
    • 快速排序(挖坑法)
    • 快速排序(前后指针法)
    • 快速排序(非递归法)
  • 归并排序
    • 递归方法

插入排序

基本思想:
把待排序的记录按其关键码值的大小逐个插入到一个已经排好序的有序序列中,直到所有的记录插入完为 止,得到一个新的有序序列 。
实际中我们玩扑克牌时,就用了插入排序的思想。
在这里插入图片描述

直接插入排序

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

我们在对一组数据排序时,插入数据之前的数据已经有序,对新插入有的数据进行比较就行 。例如数组,第一个数是有序,从第二个数进行向前比较,前两个数有序,然后第三个数有序,依次向后。
在这里插入图片描述

时间复杂度:O(n^2)
最好情况:O(n) 顺序有序

/********************************直接插入排序********************************
时间复杂度O(n^2)
最好情况O(n) 顺序有序
*/

void InsertSort(int* a, int n)//数组的地址,数组的元素个数
{
	for (int i = 0; i < n - 1; i++)//从下标为0的地方开始,一直到下标为n - 2;排列整个数组,因为是要插入的数要大一位
	{
		int end = i;//最后一个元素下标
		int temp = a[end + 1];
		while (end >= 0)
		{
			if (a[end] > temp)
			{
				a[end + 1] = a[end];
				end--;
			}
			else
			{
				break;
			}
		}
		a[end + 1] = temp;
	}
}

希尔排序

希尔排序法又称缩小增量法。
基本思想:
分为预排序和直接排序,在gap等于1之前都是预排序,让数据接近有序,gap等于1的时候在进行的排序就是直接插入排序,最终数据变得有序。
先选定一个整数gap,把待排序文件中所有数据分成 n/gap 个组,所有距离为gap的数据分在同一组内,并对每一组内的记录进行排序。然后,取 gap = gap /3 + 1 重复上述分组和排序的工作。当到达 gap=1 时,所有数据在统一组内排好序。

在这里插入图片描述

希尔排序之所以可以更快的进行排序时因为,可以让目标数字更快的跑到前面,相比于直接插入排序,希尔排序一次走多步,直接插入排序只能一次走一步。gap越大,调的越快,但是也越不接近有序。gap越小,调的越慢,越接近有序,gap等于1的时候就是有序。

预排序:
通过两个for进行预排序,第二层是一组,外面的for是换下一组。

int gap = 3;
for (int j = 0; j < gap; j++)
{
	for (int i = j; i < n - gap; i = i + gap)//注意:i <= n - 1 - gap,n - 1是下标
	{
		int end = i;
		int temp = a[end + gap];
		while (end >= 0)
		{
			if (a[end] > temp)
			{
				a[end + gap] = a[end];
				end = end - gap;
			}
			else
			{
				break;
			}
		}
		a[end + gap] = temp;
	}
}

上面的代码可以优化:

++i是与上面最大的区别,一组一组排优化成多组并排
每组排前两个,++i往下进行后面的排序

int gap = 3;
for (int i = 0; i < n - gap; ++i)//++i是与上面最大的区别,优化成一组多组并排
{
	int end = i;
	int temp = a[end + gap];
	while (end >= 0)
	{
		if (temp < a[end])
		{
			a[end + gap] = a[end];
			end -= gap;
		}
		else
		{
			break;
		}
	}
	a[end + gap] = temp;
}

因为排序的精度随着gap的大小改变,但是我们gap不能固定,要随着数据的增大而增大,不然数据很大的时候gap值很小就会极大的增加排序的时间。
于是整体希尔排序代码为:

void ShellSort(int* a, int n)
{
	int gap = n;//数据越大,gap应该越大。
	while (gap > 1)//不能写成gap大于0,如果gap等于1就会一直进入循环
	{
		gap = gap / 3 + 1;
		for (int i = 0; i < n - gap; ++i)//++i是与上面最大的区别,优化成一组多组并排
		{
			int end = i;
			int temp = a[end + gap];
			while (end >= 0)
			{
				if (temp < a[end])
				{
					a[end + gap] = a[end];
					end -= gap;
				}
				else
				{
					break;
				}
			}
			a[end + gap] = temp;
		}
	}
}

时间复杂度分析:第一个gap排序后,gap变化,上一次的排序会对下一次有影响,所以时间复杂度并不好分析。在这里插入图片描述
按照课本上的说法大概就是O(n^1.3)。

希尔排序的特性总结:

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

选择排序

基本思想:每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,直到全部待排序的数据元素排完 。

直接选择排序

在元素集合array[i]–array[n-1]中选择关键码最大(小)的数据元素
若它不是这组元素中的最后一个(第一个)元素,则将它与这组元素中的最后一个(第一个)元素交换
在剩余的array[i]–array[n-2](array[i+1]–array[n-1])集合中,重复上述步骤,直到集合剩余1个元素
选择最小的或者最大的,放在指定位置,每次选择一个
在这里插入图片描述

时间复杂度O(n^2)
最好情况:O(n^2)

void SelectSort(int* a, int n)
{
	int begin = 0;
	int end = n - 1;
	while (begin < end)
	{
		int minnum = begin;
		int maxnum = begin;
		for (int i = begin + 1; i <= end; i++)
		{
			if (a[i] < a[minnum])
			{
				minnum = i;
			}
			if (a[i] > a[maxnum])
			{
				maxnum = i;
			}
		}
		int tempmin = a[minnum];
		int tempmax = a[maxnum];
		a[minnum] = a[begin];
		a[begin] = tempmin;
		if (maxnum == begin)//如果最大值的下标原来就是begin的话,就会被覆盖,所以要判断一下
		{
			maxnum = minnum;
		}
		a[maxnum] = a[end];
		a[end] = tempmax;
		++begin;
		--end;
	}
}

堆排序

对数组进行向下调整建堆,然后进行堆排序
具体堆排序可见堆排序

void AdjustDown(int* p, int size, int parent)
{
	int child = parent * 2 + 1;
	while (child < size)
	{
		if (child + 1 < size && p[child] > p[child + 1])//不能保证右孩子一定存在
		{//如果换成大堆的话把>换成<
			child++;
		}
		if (p[child] < p[parent])//如果换成大堆的话把<换成>
		{
			Swap(&p[child], &p[parent]);
			parent = child;
			child = parent * 2 + 1;
		}
		else
		{
			break;
		}
	}
}
void HeapSort(int* p, int n)//不开辟空间,在原数组上进行堆排序
{
	assert(p);
	/*for (int i = 1; i < n; i++)
	{
		AdjustUP(p, i);
	}*/
	for (int i = (n - 1 - 1) / 2; i >= 0; --i)//n - 1是最后一个结点的下标,再减一除2就是最后一个非叶子结点
	{
		AdjustDown(p, n, i);
	}
	int end = n - 1;//end是数组下标,n是数据个数
	while (end > 0)
	{
		Swap(&p[0], &p[end]);
		AdjustDown(p, end, 0);//第二个参数是数据个数,少了队尾数据个数就是队尾的数据下标
		--end;
	}
}

需要注意的是,如果大量数据相同的时候,堆排序会进行交换顺序,导致不必要的时间浪费,所以相对希尔排序,当出现大量的相同数据时,时间就会慢一些。 这也是为什么堆排序不稳定的原因

时间复杂度:
堆排序前要建堆,建堆的时间复杂度时O(n),排序的过程时间复杂度时O(nlogn),所以总的时间复杂度还是O(nlogn)。

交换排序

基本思想:
所谓交换,就是根据序列中两个记录键值的比较结果来对换这两个记录在序列中的位置,交换排序的特点是:将键值较大的记录向序列的尾部移动,键值较小的记录向序列的前部移动。

冒泡排序:

  1. 冒泡排序是一种非常容易理解的排序
  2. 时间复杂度:O(N^2)
  3. 空间复杂度:O(1)
  4. 稳定性:稳定
    在这里插入图片描述
void BubbleSort(int* a, int n)
{
	int temp = 0;
	for (int end = n - 1; end > 0; end--)//end是最后一个元素的下标
	{
		int flag = 1;
		for (int i = 0; i < end; i++)
		{
			if (a[i] > a[i + 1])
			{
				temp = a[i];
				a[i] = a[i + 1];
				a[i + 1] = temp;
				flag = 0;
			}
		}
		if (flag)
			break;
	}
}

快速排序(hoare版本)

基本思想:
找到目标值,与目标值进行比较,比目标值大的放在一边,小的放在另一边。两边都有序了,那么结果就变得有序了。

在这里插入图片描述
在这里插入图片描述
快排类似二叉树,运用递归进行排序

二叉树展开的时候会存在不存在的区间的情况,比如,45展开的时候,
4的展开函数参数是('‘, 3,3),就是自己和自己交换,但是5的展开就是('’,5,4),此时begin大于end。所以回归的条件就时begin >= end

void QuickSort(int* a, int begin, int end)
{
	if (begin >= end)
		return;
	int keyi = begin;
	int left = begin, right = end;//left不能等于begin + 1,不然在数据有序的情况下也会发生交换,导致bug 
	while (left < right)
	{//里面两个while循环至少要有一个等号,不然遇到相等的数要进入死循环,如果只有一个相等,那么只会增加循环次数,两个等号就会直接跳过

		while (left < right && a[right] >= a[keyi])
		{
			right--;
		}
		while (left < right && a[left] <= a[keyi])//保证相遇的时候不在继续走
		{
			left++;
		}
		int temp = a[right];
		a[right] = a[left];
		a[left] = temp;
	}
	int min = a[right];
	a[right] = a[keyi];
	a[keyi] = min;
	keyi = right;//上面说left不能等于begin + 1否则就导致BUG的就是这四句
	QuickSort(a, begin, keyi - 1);
	QuickSort(a, keyi + 1, end);
}

代码中上下两个while循环至少要有一个等号,不然遇到相等的数要进入死循环,如果只有一个相等,那么只会增加循环次数,两个等号就会直接跳过。

快速排序优化(三数取中)

注意:
如果数据已经有序的情况下,快排所消耗的时间相对于其他排序所消耗的时间会多很多,因为key的选择是从左往右依次选择,一直进行下去的。几乎把所有的数据都当作key选择了一遍。
这样递归所消耗的空间很大,尤其在DeBug版本下调试的时候,很容易栈溢出。在release版本下不明显。
所有可以这样优化,三数取中,这样就会减少很多递归,在中间的数和最前面的数和最后面的数中选择一个大小中间的数作为key放在开头。

int Getmid(int* a, int begin, int end)
{
	int mid = (begin + end) / 2;
	if (a[begin] <= a[end])
	{
		if (a[mid] < a[begin])
		{
			return begin;
		}
		else if (a[mid] > a[end])
		{

			return end;
		}
		else
			return mid;
	}
	else
	{
		if (a[mid] < a[end])
		{
			return end;
		}
		else if (a[mid] > a[begin])
		{

			return begin;
		}
		else
			return mid;
	}
}

寻找中间大的数当作key然后在快排开始处插入此代码,得到数据的下标,让数据和begin交换
在这里插入图片描述

为什么最后交换的总是比keyi小呢?
因为我们规定的右边先走,总是找到小的数才去找大的数,在没有找到小的数之前会一直走。找到以后交换,假设已经没有比keyi位置小的数,那么就会一直走到上次交换的那个数的位置,然后与keyi进行交换。
假设找到小没有找到大,那么左边一直和右边相遇,那么直接进行交换,假设整体都比keyi大,那么右边一直走到begin,然后自己与自己交换。
如果是keyi在右面,那么就让左边先走,找大进行交换

快速排序优化(小区间优化)

我们在快排里面进行两次递归,思想类似于二叉树,我们,最后几层总是占用大量的空间

二叉树占用:
在这里插入图片描述

递归占用:
在这里插入图片描述

假设我有1万个数,在第一次递归的时候被分成5000与5000,然后再被分成2500,2500。但随着不断的这么进行递归下去,尤其是在最后面末流,比如说递归的区间范围是七个数,然后把七个数这个区间在递归分治分成三个数与三个数,然后对于三个数的区间也在进行递归分治划分,就会发现有点大题小做,还挺麻烦的。你会发现为了让这七个数有序,我们实际上居然递归了七次。

我们会发现,最后几个数却占了递归总数的很大一部分。
于是可以使用其他的排序方法对最后几个数进行排序。
前面几种排序方法中,直接插入排序对小区间的排序比较有优势,因为对于直接插入排序而言,只要在这个数据段当中,有几部分小段小段是有序的,对于他的优势就非常大。对于堆排也麻烦还要建堆。库函数也是这么优化的。堆排序和希尔排序都是对大量的数据才有优势。

void QuickSort2(int* a, int begin, int end)
{
	if (begin >= end)
		return;
	if (end - begin + 1 < 20)
	{
		InsertSort(a + begin, end - begin + 1);//参数是数组的地址,数组的元素个数
	}
	else
	{
		int mid = Getmid(a, begin, end);
		int tempmid = a[mid];
		a[mid] = a[begin];
		a[begin] = tempmid;
		int keyi = begin;
		int left = begin, right = end;//left不能等于begin + 1,不然在数据有序的情况下也会发生交换,导致bug
		while (left < right)
		{
			while (left < right && a[right] >= a[keyi])//上下两个循环至少要有一个等号,不然遇到相等的数要进入死循环,如果只有一个相等,那么只会增加循环次数,两个等号就会直接跳过
			{
				right--;
			}
			while (left < right && a[left] <= a[keyi])//保证相遇的时候不在继续走
			{
				left++;
			}
			int temp = a[right];
			a[right] = a[left];
			a[left] = temp;
		}
		int min = a[right];
		a[right] = a[keyi];
		a[keyi] = min;
		keyi = right;
		QuickSort2(a, begin, keyi - 1);
		QuickSort2(a, keyi + 1, end);
	}
}

在这里插入图片描述
这是当数据量为一千万的时候在Debug版本下的结果
在release版本下可能差距不大。

快速排序(挖坑法)

挖坑法相比霍尔版本要好理解一些,如果两个都掌握了,其实也差不多。我们保留上面写的三数取中和小区间优化

第一步:将key的位置(即为第一个元素的位置)作为第一个坑位,将key的值一直保存在变量key中。
第二步:定义一个right从数组最后一个元素开始即为数组右边开始向左遍历,如果找到比key小的值,right停下来,将right下标访问的元素赋值到上一个坑位,并将right作为新的坑位。
第三步:定义一个left从数组第一个元素开始即为数组左边开始向右遍历,如果找到比key大的值,left停下来,将left下标访问的元素赋值到上一个坑位,并将left作为新的坑位。
第四步:当right和left相遇时,此时它们访问的元素绝对是坑位,只需将key里保存的key值放入坑位即可。
第五步:让他们相遇位置的左区间和右区间同样执行上述四步(即为递归)。
在这里插入图片描述

代码:

void QuickSort3(int* a, int begin, int end)
{
	if (begin >= end)
		return;
	if (end - begin + 1 < 20)
	{
		InsertSort(a + begin, end - begin + 1);//参数是数组的地址,数组的元素个数
	}
	else
	{
		int mid = Getmid(a, begin, end);
		int tempmid = a[mid];
		a[mid] = a[begin];
		a[begin] = tempmid;

		int key = a[begin];
		int holei = begin;//holei存坑的下标
		int left = begin, right = end;
		while (left < right)
		{
			while (left < right && a[right] >= key)//上下两个循环至少要有一个等号,不然遇到相等的数要进入死循环,如果只有一个相等,那么只会增加循环次数,两个等号就会直接跳过
			{
				right--;
			}
			a[holei] = a[right];
			holei = right;
			while (left < right && a[left] <= key)//保证相遇的时候不在继续走
			{
				left++;
			}
			a[holei] = a[left];
			holei = left;
		}
		a[holei] = key;
		QuickSort3(a, begin, holei - 1);
		QuickSort3(a, holei + 1, end);
	}

}

快速排序(前后指针法)

前面几种快速排序本质上都没变,都是左右相向而行找大小,前后指针法本质上稍微变了一下,而且写起来也比较简单。

第一步:定义两根指针cur和prev
第二步:cur开始往后走,如果遇到比key小的值,则++prev,然后交换prev和cur指向的元素,再++cur,如果遇到比key大的值,则只++cur。
第三步:当cur访问过最后一个元素后,将key的元素与prve访问的元素交换位置。cur访问完整个数组后的各元素位置
第四步:让prev的左区间和右区间同样执行上述三步(即为递归)。
主要就是cur和prev在遇到比keyi大的之前都是紧挨着的,他们如果分开了,那么中间的就算是比keyi大的数。
在这里插入图片描述

void QuickSort4(int* a, int begin, int end)
{
	if (begin >= end)
		return;
	if (end - begin + 1 < 20)
	{
		InsertSort(a + begin, end - begin + 1);//参数是数组的地址,数组的元素个数
	}
	else
	{
		int mid = Getmid(a, begin, end);
		int tempmid = a[mid];
		a[mid] = a[begin];
		a[begin] = tempmid;

		int keyi = begin;
		int prev = begin, cur = prev + 1;//prev同样不能等于begin + 1,否则下面出循环后交换可能会出bug
		while (cur <= end)
		{
			//if (a[cur] < a[keyi])
			//{
			//	++prev;
			//	int temp = a[prev];
			//	a[prev] = a[cur];
			//	a[cur] = temp;
			//}
			//++cur;
			if (a[cur] < a[keyi] && ++prev != cur)//这样可以避免自己和自己交换浪费时间
			{
				int temp = a[prev];
				a[prev] = a[cur];
				a[cur] = temp;
			}
			++cur;
		}
		int temp = a[keyi];
		a[keyi] = a[prev];
		a[prev] = temp;
		QuickSort4(a, begin, prev - 1);
		QuickSort4(a, prev + 1, end);
	}
}

快速排序(非递归法)

非递归法的思想其实还是递归,递归是确定了keyi位置以后,再对左右区间进行排序。非递归法,我们可以把左右区间的下表存起来,然后分别对每个区间进行排序就好了。我们一般使用栈这个数据结构来存区间下标,然后上面快排的单趟排序来实现。这里选择刚刚写的,前后指针的方法。
在这里插入图片描述

前后指针单趟排序代码:

int PartSort4(int* a, int begin, int end)//前后指针的单趟排序代码,去掉了小区间优化
{
	int mid = Getmid(a, begin, end);
	int tempmid = a[mid];
	a[mid] = a[begin];
	a[begin] = tempmid;

	int keyi = begin;
	int prev = begin, cur = prev + 1;//prev同样不能等于begin + 1,否则下面出循环后交换可能会出bug
	while (cur <= end)
	{
		if (a[cur] < a[keyi] && ++prev != cur)//这样可以避免自己和自己交换浪费时间
		{
			int temp = a[prev];
			a[prev] = a[cur];
			a[cur] = temp;
		}
		++cur;
	}
	int temp = a[keyi];
	a[keyi] = a[prev];
	a[prev] = temp;
	return prev;//返回的是排好的那个数据的下标
}

非递归法最主要的就是如何把区间下标存下来,然后分别对他们进行排序,如果有其他方法,不用栈也可以。
其实非递归法也是递归的思想,都是分而治之。
关于栈的介绍:链接: 栈的实现
注意:
使用栈存的话是有先后顺序的,后进先出要牢记。

void QuickSortNonR(int* a, int begin, int end)//快排非递归
{
	ST st;
	StackInit(&st);
	StackPush(&st, end);
	StackPush(&st, begin);//注意栈是后进先出的,所以入栈顺序有要求
	while (!StackEmpty(&st))
	{
		int left = StackTop(&st);
		StackPop(&st);
		int right = StackTop(&st);
		StackPop(&st);
		int keyi = PartSort4(a, left, right);
		//[left, keyi - 1] keyi [keyi + 1, right]
		if (right > keyi + 1)
		{
			StackPush(&st, right);
			StackPush(&st, keyi + 1);
		}
		if (left < keyi - 1)
		{
			StackPush(&st, keyi - 1);
			StackPush(&st, left);
		}//用栈来存左右未调整的区间的下表
	}
	StackDestory(&st);
}

归并排序

归并排序是将两边先排好,然后再进行排序的一种排序方式
在这里插入图片描述
在这里插入图片描述

需要借助额外的数组进行排序,先把前半部分排好,再把后半部分排好,两部分再在新的数组里面进行尾插,找两部分里面小的那部分进行尾插。最后全部在新的数组里面排好以后再拷贝到原来的数组中。

递归方法

如上图所示,最开始无序的数组会被一直分割,直到还剩一个数的时候,此时一个数是有序的,然后左右都是一个数的时候开始归并,执行排序的代码。对每个数据都是这样 。
具体就是想要使最开始的数组有序,就要是左右两部分都有序。然后使左右两部分都有序,就要使他们各自的左右两部分都有序,一直循环下去,直到最后两个数,然后开始归并。

void _MergeSort(int* a, int begin, int end, int* tmp)
{
	if (begin >= end)
		return;
	int mid = (begin + end) / 2;
	_MergeSort(a, begin, mid, tmp);//左边没有排好之前会一直递归下去,直到只剩一个数的时候
	_MergeSort(a, mid + 1, end, tmp);//每段区间的begin都不一样,但是都是按照顺序的,下一段区间的begin就是上一段区间的end + 1
	int begin1 = begin, end1 = mid;
	int begin2 = mid + 1, end2 = end;
	int begin_tmp = begin;
	while (begin1 <= end1 && begin2 <= end2)
	{
		if (a[begin1] < a[begin2])
		{
			tmp[begin_tmp++] = a[begin1++];
		}
		else
		{
			tmp[begin_tmp++] = a[begin2++];
		}
	}
	while (begin1 <= end1)
	{
		tmp[begin_tmp++] = a[begin1++];
	}
	while (begin2 <= end2)
	{
		tmp[begin_tmp++] = a[begin2++];
	}
	memcpy(a + begin, tmp + begin, sizeof(int) * (end - begin + 1));
	//每段区间的begin都不一样,但是都是按照顺序的,下一段区间的begin就是上一段区间的end + 1
}

void MergeSort(int* a, int begin, int end)
{
	int* tmp = malloc(sizeof(int) * (end - begin + 1));
	if (tmp == NULL)
	{
		perror("malloc fail");
		return;
	}
	_MergeSort(a, begin, end, tmp);
	free(tmp);
}

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

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

相关文章

Unity转Unreal5从入门到精通之UMG的使用

前言 UMG (Unreal Motion Graphics UI Designer)是Unreal种的可视化 UI 工具。它就类似于Unity中的UGUI,可用于为用户创建游戏内 HUD、菜单和其他与界面相关的图形。 UMG 的核心是UI控件。它可用于创建UI界面&#xff08;按钮、复选框、滑块、进度条等&#xff09;。 快速入…

HiveSQL实战——大数据开发面试高频SQL题

查询每个区域的男女用户数 0 问题描述 每个区域内男生、女生分别有多少个 1 数据准备 use wxthive; create table t1_stu_table (id int,name string,class string,sex string ); insert overwrite table t1_stu_table values(4,张文华,二区,男),(3,李思雨,一区,女),(1…

linux -- Git基础使用

git是什么 简单说来Git是一个开源的分布式版本控制系统&#xff0c;那么什么是分布式呢&#xff0c;就是每个开发者拥有完整的本地仓库副本&#xff0c;包括所有历史记录和分支&#xff0c;可以独立工作&#xff0c;并通过合并来同步变更。 git优点 速度极快 Git在合并、分…

嵌入式 - 什么是数字晶体管

What is a digital transistor? 数字晶体管是一种集成电阻器的双极晶体管。 A digital transistor is a bipolar transistor that integrates resistors. Concerning internal resistor R1 / 关于内部电阻 R1 R1 的作用是通过将输入电压转换为电流来稳定晶体管的工作。 如果…

【秋招笔试】8.17京东秋招第二场(后端岗)-三语言题解

🍭 大家好这里是 春秋招笔试突围,一起备战大厂笔试 💻 ACM金牌团队🏅️ | 多次AK大厂笔试 | 编程一对一辅导 ✨ 本系列打算持续跟新 春秋招笔试题 👏 感谢大家的订阅➕ 和 喜欢💗 和 手里的小花花🌸 ✨ 笔试合集传送们 -> 🧷春秋招笔试合集 🍒 本专栏已收…

Nginx:高效HTTP服务器与反向代理

Nginx&#xff1a;高效HTTP服务器与反向代理 1、核心特点2、应用场景 &#x1f496;The Begin&#x1f496;点点关注&#xff0c;收藏不迷路&#x1f496; Nginx&#xff0c;一个开源的HTTP服务器与反向代理工具&#xff0c;因其高性能、低资源消耗而备受推崇。以下是Nginx的几…

Python 全栈系列261 使用apscheduler

说明 任务可以分为两种&#xff1a; 1 静态(存量)任务2 动态(增量)任务 对于静态任务来说&#xff0c;一般可以事先分好大小均匀的若干block任务&#xff0c;这时候比较强调使用分布式系统进行快速处理&#xff1b;对于动态任务来说&#xff0c;主要按时间区块大小划分。对于…

[JAVA] Java中如何使用throws语句声明异常类型

如果一个方法可能会出现异常&#xff0c;但没有能力处理这种异常&#xff0c;可以在方法声明处用throws子句来声明抛出异常 — throws语句用在方法定义时声明该方法要抛出的异常类型 public void method() throws Exception1,Exception2,...ExceptionN{//可能产生异常的代码 }…

LVS配置

基础介绍 http://t.csdnimg.cn/Lv5Byhttp://t.csdnimg.cn/Lv5By 部署NAT模式集群案例 实验环境 主机名 IP vip 角色 node1 192.168.0.100 172.25.254.100 调度器&#xff08; VS &#xff09; node1 192.168.0.101 &#xff0c; GW 192.168.0.100 \ 真实服务器&#…

HarmonyOS开发案例:创建全局自定义组件复用池-BuilderNode

介绍 本示例是全局自定义组件复用实现的示例代码&#xff0c;主要讲解如何通过BuilderNode创建全局的自定义组件复用池&#xff0c;实现跨页面的组件复用。 效果图预览 使用说明 继承NodeController&#xff0c;实现可复用的NodeItem组件。使用单例模式创建NodePool组件复用…

leetcode算法题之N皇后

N皇后也是一道很经典的问题&#xff0c;问题如下&#xff1a; 题目地址 按照国际象棋的规则&#xff0c;皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。 n 皇后问题 研究的是如何将 n 个皇后放置在 nn 的棋盘上&#xff0c;并且使皇后彼此之间不能相互攻击。 给你…

2:html:基础语法2

目录 2.1图像的一些注意点 2.2表格 2.2.1基本的表格 2.2.2表头与边框 2.3列表 2.3.1无序列表 2.3.2有序列表 2.4块 2.4.1块级元素 2.4.2内联元素 2.1图像的一些注意点 在上一篇中&#xff0c;我们已经知道了怎么样去将图片运用到我们的网站中&#xff0c;但是这里还…

荣耀Magicbook x14 扩容1TB固态

版权归作者所有&#xff0c;如有转发&#xff0c;请注明文章出处&#xff1a;https://cyrus-studio.github.io/blog/ 固态硬盘规格 在官网查看加装固态硬盘的接口规格 https://www.honor.com/cn/laptops/honor-magicbook-x14-2023/ https://club.honor.com/cn/thread-2847379…

XYplorer v26.30.0200绿色版

软件介绍 XYplorers是一款多标签文件管理器&#xff0c;支持多标签页栏&#xff0c;浏览文件管理时就跟使用Chrome之类的浏览器感觉一般&#xff0c;从浏览方便性&#xff0c;和切换滑顺程度&#xff0c;要比原本Windows10的Explorer文件管理器要得多。可以大部分程度上替代系…

树莓派5环境配置笔记 新建虚拟python环境—安装第三方库—配置Thonny解释器

树莓派5虚拟环境配及第三方库的安装&#x1f680; 在完成了树莓派的系统下载和各项基础配置之后进入到了&#xff0c;传感器开发部分&#xff0c;在测试传感器开发之前我打算先安装一下自己需要的库&#xff0c;但是在我直接在系统的根目录下运行pip命令的时候总会报环境错误&a…

sudo执行带重定向命令时仍提示无权限:Permission denied问题详解以及linux里的更高效下载命令mwget安装和使用效率对比

一、sudo执行带重定向命令时仍提示无权限&#xff1a;Permission denied问题详解 小问题&#xff0c;在此记录一下&#xff0c;有时在shell下执行命令重定向到文件时提示无权限-bash: temp_20181015.log: Permission denied&#xff0c;而且加sudo执行依提示无权限&#xff0c;…

CDD数据库文件制作(四)——Data Type(0x22/0x2E)

文章目录 1、新建Data Type步骤2、Data Types类型2.1 raw value2.1.1 ASCII读取和写入:零件号…2.1.2 “多字节的十六进制” 读取和写入:密钥,种子…2.1.3 “多字节的十进制” 读取和写入:参数标定和显示2.2 text table2.3 Linear2.3.1 分辨率和偏移量非1和0的读取和写入2.…

linux:进程优先级、环境变量、地址空间

进程优先级 什么叫进程优先级&#xff1f; 进程优先级是指进程获取某些资源的先后顺序 上文中的task_struct&#xff0c;也叫进程控制块&#xff08;PCB&#xff09;&#xff0c;本质上是结构体&#xff0c;我们的优先级就被写在结构体里面&#xff08;内部字段&#xff09;…

Python | Leetcode Python题解之第345题反转字符串中的元音字母

题目&#xff1a; 题解&#xff1a; class Solution:def reverseVowels(self, s: str) -> str:def isVowel(ch: str) -> bool:return ch in "aeiouAEIOU"n len(s)s list(s)i, j 0, n - 1while i < j:while i < n and not isVowel(s[i]):i 1while j …

模型 神经网络(通俗解读)

系列文章 分享 模型&#xff0c;了解更多&#x1f449; 模型_思维模型目录。仿脑智能&#xff0c;深度学习&#xff0c;精准识别。 1 神经网络的应用 1.1 鸢尾花分类经典问题 神经网络的一个经典且详细的经典应用是鸢尾花分类问题 。主要是通过构建一个神经网络模型来自动区分…