数据结构中的八大金刚--------八大排序算法

news2024/9/23 1:36:28

目录

引言

一:InsertSort(直接插入排序)

 二:ShellSort(希尔排序)

 三:BubbleSort(冒泡排序)

四: HeapSort(堆排序)

五:SelectSort(直接选择排序)

六:QuickSort(快速排序)

 1.Hoare版本

2.前后指针版本 

3.非递归版本 

4.快排之三路划分

5.SGI-IntrospectiveSort(自省排序)

七:MergeSort(归并排序) 

1.递归版本

2.非递归版本 

 八:CountSort(计数排序)

 

接下来的日子会顺顺利利,万事胜意,生活明朗-----------林辞忧 

引言

在日常生活当中任何地方都有着排序的思想,对于网购时价格排序,销量排序,好评排序等各种排名,因此对于学习排序算法是很重要,对于排序算法有常见的八种,它们分别是  InsertSort(直接插入排序)    ShellSort(希尔排序)    BubbleSort(冒泡排序)     HeapSort(堆排序)     SelectSort(直接选择排序)     QuickSort(快速排序)     MergeSort(归并排序)     CountSort(计数排序)   对于其他的如桶排序,奇数排序等实际用处不大,很少使用。接下来就介绍这八种排序算法

一:InsertSort(直接插入排序)

1.动图

2.思想:把待排序的记录按其关键码值的大小逐个插入到一个已经排好序的有序序列中,直到所有的记录插入完为止,得到一个新的有序序列

void InsertSort(int* a, int n)
{
	//[0,end]有序,插入a[end+1]
	for (int i = 0; i < n - 1; ++i)
	{
		int end=i;
		int tmp = a[end + 1];
		while (end>=0)
		{
			if (a[end] > tmp)
			{
				a[end + 1] = a[end];
				--end;
			}
			else
			{
				break;
			}
		}
		a[end + 1] = tmp;
	}
}

3.时间复杂度:O(N^2)    最坏情况是逆序,最好情况是有序或者接近有序O(N)

 二:ShellSort(希尔排序)

1.图片演示

2.思想:

先选定一个整数,把待排序文件中所有记录分成个 组,所有距离为的记录分在同一组内,并对每一组内的记录进行排序。然后,取,重复上述分组和排序的工 作。当到达 =1 时,所有记录在统一组内排好序
当gap>1时为预排序,目的是为了接近有序
当gap==1时为直接插入排序
间隔为gap的分为一组,总共gap组
先对一组进行排序
int gap = 3;
for (int i = 0; i < n - gap; i += gap)
{
	int end = i;
	int tmp = a[end + gap];
	while (end >= 0)
	{
		if (a[end] > tmp)
		{
			a[end + gap] = a[end];
			end -= gap;
		}
		else
		{
			break;
		}
	}
	a[end + gap] = tmp;
}

再对gap组都进行排序

int gap = 3;
for (int j = 0; j < gap; ++j)
{
	for (int i = j; i < n - gap; i += gap)
	{
		int end = i;
		int tmp = a[end + gap];
		while (end >= 0)
		{
			if (a[end] > tmp)
			{
				a[end + gap] = a[end];
				end -= gap;
			}
			else
			{
				break;
			}
		}
		a[end + gap] = tmp;
	}
}

这样就完成了预排序,但如果对于数据量大的情况下,不止会进行一次预排序且还要控制最后一次预排序的gap==1这样就可以直接排序完成

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 = a[end + gap];
			while (end >= 0)
			{
				if (a[end] > tmp)
				{
					a[end + gap] = a[end];
					end -= gap;
				}
				else
				{
					break;
				}
			}
			a[end + gap] = tmp;
		}
	}
}

对于这里可以优化掉一层循环变为

