排序算法(九大)- C++实现


目录

基数排序

快速排序 

Hoare版本(单趟)

快速排序优化

三数取中

 小区间优化

挖坑法(单趟)

前后指针法(单趟)

非递归实现(快排)

归并排序

非递归实现(归并)

计数排序

冒泡排序

插入排序

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

选择排序(优化版本)

堆排序


基数排序

实现原理:

        将所有待比较值统一为同样的数位长度,数位端的数据前面补0,然后,从最低位开始,依次进行一次排序,这样不断从最低位到最高位排序完成之后,数据就有序了。

实现步骤:

(1)、先确实数据中最高位是几位数(定义为 K)。

(2)、创建下标为 0~9 (共10个)的队列,因为所有的数字元素每一位都是由 0~9 这10个数组成的。

(3)、依次判断每个数据的 个位,十位,到 K位(共K次),依次将数据进行分发到下标对应的队列中,然后拿取回原数组中,最后到第K次后数据就有序了。

一组数据演示:

再将数据依次从每个队列的队头中拿取出来:

 最后一次拿取分发:

代码实现:

Sort.h 中函数实现代码

#pragma once
#include <iostream>
#include <queue>
using namespace std;
#define K 3 //最高位次数
#define RaIndex 10std::queue<int> q[RaIndex];//用于存储分发的数据// value: 278    k: 0   ->   8
int GetKey(int value, int k)
{int key = 0;while (k >= 0){key = value % 10;value /= 10;k--;}return key;
}//分发数据
void Distribute(int arr[], int left, int right, int k)
{for (int i = left; i < right; i++) //[left,right){//按照位数以此分发int key = GetKey(arr[i], k);//按照 key的下标分发的对应下标的队列q[key].push(arr[i]);}
}//接受数据
void Receive(int arr[])
{int index = 0;//从各个队列中依次回收数据for (int i = 0; i < RaIndex; i++){while (!q[i].empty()){arr[index] = q[i].front();q[i].pop();index++;}}
}//基数排序
void RadixSort(int arr[], int n)
{for (int i = 0; i < K; i++){//分发数据Distribute(arr, 0, n, i);//接受数据Receive(arr);}
}

 Test.cpp 中测试代码:

#include "Sort.h"int main()
{int arr[] = { 267,89,98,34,7,984,58,83,384,150,384,394,463 };int n = sizeof(arr) / sizeof(arr[0]);cout << "排序前:" << endl;for (int i = 0; i < n; i++){cout << arr[i] << " ";}cout << endl;RadixSort(arr, n);cout << "排序后:" << endl;for (int i = 0; i < n; i++){cout << arr[i] << " ";}cout << endl;return 0;
}

最后进行数据测试:


快速排序 

快速排序是一种基于二叉树结构的交换排序算法,其基本思想:

        任取待排序元素序列中的某元素作为基准值,按照该基准值将待排序列分为两个子序列,左子序列中所有的元素均小于基准值,右子序列中所有元素均大于基准值,然后左右序列递归实现该过程,直到所有元素都排序在相对应位置上为止。

Hoare版本(单趟)

单趟动图演示:

  单趟排序基本步骤:

(1)、选出一个key值作为基准,一般是最左边或者最右边。

(2)、定义两个向指针一样的下标(L 从左往右走 和 R 从右往左走),如果key值选的是最左边的,就需要R先走,如果key值选的是最右边的,就需要L先走。

(3)、若R走过程中,遇到小于key的就停下,然后L开始走,遇到大于key的就停下,随后交换R和L位置的值,然后再次开始走,直到L撞上R,或者R撞上L,然后交换key与相撞位置的值即可。(选取左边的值为key)

当L撞上R时:

 当R撞上L时:

(4)、左边序列都是小于key的,右边序列都是大于key的,然后再次对两个序列进行单趟排序,直到左右序列只有一个数据或者左右序列不存在即可,此时就是数据就是有序的了。

代码实现:

//快排的单趟排序  [] 左闭右闭
int SingSort(int arr[], int left, int right)
{//选取一个key值 左边int keyi = left;while (left < right){//右边先走,右边找比keyi小的 相等也跳过,否则可能会死循环while (left < right && arr[right] >= arr[keyi]){right--;}//左边找比keyi大的while (left < right && arr[left] <= arr[keyi]){left++;}if (left < right){std::swap(arr[left], arr[right]);}}int meeti = left;//此时相遇了std::swap(arr[keyi], arr[meeti]);return meeti;
}//快速排序
void QuickSort(int arr[], int begin, int end)
{if (begin >= end){return;}int keyi = SingSort(arr, begin, end);//[begin,keyi-1] keyi [keyi+1,end]QuickSort(arr, begin, keyi - 1);QuickSort(arr, keyi + 1, end);
}

快速排序优化

三数取中

         快速排序的时间复杂度为O(N * log N),是在理想的情况下计算的结果,每次进行完单趟排序之后,key的左序列与右序列的长度相同,并且所选key正好都是该序列中的 left 下标的值与 right 下标的值的中间值,每趟排序结束后key都位于序列的中间:

如果待排序的序列是一个有序序列,选key时依旧选最左边或者最右边,那么此时时间复杂度就会退化:

快速排序效率的影响最大的就是选key,key越接近中间位置,效率就越高。

三数取中逻辑:最左下标的值,最右下标的值,以及中间位置的值,进行大小比较,然后选大小居中位置的值作为key,当大小居中的位置的值不在最左端或者最右端时,就需要将key值与最左端的值进行交换即可。

//三数取中逻辑
int GetMidWay(int arr[], int left, int right)
{int mid = (right + left) / 2;if (arr[right] > arr[mid]){if (arr[left] > arr[right]){return right;}else if (arr[mid] > arr[left]){return mid;}else{return right;}}else // arr[right] <= arr[mid]{if (arr[left] > arr[mid]){return mid;}else if (arr[right] > arr[left]){return right;}else{return left;}}
}//快排的单趟排序  [] 左闭右闭
int SingSort(int arr[], int left, int right)
{int mid = GetMidWay(arr, left, right);std::swap(arr[left], arr[mid]);//选取一个key值 左边int keyi = left;while (left < right){//右边先走,右边找比keyi小的 相等也跳过,否则可能会死循环while (left < right && arr[right] >= arr[keyi]){right--;}//左边找比keyi大的while (left < right && arr[left] <= arr[keyi]){left++;}if (left < right){std::swap(arr[left], arr[right]);}}int meeti = left;//此时相遇了std::swap(arr[keyi], arr[meeti]);return meeti;
}

 小区间优化

随着递归的深入,每一层的递归次数会以2倍的形式快速增长,如果递归的森度过大,可能会导致栈溢出的情况,为了减少递归树的最后几层递归,可以设置一个判断语句,当递归序列的长度小于某个值时,就不再进行递归转向使用其他排序方法:

//快速排序
void QuickSort(int arr[], int begin, int end)
{if (begin >= end){return;}//小区间优化if (end - begin <= 13){//进行希尔排序InsertSort(arr + begin, end - begin + 1);//个数+1}else{int keyi = SingSort(arr, begin, end);//[begin,keyi-1] keyi [keyi+1,end]QuickSort(arr, begin, keyi - 1);QuickSort(arr, keyi + 1, end);}
}

挖坑法(单趟)

单趟动图演示:

在这里插入图片描述

 基本思想步骤:

(1)、选出一个数值(一般是最左边或者最右边的值)存储在key变量中,在该数据位置形成了一个坑。

(2)、定义两个像指针一样的下表(L与R),L从左往右走,R从右往左走。(若在坑位在最左边,需要R先走,若坑位在右边,需要L先走)。

(3)、若R遇到小于key值的数,就将该数填入到左边的坑位,再将这个数的位置设置为新的坑位,此时L再走,若遇到大于key值的数,就将该数填入的右边的坑位,这个数的位置形成新的坑位,循环往下走,直到L和R的位置相遇,再将key值填入遇到位置的坑位。(最左边的值为key)

// 挖坑法
int PartSort(int arr[], int left, int right)
{//三数取中int mid = GetMidWay(arr, left, right);std::swap(arr[left], arr[mid]);int key = arr[left];int hole = left;while (left < right){//右边找比key小的坑,填到左边while (left < right && arr[right] >= key){right --;}arr[hole] = arr[right];hole = right;//左边找比key大的坑,填到右边while (left < right && arr[left] <= key){left++;}arr[hole] = arr[left];hole = left;}arr[hole] = key;return hole;
}

前后指针法(单趟)

单趟动图演示:

在这里插入图片描述

 前后指针法的思想:

• cur 遇到比key小的值就停下来,是否一直++;

• prev++,交换 cur 与 prev 位置的值(也可以进行判断 prev ++ 之后与 cur 位置是否相等,相等就不交换)

基本步骤:

(1)、选 keyi 位置的值作为基准值,一般是最左边或者最右边。

(2)、定义两个指针变量,开始 prev 指向序列开头的位置,cur 指向 prev + 1 的位置。

(3)、若 cur 位置的值小于key,则 prev 位置进行 ++ ,交换 prev 位置与 cur 位置的值;

如果 cur 位置的值大于key,cur 位置一直 ++,直到 cur 指针越界,此时将 keyi 位置的值与 prev 位置的值进行交换即可。

// 前后指针法
int PartSort2(int arr[], int left, int right)
{int mid = GetMidWay(arr, left, right);std::swap(arr[mid], arr[left]);int keyi = left;int prev = left;int cur = prev + 1;while (cur <= right){//cur位置向前找小的while (arr[cur] >= arr[keyi]){cur++;}swap(arr[cur], arr[prev + 1]);}swap(arr[prev], arr[keyi]);return prev;
}

非递归实现(快排)

需要借助一个数据结构(栈)来实现,直接用STL中的容器(stack)即可,其中栈中存储的是区间位置,也就是下标。

基本思想步骤:

(1)、先将待排序序列的第一个元素的下标与最后一个元素的下标进行入栈。

(2)、当栈不为空时,先读取栈顶元素作为子区间的 right,出栈后再读取栈顶的元素作为子区间的 left,将这个子区间进行单趟排序,随后将被分割的新的子区间,再进行入栈处理,直到序列中只有一个元素或者不存在即可。

//快速排序 - 非递归
void QuickSortNonR(int arr[], int begin, int end)
{stack<int> st;//存储的是区间st.push(begin);st.push(end);while (!st.empty()){int right = st.top();st.pop();int left = st.top();st.pop();//区间不存在 结束/*if (left >= right){continue;}*///对区间进行单趟排序int key = PartSort(arr, left, right);// [left key-1] key [key+1 right]//对子区间进行入栈if (key + 1 < right){st.push(key + 1);st.push(right);}if (left < key - 1){st.push(left);st.push(key - 1);}}
}

归并排序

动图演示:

在这里插入图片描述

 归并排序基本思想:采用分治的方法,将已经有序的子序列合并,从而得到一组完全有序的序列,即先使每个子序列先有序,再使子序列段间有序。

如何将两个有序序列合并成一个有序序列?(只需要取小的尾插到新数组即可)

 如何得到有序的子序列呢?(当序列分解到只有一个元素或者没有元素时,就可以认为是有序的了)

归并排序(递归)实现步骤:

(1)、需要申请一块用于与待排序数组大小相同的用于合并两个 子序列的临时数组。

(2)、进行递归分治,直到只有一个元素或者不存在。

(3)、得到的两个子序列,取小的尾插的临时数组中,直到两个子序列都尾插完全,再拷贝回原数组的相对应位置

代码:

void _MergeSort(int arr[], int begin, int end, int* tmp)
{//分if (begin >= end){return;}int mid = (end + begin) / 2;//[begin mid] [mid+1 end]//递归划分子区间_MergeSort(arr, begin, mid, tmp);_MergeSort(arr, mid + 1, end, tmp);//归并int i = begin; //区间的开始int begin1 = begin, end1 = mid;int begin2 = mid + 1, end2 = end;while (begin1 <= end1 && begin2 <= end2){//取小的尾插到临时数组中if (arr[begin1] <= arr[begin2]){tmp[i++] = arr[begin1++];}else{tmp[i++] = arr[begin2++];}}//此时有的区间还没有结束while (begin1 <= end1){tmp[i++] = arr[begin1++];}while (begin2 <= end2){tmp[i++] = arr[begin2++];}//拷贝子区间数组到原数组当中memcpy(arr + begin, tmp + begin, (end - begin + 1) * sizeof(int));
}//归并排序 - 递归
void MergeSort(int arr[], int n)
{int* tmp = new int(n);//分为子函数进行 闭区间_MergeSort(arr, 0, n - 1, tmp);
}

时间复杂度( O(N * log N) )   空间复杂度( O(N) ) 


非递归实现(归并)

归并排序的非递归实现,不需要借助栈等数据结构来实现,只需要控制好,每次参加合并的元素个数即可,最终便能使序列变成有序:

 上面只是一个广泛适用的样例,其中还有很多极端场景:

场景一:

当最后一个小组进行合并时,第二个小区间存在,但是该区间元素个数不足gap个,需要在合并序列时,对第二个小区间的边界进行控制:

 场景二:

当最后一个小组进行合并时,第二个小区间不存在,此时不需要对该小组进行合并:

 场景三:

当最后一个小组进行合并时,第二个小区间不存在,并且第一个小区间元素不够gap个时,此时也不需要对该小组进行合并:

//归并排序 - 非递归
void MergeSortNonR(int arr[], int n)
{int* v = new int(n);int gap = 1;while (gap < n){for (int i = 0; i < n; i += 2 * gap){int j = i;int begin1 = i, end1 = i + gap - 1;int begin2 = i + gap, end2 = i + 2 * gap - 1;//场景一:第二组部分越界  直接修正边界if (end2 >= n){end2 = n - 1;}//场景二:第二组全部越界  if (begin2>= n){break;}//场景三:第一组越界if (end1 >= n){break;}//将数组归并while (begin1 <= end1 && begin2 <= end2){if (arr[begin1] <= arr[begin2]){v[j++] = arr[begin1++];}else{v[j++] = arr[begin2++];}}//把剩下的数进行归并while (begin1 <= end1){v[j++] = arr[begin1++];}while (begin2 <= end2){v[j++] = arr[begin2++];}memcpy(arr + i, v + i, sizeof(int)*(end2 - i + 1));}gap *= 2;}
}

计数排序

        计数排序,又叫非比较排序,通过统计数组中相同元素出现的次数,然后通过统计的结果将序列回收到原来的序列。

如例:

绝对映射:统计数组中的下标 i 的位置记录的是arr数组中数字i出现的次数。

相对映射:统计中下标为i的位置记录的是arr数组中数字 i + min 出现的次数。

注意:

        计数排序只适用于数据范围较集中的序列的排序,若待排序列的数据较分散,会造成空间浪费,计数排序只适用于整型数据的排序,不适用于字符串以及浮点型数据。

代码:

//计数排序
void CountSort(int arr[], int n)
{int a_max = arr[0], a_min = arr[0];for (int i = 1; i < n; i++){if (arr[i] > a_max){a_max = arr[i];}if (arr[i] < a_min){a_min = arr[i];}}int num = a_max - a_min + 1;//开这么大的数组vector<int> v(num);for (int i = 0; i < n; i++){v[arr[i] - a_min]++;//统计次数}int j = 0;for (int i = 0; i < num; i++){while (v[i]--)//次数{arr[j++] = i + a_min;}}
}

时间复杂度(O(N + NUM)),空间复杂度(O(NUM))


冒泡排序

动态演示:

在这里插入图片描述

 冒泡排序思想:

最外层循环控制的是循环的次数,内层循环控制的是数组中哪些元素进行交换。

代码:

//冒泡排序
void BubbleSort(int arr[], int n)
{int flag = 0;for (int i = 0; i < n; i++){for (int j = 0; j < n - 1 - i; j++){if (arr[j] > arr[j + 1]){swap(arr[j], arr[j + 1]);//把大的换到最后面的位置flag = 1;}}if (flag == 0){break;//此时是有序的数组}}
}

时间复杂度(O(N^2))空间复杂度(O(1)) 


插入排序

动图演示:

在这里插入图片描述

         插入排序,又名直接插入排序。在待排序的元素中,假设前 n-1 个元素已经是有序的,现将第n个数插入到前面已经排好序的序列中,使得前n个元素有序。依次对所有插入要的元素,直到整个序列有序为止。

实现步骤:

(1)、保存要插入的第 n 个数(要将前面的数据移动到后面所以要临时保存)。

(2)、依次在 end >= 0的情况下,与前面的数进行对比,如果要插入的数据小于前面的数,则向 end + 1 位置进行覆盖,大于则 break。

(3)、插入的位置有两种情况,只需要向 end + 1位置填入即可。

 代码:

//插入排序
void InsertSort(int arr[], int n)
{//假设[0,end]有序for (int i = 0; i < n - 1; i++){int end = i;//不能使用iint tmp = arr[end + 1];while (end >= 0){if (tmp < arr[end]){arr[end + 1] = arr[end];//继续往前比较end--;}else{//此时 2 4 这种情况break;}}arr[end + 1] = tmp;}
}

时间复杂度(O(N^2))


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

希尔排序对普通插入排序的时间复杂度进行分析,得出以下结论:

1、普通插入排序的时间复杂度最坏情况下为O(N^2),此时待排序序列为逆序情况下,或者说接近逆序。

2、普通插入排序的时间复杂度最好情况下为O(N),此时待排序序列为有序情况下,或者说接近有序。

希尔排序的思想:先将待排序序列进行一次与排序,使得待排序序列接近有序,然后再对该序列进行一次直接插入排序。

希尔排序基本步骤:

1、先选定一个小于N的整数gap作为第一增量,然后将所有距离为gap的元素分在统一组,并对每一组的元素进行直接插入排序,然后再取一个币第一增量小的整数作为第二增量,重复上述步骤,直到增量为1为止。

2、当增量大小为1时,就相当于整个序列被分到一组,直接进行插入排序即可将排序序列成为有序序列。

问题:gap如何选择?

gap越大,数据挪动得越快,gap越小,数据挪动得越慢,前期让gap较大,可以让数据更快得移动到自己对应的位置附近(比如:大的数据到后面,小的数据到前面,对升序而言)。一般情况下,取序列的一半作为增量,也可以取 / 3 + 1,直接增量为1。

举例说明分析:

前面两趟都是预排序,最后一趟为直接插入排序。

//希尔排序
void ShellSort(int arr[], int n)
{控制gap的值//int gap = n;//while (gap > 1)//{//	gap = gap / 3 + 1;//	//按组进行//	for (int j = 0; j < gap; j++)//	{//		for (int i = j; i < n - gap; i += gap)//		{//			int end = i;//			int tmp = arr[end + gap];//			while (end >= 0)//			{//				if (arr[end] > tmp)//				{//					arr[end + gap] = arr[end];//					end -= gap;//				}//				else//				{//					break;//				}//			}//			arr[end + gap] = tmp;//		}//	}//}//控制gap的值int gap = n;while (gap > 1){gap = gap / 3 + 1;//齐头并进for (int i = 0; i < n - gap; i++){int end = i;int tmp = arr[end + gap];while (end >= 0){if (arr[end] > tmp){arr[end + gap] = arr[end];end -= gap;}else{break;}}arr[end + gap] = tmp;}}
}

 时间复杂度(O(N * Log N)) 平均时间复杂度(O(N^1.3))


选择排序(优化版本)

动图演示(未优化,选择一个数的):

在这里插入图片描述

 未优化选择排序思想:每次从待排序中选出一个最小值,然后放在序列的起始位置,直到全部待排序序列排完即可。

void SelectSort(int arr[], int n)
{for (int i = 0; i < n; i++){int begin = i;int mini = begin;while (begin < n){if (arr[begin] < arr[mini]){mini = begin;}begin++;}swap(arr[mini], arr[i]);}
}

优化选择排序:可以一趟选出两个数值,一个最大值,和一个最小值,然后将它们分别放在序列的末端以及开头,直到遍历完整个序列。

特殊情况:

//选择排序
void SelectSort(int arr[], int n)
{int begin = 0;int end = n - 1;while (begin < end){int mini = begin;int maxi = begin;for (int i = begin + 1; i <= end; i++){if (arr[i] > arr[maxi]){maxi = i;}if (arr[i] < arr[mini]){mini = i;}}//进行交换swap(arr[begin], arr[mini]);//如果最大的数在begin位置,被换到mini位置了if (maxi == begin){maxi = mini;}swap(arr[end], arr[maxi]);begin++;end--;}
}

时间复杂度最好与最坏(O(N^2)) 


堆排序

首先要建堆,而建堆需要执行多次堆的向下调整算法。

堆的向下调整算法:

        新插入节点,要调整为小堆,那么根节点的左右子树必须都为小堆;调整为大堆,那么根节点的左右子树必须都是大堆。

 向下调整算法步骤(建大堆):

1、从根节点开始,选出左右孩子中值较大的孩子。

2、让大的孩子与父亲位置的值进行比较,若大于父亲位置的值,则该孩子与父亲位置进行交换,并将原来大的孩子的位置当成父亲继续向下进行调整,直到调整到叶子节点位置;若小于父亲位置的值,就不需要处理了,此时整棵数就是大堆了。

示例演示:

//堆的向下调整算法
void AdjustDown(int arr[], int n, int root)
{int parent = root;int child = parent * 2 + 1;//假设左边孩子的值大while (child < n){if (child + 1 < n && arr[child + 1] > arr[child]) //child位置存在的情况下{child++;}if (arr[child] > arr[parent]){swap(arr[child], arr[parent]);parent = child;child = parent * 2 + 1;}else{break;//此时已经是大堆了}}
}

 堆的向下调整算法,最快情况下,一直要向下调整节点,次数为 h - 1 次(h为数的高度),而 

h = log 2 (N+1) N为结点总数,所以堆的向下调整算法的时间复杂度为 O(log N)

        使用堆的向下调整算法需要满足其根节点的左右子树是大堆或者小堆才行,方法如下:

只需要从倒数第一个非叶子结点来说,从后往前,按下标,依次作为根取向下调整即可。

建堆代码:

//最后一个位置的下班是n-1,父亲位置是 (n - 1 -1)/2
for (int i = (n - 1 - 1) / 2; i >= 0; i--)
{AdjustDown(arr, n, i);
}

 建堆的时间复杂度大概是 O(N)。

如何进行堆排序?

1、将堆顶数据与堆的最后一个数据交换,然后对根位置进行一次向下调整算法,但是被交换到最后的那个最大的数不参与向下调整。

2、此时除了最后一个数之外,其余的数又成了一个大堆,然后又将堆顶数据与堆的最后一个数据进行交换,第二大的数就被放到了倒数第二位置上,反复进行运算,直到堆中只有一个数据即可。

void HeapSort(int arr[], int n)
{//最后一个位置的下班是n-1,父亲位置是 (n - 1 -1)/2for (int i = (n - 1 - 1) / 2; i >= 0; i--){AdjustDown(arr, n, i);}//此时是一个大堆,进行把大的数,放到最后即可int end = n - 1;while (end){swap(arr[0], arr[end]);//继续向下调整,成为大堆AdjustDown(arr, end, 0);end--;}
}

时间复杂度(O(N^2))


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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

奥威BI—数字化转型首选,以数据驱动企业发展

奥威BI系统BI方案可以迅速构建企业级大数据分析平台&#xff0c;可以将大量数据转化为直观、易于理解的图表和图形&#xff0c;推动和促进数字化转型的进程&#xff0c;帮助企业更好地了解自身的运营状况&#xff0c;及时发现问题并采取相应的措施&#xff0c;提高运营效率和质…

【数据结构】双链表

【数据结构】双链表 一. 前言二. 带头双向链表接口实现1.准备工作2. 创建一个节点 三. 初始化4. 打印5. 尾插6. 尾删7. 头插8. 头删9. 计算节点个数10. 查找数据11. 在任意位置插入数据12. 在任意位置删除数据13. 销毁 四. 如何10分钟内完成一个完整双链表 一. 前言 带头双向循…

笔记——听听前辈们的教学评一体化

精选课程内容 强而有力的知识 做中学&#xff0c;用中学&#xff0c;创中学。 这个技术很难做 关于支架的新理解 有价值 有意义 和 趣味性 权衡&#xff0c;不能为了趣味性舍弃价值 举例说明文 被教成了文学作品 导致所教所学 悄然发生了偏移。 所以教学评如何一直&#xff…

Ajax 笔记(一)

笔记目录 1. Ajax 入门1.1 Ajax 概念1.2 axios 使用1.2.1 URL1.2.2 URL 查询参数1.2.3 小案例-查询地区列表1.2.4 常用请求方法和数据提交1.2.5 错误处理 1.3 HTTP 协议1.3.1 请求报文1.3.2 响应报文 1.4 接口文档1.5 案例1.5.1 用户登录&#xff08;主要业务&#xff09;1.5.2…

如何构造一个安全的单例?

为什么要问这个问题&#xff1f; 我们知道&#xff0c;单例是一种很常用的设计模式&#xff0c;主要作用就是节省系统资源&#xff0c;让对象在服务器中只有一份。但是实际开发中可能有很多人压根没有写过单例这种模式&#xff0c;只是看过或者为了面试去写写demo熟悉一下。那…

职责链模式(C++)

定义 使多个对象都有机会处理请求&#xff0c;从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链&#xff0c;并沿着这条链传递请求&#xff0c;直到有一个对象处理它为止。 应用场景 在软件构建过程中&#xff0c;一个请求可能被多个对象处理&#xff0c;…

Redis单机,主从,哨兵,集群四大模式

Redis 单机模式 Redis 单机模式是指 Redis 数据库在单个服务器上以独立的、单一的进程运行的模式。在这种模式下&#xff0c;Redis 不涉及数据分片或集群配置&#xff0c;所有的数据和操作都在一个实例中进行。以下是关于 Redis 单机模式的详细介绍&#xff1a; 单一实例&#…

如何搭建自动化测试框架?资深测试整理的PO模式,一套打通自动化...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 Po模型介绍 1、简…

24届华东理工大学近5年自动化考研院校分析

今天给大家带来的是华东理工大学控制考研分析 满满干货&#xff5e;还不快快点赞收藏 一、华东理工大学 学校简介 华东理工大学原名华东化工学院&#xff0c;1956年被定为全国首批招收研究生的学校之一&#xff0c;1960年起被中共中央确定为教育部直属的全国重点大学&#…

匈牙利算法详解

匈牙利算法(Hungarian Algorithm)是一种组合优化算法(combinatorial optimization algorithm)&#xff0c;用于求解指派问题(assignment problem)&#xff0c;算法时间复杂度为O(N^3)。Harold Kuhn发表于1955年&#xff0c;由于该算法基于两位匈牙利数学家的早期研究成果&#…

基于智慧路灯杆的智慧交通应用示例

智慧路灯杆的身影已经越来越频繁出现在我们的生活之中&#xff0c;无论是我们开车在路上&#xff0c;还是行走在商业街&#xff0c;造型美轮美奂&#xff0c;功能丰富多样的智慧路灯杆&#xff0c;也已经成为了一道独特靓丽的街景。 智慧路灯杆如何发挥其智慧功能&#xff1f;对…

Zabbix6.0监控

文章目录 一、Zabbix简介1&#xff09;zabbix 是什么&#xff1f;2&#xff09;zabbix 监控原理3&#xff09;Zabbix 6.0 新特性1、Zabbix server高可用防止硬件故障或计划维护期的停机2、Zabbix 6.0 LTS新增Kubernetes监控功能&#xff0c;可以在Kubernetes系统从多个维度采集…

The ‘kotlin-android-extensions‘ Gradle plugin is no longer supported.

Android使用kotlin开发&#xff0c;运行报错 The kotlin-android-extensions Gradle plugin is no longer supported. Please use this migration guide (https://goo.gle/kotlin-android-extensions-deprecation) to start working with View Binding (https://developer.an…

一文了解 Android Auto 车载开发~

作者&#xff1a;牛蛙点点申请出战 背景 我的的产品作为一个海外音乐播放器&#xff0c;在车载场景听歌是一个很普遍的需求。在用户反馈中&#xff0c;也有很多用户提到希望能在车上播放音乐。同时车载音乐也可以作为提升用户消费时长一个抓手。 出海产品&#xff0c;主要服务…

【单片机】51单片机,晨启科技,板子引脚对应关系

一般引脚: sbit beepP2^4; //将单片机的P2.4端口定义为beep.本口用于屏蔽上电后蜂鸣器响 sbit ledP1^0; //将单片机的P1.0端口定义为led&#xff0c;用于点亮LED-D1 sbit DIG1P0^0; //数码管位选1 sbit DIG2P0^1; //数码管位选2P10xFF;//初始化P1引脚全部置高&a…

Linux中singal信号的作用

void&#xff08;* signal&#xff08;int sig&#xff0c;void&#xff08;* func&#xff09;&#xff08;int&#xff09;&#xff09;&#xff09;&#xff08;int&#xff09;;设置处理信号的功能 头文件为&#xff1a;#include <signal.h> 指定使用sig指定的信号…

时序预测 | MATLAB实现BO-GRU贝叶斯优化门控循环单元时间序列预测

时序预测 | MATLAB实现BO-GRU贝叶斯优化门控循环单元时间序列预测 目录 时序预测 | MATLAB实现BO-GRU贝叶斯优化门控循环单元时间序列预测效果一览基本介绍模型搭建程序设计参考资料 效果一览 基本介绍 MATLAB实现BO-GRU贝叶斯优化门控循环单元时间序列预测。基于贝叶斯(bayes)…

Spring MVC

hi,今天为大家带来Spring MVC相关知识 文章目录 &#x1f33b;1.什么是Spring MVC?&#x1f36c;1.1什么是MVC?&#x1f36c;1.2MVC和Spring MVC的关系 &#x1f33b;2.Spring MVC的意义&#x1f36c;2.1Spring MVC和Spring Boot区别 &#x1f33b;3.Spring MVC的三大要点&a…

用PointNet分类3D点云

在本教程中&#xff0c;我们将学习如何训练PointNet进行分类。 我们将主要关注数据和训练过程&#xff1b; 展示如何从头开始编码 Point Net 的教程位于此处。 本教程的代码位于这个Github库中&#xff0c;我们将使用的笔记本位于这个Github库中。 一些代码的灵感来自于这个Git…

wordpress 打开缓慢处理

gravatar.com 头像网站被墙 追踪发现请求头像时长为21秒 解决方案一 不推荐&#xff0c;容易失效&#xff0c;网址要是要稳定为主&#xff0c;宁愿头像显示异常&#xff0c;也不能网址打不开 网上大部分搜索到的替换的CDN网址都过期了&#xff0c;例如&#xff1a;gravatar.du…