【排序算法】实现快速排序值(霍尔法三指针法挖坑法优化随即选key中位数法小区间法非递归版本)

news2024/11/20 0:24:50

请添加图片描述

文章目录

  • 📝快速排序
    • 🌠霍尔法
    • 🌉三指针法
    • 🌠挖坑法
      • ✏️优化快速排序
  • 🌠随机选key
    • 🌉三位数取中
  • 🌠小区间选择走插入,可以减少90%左右的递归
  • 🌉 快速排序改非递归版本
  • 🚩总结


📝快速排序

快速排序是一种分治算法。它通过一趟排序将数据分割成独立的两部分,然后再分别对这两部分数据进行快速排序。

本文将用3种方法实现:

🌠霍尔法

霍尔法是一种快速排序中常用的单趟排序方法,由霍尔先发现。

它通过选定一个基准数key(通常是第一个元素),然后利用双指针leftright的方式进行排序,right指针先找比key基准值小的数,left然后找比key基准值大的数,找到后将两个数交换位置,同时实现大数右移和小数左移,当leftright相遇就排序完成,然后将下标key的值与left交换,返回基准数key的下标,完成了单趟排序。这一过程使得基准数左侧的元素都比基准数小,右侧的元素都比基准数大。

如图动图展示:
请添加图片描述
以下是单趟排序的详解图解过程:

  • beginend记录区间的范围,left记录做下标,从左向右遍历,right记录右下标,从右向左遍历,以第一个数key作为基基准值
    在这里插入图片描述
  • 先让right出发,找比key值小的值,找到就停下来
    在这里插入图片描述
  • 然后left再出发,找比key大的值,若是找到则停下来,与right的值进行交换
    在这里插入图片描述
  • 接着right继续找key小的值,找到后才让left找比key大的值,直到left相遇right,此时left会指向同一个数
    在这里插入图片描述
    在这里插入图片描述
  • leftright指向的数与key进行交换,单趟排序就完成了,最后将基准值的下标返回
    在这里插入图片描述
    为啥相遇位置比key要小->右边先走保证的
  1. LR: R先走,R在比key小的位置停下来了,L没有找到比key大的,就会跟R相遇相遇位置R停下的位置,是比key小的位置
  2. RL:第一轮以后的,先交换了,L位置的值小于key,R位置的值大于keyR启动找小,没有找到,跟L相遇了,相遇位置L停下位置,这个位置比key
  • 第一轮RL,那么就是R没有找到小的,直接就一路左移,遇到L,也就是key的位置

代码实现

void Swap(int* px, int* py)
{
	int tmp = *px;
	*px = *py;
	*py = tmp;
}

//Hoare经典随机快排
void QuickSort1(int* a, int left, int right)
{
	// 如果左指针大于等于右指针,表示数组为空或只有一个元素,直接返回
	if (left >= right)
		return;

	// 区间只有一个值或者不存在就是最小子问题
	int begin = left, end = right;// begin和end记录原始整个区间
	// keyi为基准值下标,初始化为左指针
	int keyi = left;

	 // 循环从left到right
	while (left < right)
	{
		// right先走,找小,这里和下面的left<right一方面也是为了防止,right一路走出区间,走到left-1越界
		while (left<right && a[right] >= a[keyi])
		{
			--right;
		}
		// 左指针移动,找比基准值大的元素   
		while (left<right && a[left] <= a[keyi])
		{
			++left;
		}
		Swap(&a[left], &a[right]);
	}
	// 交换左右指针所指元素
	Swap(&a[left], &a[keyi]);
	// 更新基准值下标
	keyi = left;
	
	// 递归排序左右两部分
	//[begin , keyi-1]keyi[keyi+1 , end]
	QuickSort1(a, begin, keyi - 1);
	QuickSort1(a, keyi + 1, end);

}

🌉三指针法