void ShellSort(int* a, int n)
{
	//当gap>1时为预排序,目的是为了接近有序
	//当gap==1时为直接插入排序
	//间隔为gap的分为一组,总共gap组

	int gap = n;
	while (gap > 1)
	{
		gap = gap / 3 + 1;
		
			for (int i = 0; i < n - gap; ++i)
			{
				int end = i;
				int tmp = a[end + gap];
				while (end >= 0)
				{
					if (a[end] > tmp)
					{
						a[end + gap] = a[end];
						end -= gap;
					}
					else
					{
						break;
					}
				}
				a[end + gap] = tmp;
			}
	}
}

以前的是一组排序完了再排下一组,这里是全部gap组一次排过去

3.关于gap如何取的问题以及一些其他注意问题

时间复杂度:O(N^1.3)

 三:BubbleSort(冒泡排序)

1.动图展示

2. 代码实现

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

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

详细介绍可参考https://blog.csdn.net/Miwll/article/details/135315155?spm=1001.2014.3001.5501

四: HeapSort(堆排序)

1.图片展示

2.思想及代码实现

堆排序 (Heapsort) 是指利用堆积树(堆)这种数据结构所设计的一种排序算法,它是选择排序的一种。它是通过堆来进行选择数据。需要注意的是排升序要建大堆,排降序建小堆
void AdjustDown(int* a, int n, int parent)
{
	int child = parent * 2 + 1;
	while (child < n)
	{
		if (child + 1 < n && a[child] < a[child + 1])
		{
			++child;
		}

		if (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)
	{
		AdjustDown(a, n, i);
	}

	//排数据--首尾交换再向下调整
	int end = n - 1;
	while (end)
	{
		Swap(&a[end], &a[0]);
		AdjustDown(a, end, 0);
		--end;
	}
}

时间复杂度为O(N*logN) 

详细可以参考https://blog.csdn.net/Miwll/article/details/136636869?spm=1001.2014.3001.5501

五:SelectSort(直接选择排序)

1.动图显示

2.思想及实现

每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,直到全部待排序的数据元素排完 。
void SelectSort(int* a, int n)
{
	//遍历一遍选出最大和最小值下标,再收尾交换
	int begin = 0, end = n - 1;
	int maxi = 0, mini = 0;
	while (begin < end)
	{
		for (int i = begin; i <= end; ++i)
		{
			if (a[i] > a[maxi]) maxi = i;
			if (a[i] < a[mini]) mini = i;
		}
		Swap(&a[begin], &a[mini]);
		if (begin == maxi)
		{
			maxi = mini;
		}
		Swap(&a[end], &a[maxi]);
		
		begin++;
		end--;
	}
}

这里需要注意当begin和maxi重叠的情况

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

六:QuickSort(快速排序)

 1.Hoare版本

1.动图展示

2.思想及实现

对于Hoare版本的快排是选取一个key值,然后先让右边先走找小,再左边找大,再交换继续往后直至相遇,再交换key位置处的值,再以相遇位置为划分子区间继续执行

画一部分递归展开图理解最小子问题的条件

 

3.为啥相遇位置一定比key值小?---右边先走保证的

 

4.快排的时间复杂度为O(N*logN),但在有序或者接近有序的情况下最坏为O(N^2),为了防止出现最坏的情况,可以使用三数取中或者随机选key来解决问题

//2.三数取中
int mid = GetMidi(a,begin, end);
Swap(&a[begin], &a[mid]);

int GetMidi(int*a,int left, int right)
{
	int mid = (left + right) / 2;
	if (a[left] < a[mid])
	{
		if (a[right] > a[mid])//mid>left right>mid
		{
			return mid;
		}
		else if (a[left] > a[right])//mid>left right<mid
		{
			return left;
		}
		else
		{
			return right;
		}
	}
	else //left>mid
	{
		if (a[right] < a[mid])//right<mid
		{
			return mid;
		}
		else if (a[left] > a[right])//right>mid 
		{
			return right;
		}
		else
		{
			return left;
		}
	}
}

5.小区间优化  由于到最后的几步时,递归的深度和广度是非常巨大的,因此可以采用小区间优化的方式减少递归,这里可以采用插入排序

void QuickSort1(int* a, int begin, int end)
{
	//最小子问题--区间不存在或者只有一个数据
	if (begin >= end) return;
	
	//1.随机选key---选[left, right]区间中的随机数做key
	//int randi = rand() % (end - begin + 1);
	//randi += begin;//在递归时begin不一定是0开始的
	//Swap(&a[begin],&a[randi]);
	if (end - begin + 1 < 10)
	{
		InsertSort(a+begin, end - begin + 1);
	}
	else
	{
		//2.三数取中
		int mid = GetMidi(a, begin, end);
		Swap(&a[begin], &a[mid]);

		int keyi = begin;
		int left = begin, right = end;
		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]);
		keyi = left;
		//[begin,keyi-1] keyi [keyi+1,end]
		QuickSort1(a, begin, keyi - 1);
		QuickSort1(a, keyi + 1, end);
	}
}

2.前后指针版本 

 1.动图展示

2.思想及实现

当cur处的值>=key时,++cur

当cur处的值<key时,++prev,再交换prev和cur的值,再++cur

void QuickSort2(int* a, int begin, int end)
{
	if (begin >= end) return;

	int prev = begin;
	int cur = begin + 1;
	int keyi = begin;
	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]
	QuickSort2(a, begin, keyi - 1);
	QuickSort2(a, keyi + 1, end);
}

3.非递归版本 

对于递归如果深度太深的话,就会导致栈溢出,因此用栈实现非递归版本很重要

思想:走一趟单趟,再右左区间入栈

void QuickSortNonR(int* a, int begin, int end)
{
	ST st;
	STInit(&st);

	//先入右再入左
	STPush(&st, end);
	STPush(&st, begin);

	while (!STEmpty(&st))
	{
		int left = STTop(&st);
		STPop(&st);

		int right = STTop(&st);
		STPop(&st);

		//单趟
		int keyi = left;
		int cur = left + 1;
		int prev = left;
		while (cur <= right)
		{
			if (a[cur] < a[keyi] && ++prev != cur)
				Swap(&a[cur],&a[prev]);

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

		//[left,keyi-1]keyi[keyi+1,right]
		//保证入的区间有效
		if (keyi + 1 < right)
		{
			STPush(&st, right);
			STPush(&st, keyi + 1);
		}
		if (left < keyi -1)
		{
			STPush(&st, keyi - 1);
			STPush(&st, left);
		}
		//Print(a, left, right);
	}
	STDestroy(&st);
}

4.快排之三路划分

1.快排性能的关键点分析

决定快排性能的关键点是每次单趟排序后,key对数组的分割,如果每次选key基本⼆分居中,那么快 排的递归树就是颗均匀的满⼆叉树,性能最佳。但是实践中虽然不可能每次都是⼆分居中,但是性能 也还是可控的。但是如果出现每次选到最⼩值/最⼤值,划分为0个和N-1的⼦问题时,时间复杂度为 O(N^2),数组序列有序时就会出现这样的问题,我们前⾯已经⽤三数取中或者随机选key解决了这个问 题,也就是说我们解决了绝⼤多数的问题,但是现在还是有⼀些场景没解决(数组中有⼤量重复数据时),即以下情况

 此时就提出了采用三路划分的思想来解决

这样再对比key大的数据区间和比key小的数据区间进行递归

//三路划分
void QuickSort3(int* a, int begin, int end)
{
	//最小子问题
	if (begin >= end) return;

	int left = begin, right = end;
	int key = a[left];

	int cur = left + 1;
	while (cur <= right)
	{
		if (a[cur] < key)
		{
			Swap(&a[left], &a[cur]);
			++cur;
			++left;
		}
		else if(a[cur]>key)
		{
			Swap(&a[cur],&a[right]);
			--right;
		}
		else
		{
			++cur;
		}
	}

	//[begin,left-1][left,right][right+1,end]
	QuickSort3(a, begin, left - 1);
	QuickSort3(a, right+1, end);
}

5.SGI-IntrospectiveSort(自省排序)

 introsort是introspectivesort采⽤了缩写,他的名字其实表达了他的实现思路,他的思路就是进⾏⾃ 我侦测和反省,快排递归深度太深(sgistl中使⽤的是深度为2倍排序元素数量的对数值)那就说明在 这种数据序列下,选key出现了问题,性能在快速退化,那么就不要再进⾏快排分割递归了,改换为堆 排序进⾏排序

void IntroSort(int* a, int left, int right, int depth, int defaultDepth)
{
	if (left >= right)
		return;

	// 数组长度⼩于16的⼩数组,换为插入排序,简单递归次数---小区间优化    
	if (right - left + 1 < 16)
	{
		InsertSort(a + left, right - left + 1);
		return;
	}
	// 当深度超过2 * logN时改用堆排序    
	if (depth > defaultDepth)
	{
		HeapSort(a + left, right - left + 1);
		return;
	}

	depth++;
	int begin = left;
	int end = right;

	// 随机选key
	int randi = left + (rand() % (right - left));
	Swap(&a[left], &a[randi]);

	int prev = left;
	int cur = prev + 1;
	int keyi = left;
	while (cur <= right)
	{
		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]
	IntroSort(a, begin, keyi - 1, depth, defaultDepth);
	IntroSort(a, keyi + 1, end, depth, defaultDepth);
}

void QuickSort4(int* a, int begin, int end)
{
	int depth = 0;
	int logn = 0;
	int N= end - begin + 1;
	for (int i = 1; i < N; i *= 2)
	{
		logn++;
	}
	// introspective sort -- 自省排序
	IntroSort(a, begin, end, depth, logn * 2);
}

七:MergeSort(归并排序) 

1.递归版本

1.动图演示

 2.思想及实现

归并排序( MERGE-SORT )是建立在归并操作上的一种有效的排序算法 , 该算法是采用分治法 Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有 序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并

void _MergeSort(int* a, int left,int right,int*tmp)
{
	//最小子问题
	if (left == right) return;

	int mid = (left + right) / 2;
	//[begin,mid][mid+1,end]
	_MergeSort(a, left, mid, tmp);
	_MergeSort(a, mid + 1, right, tmp);

	//开始归并
	int begin1 = left, end1=mid;
	int begin2=mid+1, end2=right;
	int i = left;
	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++];
	}
	memcpy(a + left, tmp + left, sizeof(int) * (right-left+1));
}
void MergeSort(int* a, int n)
{
	int* tmp = (int*)malloc(sizeof(int) * n);
	if (tmp == NULL)
	{
		perror("malloc fail\n");
		return;
	}
	_MergeSort(a, 0, n - 1, tmp);
	free(tmp);
	tmp = NULL;
}

 部分递归展开