定义一个数组,第一个元素还是key基准值,定义前指针prev指向第一个数,后指针cur指向第二个数,让cur走,然后遍历数组,cur找到大于等于key基准值的数,cur++cur向前走一步。当cur指针小于key基准值时,后指针加一走一步(++prev),然后交换prevcur所指的值进行交换,因为这样cur一直都是小于key的值,让他继续向前不断找大的,而prev一直在找小的。依次类推,到cur遍历完数组,完成单趟排序。
如此动图理解:
请添加图片描述
简单总结:
在这里插入图片描述
以下是单趟排序的详解图解过程:

  1. 一开始,让prev指向第一个数,cur指向prev的下一位,此时cur位置的数比key基准值小,所以prev加一后,与cur位置的数交换,由于此时prev+1 == cur,自己跟自己交换,交换没变,完了让cur++走下一个位置。
    在这里插入图片描述
    紧接着:
    在这里插入图片描述

  2. cur继续前进,此时来到了7的位置,大于key的值6cur++继续向前走,来到9位置,9还是大于6,OK ! 我curcur++,来到3的位置,也是看到curprev拉开了距离,所以他又叫前后指针,这就体现出来,往下看–》
    在这里插入图片描述
    在这里插入图片描述

  3. 此时此刻,我cur的值小于key基准值,先让prev走一步,然后与cur的值交换交换
    在这里插入图片描述
    在这里插入图片描述

  4. 同样的步骤,重复上述遍历,直到遍历完数组

在这里插入图片描述在这里插入图片描述

  1. cur遍历完数组后,将交换prev的值key的基准值进行交换,交换完,将key的下标更新为prev下标的,然后返回key下标,完成单趟。
    在这里插入图片描述
    代码如下:
void QuickSort2(int* a, int left, int right)
{
	// 如果左指针大于等于右指针,表示数组为空或只有一个元素,直接返回
	if (left >= right)
		return;
		
	// keyi为基准值下标,初始化为左指针
	int keyi = left;
	
	// prev记录每次交换后的下标
	int prev = left;

	// cur为遍历指针
	int cur = left+1;
	
	// 循环从左指针+1的位置开始到右指针结束
	while (cur <= right)
	{
		// 如果cur位置元素小于基准值,并且prev不等于cur
	    // 就将prev和cur位置元素交换
	    // 并将prev后移一位
		if (a[cur] < a[keyi] && ++prev != cur)
			Swap(&a[prev], &a[cur]);

		++cur;//不管是cur小于还是大于,是否交换,cur都后移一位      cur都++
	}
	// 将基准值和prev位置元素交换
	Swap(&a[keyi], &a[prev]);
	 // 更新基准值下标为prev
	keyi = prev;
	
	// 递归调用左右两部分
	// [left, keyi-1]keyi[keyi+1, right]
	QuickSort2(a, left, keyi - 1);
	QuickSort2(a, keyi + 1, right);
}

🌠挖坑法

挖坑法也是快速排序的一种单趟排序方法。它也是利用双指针,但与霍尔法不同的是,挖坑法在每次找到比基准数小的元素时,会将其值填入基准数所在的位置,然后将基准数所在的位置作为“坑”,接着从右边开始找比基准数大的元素填入这个“坑”,如此往复,直到双指针相遇。最后,将基准数填入最后一个“坑”的位置。
请添加图片描述
挖坑法思路:
您提到的挖坑法是一种快速排序的实现方式。

  1. 选择基准值(key),将其值保存到另一个变量pivot中作为"坑"
  2. 从左往右扫描,找到小于基准值的元素,将其值填入"坑"中,然后"坑"向右移动一个位置
  3. 从右往左扫描,找到大于或等于基准值的元素,将其值填入移动后的"坑"中
  4. 重复步骤23,直到左右两个指针相遇
  5. 将基准值填入最后一个"坑"位置
  6. 对基准值左右两边递归分治,【begin,key-1keykey+1,end】重复上述过程,实现递归排序

与双指针法相比,挖坑法在处理基准值时使用了额外的"坑"变量,简化了元素交换的操作,但思想都是利用基准值将数组分割成两部分。

代码如下:

//挖坑法
void Dig_QuickSort(int* a, int begin, int end)
{
	if (begin >= end)
		return;

	//一趟的实现
	int key = a[begin];
	int pivot = begin;
	int left = begin;
	int right = end;
	while (left < right)
	{
		while (left < right && a[right] >= key)
		{
			right--;
		}
		a[pivot] = a[right];
		pivot = right;
		while (left < right && a[left] <= key)
		{
			left++;
		}
		a[pivot] = a[left];
		pivot = left;
	}

	//补坑位
	a[pivot] = key;
	
	//递归分治
	//[begin, piti - 1] piti [piti + 1, end]
	Dig_QuickSort(a, begin, pivot - 1);
	Dig_QuickSort(a, pivot + 1, end);
}

当你讨厌挖左边的坑,可以试试右边的坑😉:
代码如下:

// 交换元素
void swap(int* a, int* b) 
{
    int t = *a;
    *a = *b;
    *b = t;
}

// 分区操作函数
int partition(int arr[], int low, int high) 
{

    // 取最后一个元素作为基准值
    int pivot = arr[high];

    // 初始化左右索引  
    int i = (low - 1);

    // 从左到右遍历数组
    for (int j = low; j <= high - 1; j++) 
    {

        // 如果当前元素小于或等于基准值
        if (arr[j] <= pivot) 
        {

            // 左索引向右移动一位
            i++;

            // 将当前元素与左索引位置元素交换  
            swap(&arr[i], &arr[j]);
        }
    }

    // 将基准值和左索引位置元素交换
    swap(&arr[i + 1], &arr[high]);

    // 返回基准值的最终位置
    return (i + 1);
}


// 快速排序主函数
void quickSort(int arr[], int low, int high) 
{

    // 如果低位索引小于高位索引,表示需要继续排序
    if (low < high) 
    {

        // 调用分区函数,得到基准值的位置
        int pi = partition(arr, low, high);

        // 对基准值左边子数组递归调用快速排序
        quickSort(arr, low, pi - 1);

        // 对基准值右边子数组递归调用快速排序   
        quickSort(arr, pi + 1, high);
    }
}

// 测试
int main() 
{
    // 测试数据
    int arr1[] = { 5,3,6,2,10,1,4 };
    int n1 = sizeof(arr1) / sizeof(arr1[0]);
    quickSort(arr1, 0, n1 - 1);
    // 输出排序结果
    for (int i = 0; i < n1; i++)
    {
        printf("%d ", arr1[i]);
    }
    printf("\n");

    int arr2[] = { 5,3,6,2,10,1,4,29,44,1,3,4,5,6 };
    int n2 = sizeof(arr2) / sizeof(arr2[0]);
    quickSort(arr2, 0, n2 - 1);
    // 输出排序结果
    for (int i = 0; i < n2; i++)
    {
        printf("%d ", arr2[i]);
    }
    printf("\n");

    // 测试数据
    int arr3[] = { 10,1,4,5,3,6,2,1 };
    int n3 = sizeof(arr3) / sizeof(arr3[0]);
    quickSort(arr3, 0, n3 - 1);
    // 输出排序结果
    for (int i = 0; i < n3; i++)
    {
        printf("%d ", arr3[i]);
    }
    printf("\n");

    return 0;
}

运行启动:
在这里插入图片描述

✏️优化快速排序

🌠随机选key

为什么要使用随机数选取key?
避免最坏情况,即每次选择子数组第一个或最后一个元素作为key,这样会导致时间复杂度退化为O(n^2)
随机化可以减少排序不均匀数据对算法性能的影响。
相比固定选择第一个或最后一个元素,随机选择key可以在概率上提高算法的平均性能。

这里是优化快速排序使用随机数选取key的方法:

  1. 在划分子数组前,随机生成一个[left,right]区间中的随机数randi
  2. 将随机randi处的元素与区间起始元素left交换
  3. 使用这个随机索引取出子数组中的元素作为keyi。

随机选key逻辑代码:

//快排,随机选key
void QuickSort3(int* a, int left, int right) 
{

  //区间只有一个值或者不存在就是最小子问题
  if (left >= right)
    return;

  int begin = left, end = right;

  //选[left,right]区间中的随机数做key
  int randi = rand() % (right - left + 1);  
  //rand() % N生成0到N-1的随机数
  randi += left;  

  //将随机索引处的元素与区间起始元素交换
  Swap(&a[left], &a[randi]);

  //用交换后的元素作为基准值keyi
  int keyi = left;

  while (left < right) 
  {
    
    //从右向左找小于key的元素
    while (left < right && a[right] >= a[keyi]) 
    {
      --right;
    }
    
    //从左向右找大于key的元素      
    while (left < right && a[left] <= a[keyi]) 
    {
      ++left; 
    }

    //交换元素
    Swap(&a[left], &a[right]);
  }

  //将基准值与交叉点元素交换
  Swap(&a[left], &a[keyi]);
  keyi = left;

  //递归处理子区间
  QuickSort3(a, begin, keyi - 1);
  QuickSort3(a, keyi + 1, end);
}

🌉三位数取中

有无序数列数组的首和尾后,我们只需要在首,中,尾这三个数据中,选择一个排在中间的数据作为基准值(keyi),进行快速排序,减少极端情况,进一步提高快速排序的平均性能。
代码实现:

// 三数取中  left  mid  right
// 大小居中的值,也就是不是最大也不是最小的
int GetMidi(int* a, int left, int right)
{
	int mid = (left + right) / 2;
	
	if (a[left] < a[mid])
	{
		if (a[mid] < a[right])
		{
			return mid;
		}
		else if (a[left] > a[right])
		{
			return left;
		}
		else
		{
			return right;
		}
	}
	else // a[left] > a[mid]
	{
		if (a[mid] > a[right])
		{
			return mid;
		}
		else if (a[left] < a[right])
		{
			return left;
		}
		else
		{
			return right;
		}
	}
}

取中的返回函数接收:

		int begin = left, end = right;
		// 三数取中
		int midi = GetMidi(a, left, right);
		//printf("%d\n", midi);
		Swap(&a[left], &a[midi]);

整体函数实现:

//三数取中  left  mid  right
//大小居中的值,也就是不是最大,也不是最小的
int GetMid(int* a, int left, int right)
{
	int mid = (left + right) / 2;
	
	if (a[left] < a[mid])
	{
		if (a[mid] < a[right])
		{
			return mid;
		}
		else if(a[left] > a[right])
		{
			return left;
		}
		else
		{
			return  right;
		}
	}
	else//a[left] > a[mid]
	{
		if (a[mid] > a[right])
		{
			return mid;
		}
		else if (a[right] > a[left])
		{
			return left;
		}
		else
		{
			return right;
		}
	}
}


void QuickSort4(int* a, int left, int right)
{
	if (left >= right)
		return;

	int begin = left, end = right;
	//三数取中
	int midi = GetMid(a, left, right);
	//printf("%d\n",midi);
	Swap(&a[left], &a[midi]);

	int 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[left], &a[keyi]);
	keyi = left;

	QuickSort4(a, begin, keyi - 1);
	QuickSort4(a, keyi + 1, end);

}

🌠小区间选择走插入,可以减少90%左右的递归

对于小区间,使用插入排序而不是递归进行快速排序。
在快速排序递归中,检查子问题的区间长度是否小于某个阈值(如10-20),如果区间长度小于阈值,则使用插入排序进行排序,否则使用快速排序递归进行划分
而这个(如10-20)刚好可以在递归二叉树中体现出来。
如图:
在这里插入图片描述
当然从向下建堆优于向上建堆,也可以体现出来:
在这里插入图片描述

优点在于:对于小区间,插入排序效率高于快速排序的递归开销大部分数组元素位于小区间中,采用插入排序可以省去90%左右的递归调用,但整体数组规模大时,主要工作还是由快速排序完成

与三数取中进行合用

void QuickSort5(int* a, int left, int right)
{
	if (left >= right)
		return;

	// 小区间选择走插入,可以减少90%左右的递归
	if (right - left + 1 < 10)
	{
		InsertSort(a + left, right - left + 1);
	}
	else
	{
		int begin = left, end = right;
		//三数取中
		int midi = GetMid(a, left, right);
		//printf("%d\n",midi);
		Swap(&a[left], &a[midi]);

		int 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[left], &a[keyi]);
		keyi = left;

		QuickSort4(a, begin, keyi - 1);
		QuickSort4(a, keyi + 1, end);
	}
}