2.非递归版本 

这里的非递归版本采用循环的方式来解决

void MergeSortNonR(int* a, int n)
{
	int* tmp = (int*)malloc(sizeof(int) * n);
	if (tmp == NULL)
	{
		perror("malloc fail\n");
		return;
	}

	int gap = 1;
	while (gap < n)
	{
		for (int i = 0; i < n; i += 2 * gap)
		{
			int begin1 = i, end1 = begin1 + gap - 1;
			int begin2 = end1 + 1, end2 = begin2 + gap - 1;

			//调整越界问题
			if (end1 >= n || begin2 >= n)
			{
				break;
			}
			if (end2 >= n)//修正
			{
				end2 = n - 1;
			}
			int j = i;
			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));
		}
		gap *= 2;
	}
}

 八:CountSort(计数排序)

1.思想及实现

开辟一个数组用来统计每个数据出现的次数,在相对映射位置的次数++,然后再往原数组写入数据,适合于整形且数据集中的

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

	int range = max - min + 1;
	int* count = (int*)malloc(sizeof(int) * range);
	if (count == NULL)
	{
		perror("malloc fail\n");
		return;
	}
	memset(count, 0, sizeof(int) * range);
	//统计次数
	for (int i = 0; i < n; ++i)
	{
		count[a[i] - min]++;
	}

	//写回原数组
	int j = 0;
	for (int i = 0; i < range; ++i)
	{
		while (count[i]--)
		{
			a[j++] = i + min;
		}
	}
}

 总结

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

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