🌉 快速排序改非递归版本

逻辑原理:
非递归版本的快速排序利用了栈来模拟递归的过程。它的基本思想是:将待排序数组的起始和结束位置压入栈中,然后不断出栈,进行单趟排序,直到栈为空为止。在单趟排序中,选取基准数,将小于基准数的元素移到基准数左边,大于基准数的元素移到基准数右边,并返回基准数的位置。然后根据基准数的位置,将分区的起始和结束位置入栈,继续下一轮排序,直到所有子数组有序。
在这里插入图片描述

代码实现步骤:

  1. 初始化一个栈用于保存待排序子数组的起始和结束位置。
  2. 将整个数组的起始和结束位置压入栈中。
  3. 循环执行以下步骤,直到栈为空:
    出栈,获取当前待排序子数组的起始和结束位置。
    进行单趟排序,选取基准数,并将小于基准数的元素移到左边,大于基准数的元素移到右边。
    根据基准数的位置,将分区的起始和结束位置入栈。
  4. 排序结束。

代码实现

#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 = begin;
		int prev = begin;
		int cur = begin + 1;

		while (cur <= end)
		{
			if (a[cur] < a[keyi] && ++prev != cur)
				Swap(&a[prev], &a[cur]);
			++cur;
		}

		Swap(&a[prev], &a[keyi]);
		keyi = prev;

		//[begin,keyi-1]keyi[keyi+1,end]
		if (keyi + 1 < end)
		{
			STPush(&st, end);
			STPush(&st, keyi + 1);
		}

		if (keyi - 1 > begin)
		{
			STPush(&st, keyi - 1);
			STPush(&st, begin);
		}
	}
	
	STDestroy(&st);
}

以下是栈的实现:
Stack.c

#include"Stack.h"

void STInit(ST* ps)
{
	assert(ps);

	ps->a = NULL;
	ps->top = 0;
	ps->capacity = 0;
}

void STDestroy(ST* ps)
{
	assert(ps);

	free(ps->a);
	ps->a = NULL;
	ps->top = ps->capacity = 0;
}

// 栈顶
// 11:55
void STPush(ST* ps, STDataType x)
{
	assert(ps);

	// 满了, 扩容
	if (ps->top == ps->capacity)
	{
		int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
		STDataType* tmp = (STDataType*)realloc(ps->a, newcapacity * sizeof(STDataType));
		if (tmp == NULL)
		{
			perror("realloc fail");
			return;
		}

		ps->a = tmp;
		ps->capacity = newcapacity;
	}

	ps->a[ps->top] = x;
	ps->top++;
}

void STPop(ST* ps)
{
	assert(ps);
	assert(!STEmpty(ps));

	ps->top--;
}

STDataType STTop(ST* ps)
{
	assert(ps);
	assert(!STEmpty(ps));

	return ps->a[ps->top - 1];
}

int STSize(ST* ps)
{
	assert(ps);

	return ps->top;
}

bool STEmpty(ST* ps)
{
	assert(ps);

	return ps->top == 0;
}

栈的头文件实现:

#pragma once

#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#include<assert.h>

typedef int STDataType;
typedef struct Stack
{
	STDataType* a;
	int top;
	int capacity;
}ST;

void STInit(ST* ps);
void STDestroy(ST* ps);

// 栈顶
void STPush(ST* ps, STDataType x);
void STPop(ST* ps);
STDataType STTop(ST* ps);
int STSize(ST* ps);
bool STEmpty(ST* ps);

🚩总结

快速排序的特性总结:

  1. 快速排序整体的综合性能和使用场景都是比较好的,所以才敢叫快速排序
  2. 时间复杂度:O(N*logN)
  3. 空间复杂度:O(logN)
  4. 稳定性:不稳定

快排可以很快,你的点赞也可以很快,哈哈哈,感谢💓 💗 💕 💞,喜欢的话可以点个关注,也可以给博主点一个小小的赞😘呀
请添加图片描述

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

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

相关文章

2024阿里云2核2G服务器租用价格99元和61元一年

阿里云2核2G服务器配置优惠价格61元一年和99元一年&#xff0c;61元是轻量应用服务器2核2G3M带宽、50G高效云盘&#xff1b;99元服务器是ECS云服务器经济型e实例ecs.e-c1m1.large&#xff0c;2核2G、3M固定带宽、40G ESSD entry系统盘&#xff0c;阿里云活动链接 aliyunfuwuqi.…

STM32 | Systick定时器(第四天)

STM32 第四天 一、Systick定时器 1、定时器概念 定时器:是芯片内部用于计数从而得到时长的一种外设。 定时器定时长短与什么有关???(定时器定时长短与频率及计数大小有关) 定时器频率换算单位:1GHZ=1000MHZ=1000 000KHZ = 1000 000 000HZ 定时器定时时间:计数个数…

Github 2024-03-23 Rust开源项目日报 Top10

根据Github Trendings的统计,今日(2024-03-23统计)共有10个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量Rust项目10Dart项目1RustDesk: 用Rust编写的开源远程桌面软件 创建周期:1218 天开发语言:Rust, Dart协议类型:GNU Affero General Public Li…

使用Intellij idea编写Spark应用程序(Scala+SBT)

使用Intellij idea编写Spark应用程序(ScalaSBT) 对Scala代码进行打包编译时&#xff0c;可以采用Maven&#xff0c;也可以采用SBT&#xff0c;相对而言&#xff0c;业界更多使用SBT。 运行环境 Ubuntu 16.04 Spark 2.1.0 Intellij Idea (Version 2017.1) 安装Scala插件 安…

SpringBoot源码探险 —— SpringBoot启动流程详解

一&#xff0c;SpringBoot启动流程 本人使用的SpringBootParent版本为 <parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.4.1</version><relativePath/>…

STM32之HAL开发——RCC外设CubeMX配置时钟

RCC外设介绍 RCC是Reset and Clock Control (复位和时钟控制)的缩写&#xff0c;它是STM32内部的一个重要外设&#xff0c;负责管理各种时钟源和时钟分频&#xff0c;以及为各个外设提供时钟使能。RCC模块可以通过寄存器操作或者库函数来配置。 RCC是复位和时钟控制模块&#…

强化学习之父Richard Sutton:通往AGI的另一种可能

2019年&#xff0c;强化学习之父、阿尔伯塔大学教授Richard Sutton发表了后来被AI领域奉为经典的The Bitter lesson&#xff0c;这也是OpenAI研究员的必读文章。 在这篇文章中&#xff0c;Richard指出&#xff0c;过去 70 年来&#xff0c;AI 研究的一大教训是过于重视人类既有…

是德科技keysight DSOX3024T示波器

181/2461/8938产品概述&#xff1a; DSOX3024T 示波器 要特性与技术指标 使用电容触摸屏进行简洁的触控操作&#xff1a; •提高调试效率 •触控设计可以简化文档记录 •使用起来就像您喜欢的智能手机或平板电脑一样简单 使用 MegaZoom IV 技术揭示偶发异常&#xff1a; •超快…

区块链技术下的新篇章:DAPP与消费增值的深度融合

随着区块链技术的持续演进&#xff0c;去中心化应用&#xff08;DAPP&#xff09;正逐渐受到人们的瞩目。DAPP&#xff0c;这种在分布式网络上运行的应用&#xff0c;以其去中心化、安全可靠、透明公开的特性&#xff0c;为用户提供了更为便捷和安全的消费体验。近年来&#xf…

ReactNative项目构建分析与思考之RN组件化

传统RN项目对比 ReactNative项目构建分析与思考之react-native-gradle-plugin ReactNative项目构建分析与思考之native_modules.gradle ReactNative项目构建分析与思考之 cli-config 在之前的文章中&#xff0c;已经对RN的默认项目有了一个详细的分析&#xff0c;下面我们来…

K8S之DaemonSet控制器