相关文章

数组Arrays,排序算法,String类,Stringbulider,正则表达式

## 数组 排序 经典的三大排序&#xff1a;冒泡&#xff0c;选择&#xff0c;插入 &#xff08;一&#xff09;冒泡排序核心&#xff1a;数组中的 相邻 两项比较&#xff0c;交换&#xff08;正序or倒序&#xff09; 正序原理图&#xff1a; 代码实现&#xff1a; public s…

jmeter 重试机制

一、功能实现 我们在测试过程中&#xff0c;请求接口可能是因为请求超时&#xff0c;或者接口异常失败&#xff0c;导致整个测试链路验证失败&#xff0c;jmeter重试机制&#xff0c;这个时候就可以避免上述问题发生 二、配置 1、添加线程组 首先&#xff0c;确保你已经在测…

Python | Leetcode Python题解之第278题第一个错误的版本

题目&#xff1a; 题解&#xff1a; # The isBadVersion API is already defined for you. # def isBadVersion(version: int) -> bool:class Solution:def firstBadVersion(self, n: int) -> int:left, right 1, nwhile left < right:mid left (right - left) //…

power bi条件判断函数

power bi条件判断函数 1. iferror函数2. if 函数3. switch函数4. hasonefilter函数5. hasonevalue函数6. selectedvalue函数 1. iferror函数 遇到错误时使用指定数值替换注意&#xff1a;替换的必须是数值例子列 [销售数量]*[单价] 列 iferror([销售数量]*[单价],0) 列 ife…

昇思25天学习打卡营第17天|计算机视觉

昇思25天学习打卡营第17天 文章目录 昇思25天学习打卡营第17天ShuffleNet图像分类ShuffleNet网络介绍模型架构Pointwise Group ConvolutionChannel ShuffleShuffleNet模块构建ShuffleNet网络 模型训练和评估训练集准备与加载模型训练模型评估模型预测 打卡记录 ShuffleNet图像分…

自学Java第11Day

学习目标&#xff1a;面向对象进阶 学习内容&#xff1a;包、final、权限修饰符、代码块、抽象类、接口 学习时间&#xff1a; 下午 3 点-下午 6 点 学习产出&#xff1a; 什么的包&#xff1f; 包就是文件夹。用来管理各种不同功能的Java类&#xff0c;方便后期代码维护。 包…

【Go系列】Go的UI框架Fyne

前言 总有人说Go语言是一门后端编程语言。 Go虽然能够很好地处理后端开发&#xff0c;但是者不代表它没有UI库&#xff0c;不能做GUI&#xff0c;我们一起来看看Go怎么来画UI吧。 正文 Go语言由于其简洁的语法、高效的性能和跨平台的编译能力&#xff0c;非常适合用于开发GUI…

爬虫学习1:初学者简单了解爬虫的基本认识和操作(详细参考图片)

爬虫 定义&#xff1a;爬虫&#xff08;Web Crawler 或 Spider&#xff09;是一种自动访问互联网上网页的程序&#xff0c;其主要目的是索引网页内容&#xff0c;以便搜索引擎能够快速检索到相关信息。以下是爬虫的一些关键特性和功能&#xff1a; 自动化访问&#xff1a;爬虫能…

58、主从复制数据库+读写分离

mysql的主从复制和读写分离&#xff08;面试问原理&#xff09; mysql的主从复制和读写分离&#xff1a; 主从复制 面试必问 主从复制的原理。 读写分离&#xff0c;MHA 一、主从复制 1.1、主从复制的模式&#xff1a; 1、mysql的默认模式&#xff1a; 异步模式&#xf…

centos系统mysql数据库差异备份与恢复

文章目录 差异备份mysql数据一、 安装 Percona XtraBackup数据库中创建一些数据三、创建全备份四、创建差异备份1. 在数据库中添加数据&#xff0c;让数据发生一些改变2. 创建第一个差异备份3. 数据库中再次添加一些数据4. 创建第二个差异备份 五、模拟数据丢失&#xff0c;删库…