DaemonSet控制器 概念、原理解读、应用场景概述工作原理典型的应用场景介绍DaemonSet 与 Deployment 的区别 解读资源清单文件实践案例 概念、原理解读、应用场景 概述 DaemonSet控制器能够确保K8S集群所有的节点都分别运行一个相同的pod副本&#xff1b; 当集群中增加node节…

如何打造智慧公厕?发挥数据要素价值构建新型智慧公厕

公共厕所是城市建设和管理中不可或缺的一环。然而&#xff0c;长期以来&#xff0c;公厕的管理难题一直困扰着城市管理者和市民。为了解决这一问题&#xff0c;新时期以信息化为引领的智慧公厕建设应运而生。智慧公厕建设的推进需要技术融合、业务融合和数据融合&#xff0c;以…

C语言与sqlite3入门

c语言与sqlite3入门 1 sqlite3数据类型2 sqlite3指令3 sqlite3的sql语法3.1 创建表create3.2 删除表drop3.3 插入数据insert into3.4 查询select from3.5 where子句3.6 修改数据update3.7 删除数据delete3.8 排序Order By3.9 分组GROUP BY3.10 约束 4 c语言执行sqlite34.1 下载…

jmeter使用方法---自动化测试

HTTP信息头管理器 一个http请求会发送请求到服务器&#xff0c;请求里面包含&#xff1a;请求头、请求正文、请求体&#xff0c;请求头就是信息头Authorization头的主要用作http协议的认证。 Authorization的作用是当客户端访问受口令保护时&#xff0c;服务器端会发送401状态…

Head First Design Patterns -模板方法模式

什么是模板方法模式 在一个方法中定义一个算法的骨架&#xff0c;而把一些步骤延迟到子类。模板方法使得子类可以在不改变算法结构的情况下&#xff0c;重新定义算法的某些步骤。 这些算法步骤中的一个或者多个被定义为抽象的&#xff0c;由子类实现。 类图 代码 书中用泡茶和…

鸿蒙开发实战:网络请求库【axios】

简介 [Axios] &#xff0c;是一个基于 promise 的网络请求库&#xff0c;可以运行 node.js 和浏览器中。本库基于[Axios]原库v1.3.4版本进行适配&#xff0c;使其可以运行在 OpenHarmony&#xff0c;并沿用其现有用法和特性。 http 请求Promise APIrequest 和 response 拦截器…

分布式ID生成方案总结

分布式场景下&#xff0c;由于通常是分库分表&#xff0c;所以通常无法仅仅使用数据库的自增Id。需要使用其他方案生成唯一的id。目前业界主流的是基于雪花算法或者雪花算法的改进版本。 UUID 有什么特点&#xff1f; 足够的简单&#xff0c;java原生自带。本地生成具有唯一性…

kubernetes负载均衡-service

一、service的概念 1、什么是service 在Kubernetes中&#xff0c;pod是应用程序的载体&#xff0c;当我们需要访问这个应用时&#xff0c;可以通过Pod的IP进行访问&#xff0c;但是这里有两个问题:1、Pod的IP地址不固定&#xff0c;一旦Pod异常退出、节点故障&#xff0c;则会…

java的IO之NIO

NIO是一种同步非阻塞的I/O模型&#xff0c;在Java 1.4中引入了NIO框架&#xff0c;对应java.nio包&#xff0c;提供了channel、selector、buffer等。 NIO中的N可以理解为Non-blocking不在单纯是New&#xff0c;它支持面向缓冲的&#xff0c;基于通道的I/O操作方法。NIO提供了与…

SCI一区 | Matlab实现WOA-TCN-BiGRU-Attention鲸鱼算法优化时间卷积双向门控循环单元融合注意力机制多变量时间序列预测

SCI一区 | Matlab实现WOA-TCN-BiGRU-Attention鲸鱼算法优化时间卷积双向门控循环单元融合注意力机制多变量时间序列预测 目录 SCI一区 | Matlab实现WOA-TCN-BiGRU-Attention鲸鱼算法优化时间卷积双向门控循环单元融合注意力机制多变量时间序列预测预测效果基本介绍模型描述程序…