MongoDB 学习笔记

一、简介 1、MongoDB 是什么 MongoDB 是一个基于分布式文件存储的数据库&#xff0c;官方地址 https://www.mongodb.com/ 2、数据看是什么 数据库&#xff08;DataBase&#xff09;是按照数据结构来组织、存储和管理数据的应用程序。 3、数据库的作用 主要作用是 管理数据…

Data Analytics for Business BISM7233

SSIS Task: Company_data.csv contains information for each of the companies, some of the state code information is missing in this table. You would need to use “state_code.csv” to fill in these blank cells under state code before creating the company dime…

利用OSMnx求路网最短路径并可视化(二)

书接上回&#xff0c;为了增加多路径的可视化效果和坐标匹配最近点来实现最短路可视化&#xff0c;我们使用图形化工具matplotlib结合OSMnx的绘图功能来展示整个路网图&#xff0c;并特别高亮显示计算出的最短路径。 多起终点最短路路径并计算距离和时间 完整代码#运行环境 P…

vite环境下使用bootstrap

环境 nodejs 18 pnpm 初始化 pnpm init pnpm add -D vite --registry http://registry.npm.taobao.org pnpm add bootstrap popperjs/core --registry http://registry.npm.taobao.org pnpm add -D sass --registry http://registry.npm.taobao.org新建vite.config.js cons…

【微服务】Spring Cloud Bus的注意事项和常用案例

文章目录 强烈推荐引言关键方面注意事项1. 消息代理选择2. 消息队列配置3. 消息持久化4. 幂等性5. 安全性6. 消息大小7. 性能监控8. 错误处理9. 版本兼容性10. 测试11. 配置同步12. 日志记录 常用示例示例 1: 配置同步配置服务器 (config-server)客户端服务 (client-service)触…

数据库的事务隔离级别有哪些?

并行事务会引发什么问题&#xff1f; 同时处理多个事务的时候&#xff0c;就可能出现脏读&#xff08;dirty read&#xff09;、不可重复读&#xff08;non-repeatable read&#xff09;、幻读&#xff08;phantom read&#xff09;的问题。脏读: 如果一个事务「读到」了另一个…

MQ消息队列+Lua 脚本实现异步处理下单流程,将同步下单改为异步下单

回顾一下下单流程&#xff1a; 用户发起请求 会先请求Nginx,Nginx反向代理到Tomcat&#xff0c;而Tomcat中的程序&#xff0c;会进行串行工作&#xff0c; 分为以下几个操作&#xff1a; 1 查询优惠券 2 判断秒杀库存是否足够 3 查询订单 4 校验是否是一人一单 5 扣减库…

Unity Shader - 2024 工具篇

目录 IDE 工具建议 IDE工具 Sublime 3 大势所趋&#xff0c;但是Sublime 使用插件还是相当的不习惯 代码跳转 Go to definite IDE 工具建议 () what is the best ide for coding shaderlab - #4 by DaveAstator - Unity Engine - Unity Discussions​​​​​​​I IDE工…

用Swagger进行后端接口测试的实战操作

目录 一.什么是Swagger&#xff1f; 二.Swagger的使用操作流程&#xff1a; 1.在pom.xml配置文件导入 Knife4j 的依赖&#xff1a; 2.在config配置类中加入 Knife4j 的相关配置并设置静态资源映射&#xff08;否则接口文档无法访问&#xff09;&#xff1a; 三.Swagger的四个…

案例研究|柯尼卡美能达软件开发(大连)有限公司基于DataEase构筑内部数据可视化体系

柯尼卡美能达软件开发&#xff08;大连&#xff09;有限公司于2007年5月25日注册成立。公司以“洞悉在工作的人们真实情况&#xff0c;探寻他们的愿望&#xff0c;持续提供使人们更加幸福的服务”为使命&#xff0c;致力于系统品质测试服务、软件开发服务、IT安全服务、高级BPO…