【C语言】数据结构——排序二(快排)

news2024/11/25 13:00:48

💗个人主页💗
⭐个人专栏——数据结构学习⭐
💫点击关注🤩一起学习C语言💯💫

目录

  • 导读:
  • 数组打印与交换
  • 1. 交换排序
    • 1.1 基本思想:
    • 1.2 冒泡与快排的异同
  • 2. 冒泡排序
    • 2.1 基本思想
    • 2.2 实现代码
  • 3. 快速排序
    • 3.1 基本思想
    • 3.2 hoare版本
      • 3.2.1 动图讲解
      • 3.2.2 实现代码
      • 3.2.3 代码优化
    • 3.3 挖坑法
      • 3.3.1 动图详解
      • 3.3.2实现代码
    • 3.4 双指针
      • 3.4.1 动图详解
      • 3.4.2 实现代码
  • 4. 无递归实现快排
    • 4.1 基本思想
    • 4.2 实现代码

导读:

我们在前面学习了排序,包括直接插入排序,希尔排序,选择排序,堆排序。
今天我们来学习交换排序,也就是冒泡排序和快排。
下期我们来讲一讲归并排序。
关注博主或是订阅专栏,掌握第一消息。

数组打印与交换

为了方便我们来测试每个排序是否完成,我们来写个打印数组和交换两数的函数,方便我们后续的打印与交换。

void PrintArray(int* a, int n)
{
	for (int i = 0; i < n; i++)
	{
		printf("%d ", a[i]);
	}
	printf("\n");
}

void Swap(int* p1, int* p2)
{
	int tmp = *p1;
	*p1 = *p2;
	*p2 = tmp;
}

1. 交换排序

1.1 基本思想:

所谓交换,就是根据序列中两个记录键值的比较结果来对换这两个记录在序列中的位置。将键值较大的记录向序列的尾部移动,键值较小的记录向序列的前部移动。
交换排序包括冒泡排序与快速排序。

1.2 冒泡与快排的异同

相似之处:

都是基于比较的排序算法,通过比较元素的大小来确定它们的顺序。

不同之处:

  1. 思想不同:冒泡排序是通过相邻元素的比较和交换来将较大的元素“浮”到序列的末尾,而快速排序是通过在序列中选择一个基准元素,将序列分割成两个子序列,并递归地对子序列进行排序。

  2. 时间复杂度不同:冒泡排序的平均时间复杂度为O(n2),最好情况下为O(n),最坏情况下为O(n2)。快速排序的平均时间复杂度为O(nlogn),最坏情况下为O(n^2)。

  3. 空间复杂度不同:冒泡排序的空间复杂度为O(1),原地排序。快速排序的空间复杂度为O(logn),需要使用递归栈空间。

  4. 稳定性不同:冒泡排序是稳定的排序算法,相等元素的相对顺序不会改变。快速排序是不稳定的排序算法,相等元素的相对顺序可能会改变。

总结:冒泡排序和快速排序都是基于比较的排序算法,它们的主要区别在于思想、时间复杂度、空间复杂度和稳定性等方面。快速排序通常比冒泡排序更高效,但在某些情况下冒泡排序可能更适合,例如对较小规模的数据进行排序。

2. 冒泡排序

2.1 基本思想

冒泡排序算法的基本思想是要将待排序序列中的元素逐个比较并交换位置,使得较大的元素逐渐“浮”到序列的末尾。

  1. 从待排序序列的第一个元素开始,逐个比较相邻的两个元素。

  2. 如果前一个元素比后一个元素大,则交换它们的位置。这样就使得较大的元素逐渐“浮”到序列的末尾。

  3. 继续对剩下的元素重复上述比较和交换的过程,直到整个序列有序为止。

  4. 重复上述步骤,每次将待排序序列的长度减1,直到待排序序列的长度为1。

冒泡排序算法的思想类似于水中冒泡,较大的元素会逐渐向上浮动,而较小的元素会逐渐沉淀到底部。因此,最终结果是将待排序序列从小到大排序。

冒泡排序算法的时间复杂度为O(n^2),其中n为待排序序列的长度。尽管冒泡排序算法的效率相对较低,但由于其实现简单,适用于数据量较小的情况。

2.2 实现代码

// 冒泡排序
void BubbleSort(int* a, int n)
{
	int i = 0;
	int j = 0;
	for (i = 0; i < n; i++)
	{
		for (j = 0; j < n - i -1; j++)
		{
			if (a[j + 1] < a[j])
			{
				Swap(&a[j + 1], &a[j]);
			}
		}
	}
}
void TestBubbleSort()
{
	int arr[10] = { 5, 1, 8, 7, 3, 9, 2, 0, 4, 6 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	BubbleSort(arr, 10);
	PrintArray(arr, 10);
}
int main()
{
	TestBubbleSort();
	return 0;
}

3. 快速排序

快速排序有三种实现方法:

  1. hoare版本
  2. 挖坑法
  3. 双指针

3.1 基本思想

快速排序是一种基于分治思想的排序算法,其基本思想可以概括为以下步骤:

  1. 选择一个基准元素:从待排序序列中选择一个元素作为基准元素。

  2. 分割操作:以基准元素为准,将序列分割成两个子序列,使得左边的子序列中的所有元素都小于等于基准元素,右边的子序列中的所有元素都大于基准元素。这个分割操作可以采用多种方式实现,常见的有挖坑法、交换法和指针交替法等。

  3. 递归排序:对分割后的两个子序列分别递归地进行快速排序,直到子序列的长度为1或0,即递归的终止条件。

  4. 合并操作:将分割后的子序列进行合并,即将左边子序列、基准元素和右边子序列按照顺序拼接起来,得到完整的排序序列。

整个过程可以通过递归来实现,每次递归中选取一个基准元素,将序列分割成两部分,然后递归地对两部分进行排序,最后将结果合并起来得到有序序列。

快速排序的时间复杂度为O(nlogn),其中n为待排序序列的长度。在最坏情况下,快速排序的时间复杂度为O(n^2),但通常情况下快速排序是一种高效的排序算法。快速排序是原地排序的算法,不需要额外的空间。然而,由于快速排序是递归实现的,所以需要使用递归栈空间。

3.2 hoare版本

3.2.1 动图讲解

我们需要定义一个key来指向第一个数,也就是基准元素。
同时定义leftright来指向数组的两端。
我们让right先走,来找比key小的值,找到后left开始走,去找比key大的值,找到之后交换leftright的值,之后继续right找小,left找大,直到两者相遇,循环结束。
这时再把key处的值和left处的值交换,让key走到left位置。

请添加图片描述
第一次循环结束后如图:
左边的值都比key处的值小,而右边的值都比key处的值大。
这时key所指向的值就是我们上面所说的基准元素。
在这里插入图片描述
下面我们就需要以key为中点,分为左右两个序列。
在这里插入图片描述
然后我们可以用递归继续调用这个函数,分别把左子序列和右子序列继续排序划分为若干左右子序列,这样就能实现排序。

3.2.2 实现代码

递归结束条件就是当第n个子序列长度为1或者0时结束,也就是子序列起点和尾点重合。

void QuickSort1(int* a, int begin, int end)
{
	if (begin >= end)
	{
		return;
	}
	int key = begin;
	int left = begin;
	int right = end;
	while (left < right)
	{
		// 右边先走,找比key值小的
		while (right > left && a[right] >= a[key])
		{
			right--;
		}
		// 左边后走,找比key值大的
		while (right > left && a[left] <= a[key])
		{
			left++;
		}
		Swap(&a[left], &a[right]);
	}
	Swap(&a[key], &a[left]);
	key = left;
	//分左右两边
	//左边
	QuickSort1(a, begin, key - 1);
	//右边
	QuickSort1(a, key + 1, end);
}
void TestQuickSort1()
{
	int arr[10] = { 5, 1, 8, 7, 3, 9, 2, 0, 4, 6 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	QuickSort1(arr, 0, sz - 1);
	PrintArray(arr, 10);
}
int main()
{
	TestQuickSort1();
	return 0;
}

3.2.3 代码优化

如果我们遇到一些极端的情况,比如数组是以排序好或者逆序,这可能就会使我们的时间复杂度大大增加,以及递归调用的太多,可能会导致Stack Overflow的情况。
我们就可以在key,left和right三者中选择一个中位数来当key值。
还有比如数据较少的情况下,选择快排是不大理想的,这时我们用直接插入排序效果会更好。

//优化
int GetMidi(int* a, int begin, int end)
{
	int midi = (begin + end) / 2;
	// begin midi end 三个数选中位数
	if (a[begin] < a[midi])
	{
		if (a[midi] < a[end])
			return midi;
		else if (a[begin] > a[end])
			return begin;
		else
			return end;
	}
	else // a[begin] > a[midi]
	{
		if (a[midi] > a[end])
			return midi;
		else if (a[begin] < a[end])
			return begin;
		else
			return end;
	}
}

// hoare
void QuickSort1(int* a, int begin, int end)
{
	if (begin >= end)
	{
		return;
	}
	if (end - begin + 1 <= 10)
	{
		InsertSort(a + begin, end - begin + 1);
	}
	else
	{
		int midi = GetMidi(a, begin, end);
		Swap(&a[midi], &a[begin]);

		int key = begin;
		int left = begin;
		int right = end;
		while (left < right)
		{
			// 右边先走,找比key值小的
			while (right > left && a[right] >= a[key])
			{
				right--;
			}
			// 左边后走,找比key值大的
			while (right > left && a[left] <= a[key])
			{
				left++;
			}
			Swap(&a[left], &a[right]);
		}
		Swap(&a[key], &a[left]);
		key = left;
		//分左右两边
		//左边
		QuickSort1(a, begin, key - 1);
		//右边
		QuickSort1(a, key + 1, end);
	}
	
}
void TestQuickSort1()
{
	int arr[10] = { 5, 1, 8, 7, 3, 9, 2, 0, 4, 6 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	QuickSort1(arr, 0, sz - 1);
	PrintArray(arr, 10);
}
int main()
{
	TestQuickSort1();
	return 0;
}

3.3 挖坑法

3.3.1 动图详解

挖坑法与hoare版本的快排并无太大差别。
我们另定义一个hole变量,left和right不变,这时的key不再是下标,而是一个具体的数值,key是首元素的值。
我们仍旧是右边先找小,找到之后并不是直接让左边去找大,而是让这个小的值赋值给hole的位置,注意不是交换,key的值记录着最开始的hole位置的值,不必担心丢失。
接着让hole移动到right位置,左边开始找大,找到后也是把left指向的值赋值给hole位置,hole移动到left位置。
仍旧是left和right相遇之后,把key记录的值赋值给hole位置。
请添加图片描述

3.3.2实现代码

//挖坑法
void QuickSort2(int* a, int begin, int end)
{
	if (begin >= end)
	{
		return;
	}
	int midi = GetMidi(a, begin, end);
	Swap(&a[midi], &a[begin]);
	int left = begin;
	int right = end;
	int hole = left;
	int key = a[hole];
	while (left < right)
	{
		while (a[right] >= key && right > left)
		{
			right--;
		}
		a[hole] = a[right];
		hole = right;
		while (a[left] <= key && right > left)
		{
			left++;
		}
		a[hole] = a[left];
		hole = left;
	}
	a[hole] = key;
	QuickSort2(a, begin, hole - 1);
	QuickSort2(a, hole + 1, end);
}

void TestQuickSort2()
{
	int arr[10] = { 5, 1, 8, 7, 3, 9, 2, 0, 4, 6 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	QuickSort2(arr, 0, sz - 1);
	PrintArray(arr, 10);
}
int main()
{
	TestQuickSort2();
	return 0;
}

3.4 双指针

3.4.1 动图详解

双指针相对于上面两个代码是相较少的,不必再去三位取中。
定义两个指针cur,prev,而key仍然是值。
开始的时候两个指针都指向第一个元素
在这里插入图片描述
之后cur先走,找比key值小的数,找到之后,prev向前走一步,如果这时prev和cur的指向的不是同一个元素,就交换两者指向的值。
反之,如果两者重叠,cur则继续往前走一步。
请添加图片描述
直到cur出了数组,循环结束,这时再交换key值和prev。
再以prev为中心,分为左右子序列。

3.4.2 实现代码

// 双指针
void QuickSort3(int* a, int begin, int end)
{
	if (begin >= end)
	{
		return;
	}
	int key = begin;
	int prev = begin;
	int cur = prev + 1;
	while (cur <= end)
	{
		if (a[cur] < a[key] && ++prev != cur)
		{
			Swap(&a[cur], &a[prev]);
		}
		cur++;
	}
	Swap(&a[key], &a[prev]);
	QuickSort3(a, begin, prev - 1);
	QuickSort3(a, prev + 1, end);
}
void TestQuickSort3()
{
	int arr[10] = { 5, 1, 8, 7, 3, 9, 2, 0, 4, 6 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	QuickSort3(arr, 0, sz - 1);
	PrintArray(arr, 10);
}
int main()
{
	TestQuickSort3();
	return 0;
}

4. 无递归实现快排

4.1 基本思想

非递归实现快速排序算法的关键是使用栈来模拟递归过程。具体步骤如下:

  1. 创建一个栈,并将待排序数组的起始索引和结束索引入栈。
  2. 循环直到栈为空:
  • 弹出栈顶的起始索引和结束索引,作为当前子数组的范围。
  • 选择一个基准元素,将数组按照基准元素进行划分,得到基准元素的索引。
  • 如果基准元素左侧的子数组长度大于1,则将左侧子数组的起始索引和结束索引入栈。
  • 如果基准元素右侧的子数组长度大于1,则将右侧子数组的起始索引和结束索引入栈。
  1. 返回排序后的数组。

4.2 实现代码

前面我们都是用递归的方法来实现快排的,思考一下不用递归该怎么写。
这里我们可以用栈来实现,我们每次把需要排列的左右子序列的开始和结束的下标入栈,记录范围,之后再出栈赋给left和right,又或者其它变量,最后调用上面的函数来实现排序。
我们先来看代码,后面来具体分析。
在这里的栈,我还是调用之前写的栈代码,感兴趣的小伙伴可以看数据结构的专栏。
在这里插入图片描述

// hoare
int PartSort1(int* a, int begin, int end)
{
	int midi = GetMidi(a, begin, end);
	Swap(&a[midi], &a[begin]);

	int left = begin, right = end;
	int keyi = begin;

	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]);

	return left;
}
//挖坑法
int PartSort2(int* a, int begin, int end)
{
	int midi = GetMidi(a, begin, end);
	Swap(&a[midi], &a[begin]);
	int left = begin;
	int right = end;
	int hole = left;
	int key = a[hole];
	while (left < right)
	{
		while (a[right] >= key && right > left)
		{
			right--;
		}
		a[hole] = a[right];
		hole = right;
		while (a[left] <= key && right > left)
		{
			left++;
		}
		a[hole] = a[left];
		hole = left;
	}
	a[hole] = key;
	return hole;
}
//双指针
int PartSort3(int* a, int begin, int end)
{
	int midi = GetMidi(a, begin, end);
	Swap(&a[midi], &a[begin]);
	int key = begin;
	int prev = begin;
	int cur = prev + 1;
	while (cur <= end)
	{
		if (a[cur] < a[key] && ++prev != cur)
		{
			Swap(&a[cur], &a[prev]);
		}
		cur++;
	}
	Swap(&a[key], &a[prev]);
	key = prev;
	return key;
}
//无递归方法实现
void QuickSortNonR(int* a, int begin, int end)
{
	ST s;
	STInit(&s);
	STPush(&s, end);
	STPush(&s, begin);
	while (!STEmpty(&s))
	{
		int left = STTop(&s);
		STPop(&s);
		int right = STTop(&s);
		STPop(&s);

		int keyi = PartSort3(a, left, right);
		// [left, keyi-1] keyi [keyi+1, right]
		if (left < keyi - 1)
		{
			STPush(&s, keyi - 1);
			STPush(&s, left);
		}
		if (keyi + 1 < right)
		{
			STPush(&s, right);
			STPush(&s, keyi + 1);
		}
	}
	STDestroy(&s);
}

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

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

相关文章

【模型】模型量化技术:动态范围、全整数和Float16量化

目录 一 动态范围量化 二 全整数量化 三 float16量化 通常&#xff0c;表示神经网络的数据类型是32位浮点数&#xff08;float32&#xff09;&#xff0c;这种数据类型可以提供高精度的计算&#xff0c;但是在计算资源和存储空间有限的设备上运行神经网络时&#xff0c;会带…

小型内衣洗衣机什么牌子好?口碑好的小型洗衣机

想必大家都知道&#xff0c;我们的内衣裤、袜子这些衣物对卫生方面的要求是比较的高&#xff0c;毕竟是贴身的衣物&#xff0c;因此是要分开清洗的&#xff0c;而不能够跟我们其他的大件衣服一起放入到大型洗衣机里进行混洗&#xff0c;很多就选择了分开单独的手洗&#xff0c;…

【Python排序算法系列】—— 冒泡排序

&#x1f308;个人主页: Aileen_0v0 &#x1f525;热门专栏: 华为鸿蒙系统学习|计算机网络|数据结构与算法 &#x1f4ab;个人格言:"没有罗马,那就自己创造罗马~" 目录 冒泡排序 过程演示&#xff1a; 冒泡排序实现代码&#xff1a; 分析冒泡排序&#xff1a; P…

车载毫米波雷达及芯片新趋势研究2--“CMOS+AiP+SoC”与4D毫米波雷达推动产业越过大规模发展临界点

2.1 MMIC芯片工艺发展至CMOS时代&#xff0c;芯片集成度更高、体积与成本下降  MMIC芯片工艺经GaAs、SiGe已发展至CMOS时代&#xff0c;CMOS MMIC具有更低成本、更高集成度的优势。 工艺的主要变化发生在MMIC芯片的射频材料部分&#xff0c;目前SiGe仍为主流工艺。 SiGe虽在…

c# label 自定义行间距

label 添加 Paint 事件。用"\n" 段落换行 private void label2_Paint(object sender, PaintEventArgs e){int LineDistance 8;//行间距System.Windows.Forms.Label label sender as System.Windows.Forms.Label;System.Drawing.Font drawFont label.Font;label.Au…

Tips:电池电源电压转换为220V

今天在进行操作的时候&#xff0c;看到一个新的东西&#xff0c;就是如何普通的电瓶电压转化为220V交流电。 当在室外或者工作地距离电源比较远的情况下&#xff0c;一般是选取拉线的方式进行采电&#xff0c;但是当距离电源过远&#xff0c;使用拉线的方式就不可用了。如何在…

【Vue2+3入门到实战】(9)Vue基础之组件的三大组成部分(结构/样式/逻辑) 详细示例

目录 一、学习目标1.组件的三大组成部分&#xff08;结构/样式/逻辑&#xff09; 二、scoped解决样式冲突**1.默认情况**&#xff1a;2.代码演示3.scoped原理4.总结 三、data必须是一个函数1、data为什么要写成函数2.代码演示3.总结 一、学习目标 1.组件的三大组成部分&#x…

ksuser.dll文件缺失怎么办?软件或游戏无法启动,一键自动修复

很多小伙伴反馈&#xff0c;自己的电脑中了病毒&#xff0c;被杀毒软件清理后&#xff0c;在打开游戏或软件的时候&#xff0c;经常会报错“提示无法找到ksuser.dll文件&#xff0c;建议重新安装软件或游戏”。自己根据提示重装后&#xff0c;还是报错&#xff0c;不知道应该怎…

php学习05-常量

常量可以理解为值不变的量。常量值被定义后&#xff0c;在脚本的其他任何地方都不能改变。一个常量由英文字母、下划线和数字组成&#xff0c;但数字不能作为首字母出现。 在PHP中使用define()函数来定义常量&#xff0c;该函数的语法格式如下&#xff1a; define(string cons…

[SWPUCTF 2021 新生赛]error

[SWPUCTF 2021 新生赛]error wp 信息搜集 查看页面&#xff1a; 输个单引号会报错&#xff1a; 显然是 SQL 注入。 提示看看有没有什么捷径&#xff0c;你要说捷径的话&#xff0c;sqlmap&#xff1f;你不说我也会用 sqlmap 先跑一下&#xff0c;哈哈。 sqlmap 的使用 先简…

基于优化的规划方法 - 数值优化基础 Frenet和笛卡尔的转换 问题建模 实现基于QP的路径优化算法

本文讲解基于优化的规划算法&#xff0c;将从以下几个维度讲解&#xff1a;数值优化基础、Frenet与Cartesian的相互转换、问题建模OSQP 1 数值优化基础 1.1 优化的概念 一般优化问题公式&#xff1a; f ( x ) f(x) f(x)&#xff1a;目标/成本函数 x x x&#xff1a;决策变…

Python圣诞树代码

Python圣诞树代码 # 小黄 2023/12/25import turtle as t # as就是取个别名&#xff0c;后续调用的t都是turtle from turtle import * import random as rn 100.0speed(20) # 定义速度 pensize(5) # 画笔宽度 screensize(800, 800, bgblack) # 定义背景颜色&#xff0c;可…

共建鸿蒙世界,信息流合作突破500家;程序员能入局吗?

12月28日&#xff0c;华为信息流在上海举办了创作者系列沙龙。HarmonyOS是面向万物互联全场景时代的智能终端操作系统&#xff0c;鸿蒙正致力于打造“一切皆服务&#xff0c;万物可分享”自主创新的移动应用生态。到目前为止&#xff0c;鸿蒙生态的设备数量已经超过7亿&#xf…

Spire.Office for Java 8.12.0

Spire.Office for Java 8.12.0 发布。在该版本中&#xff0c;Spire.XLS for Java支持检索使用WPS工具添加的嵌入图像&#xff1b;Spire.PDF for Java 增强了从 PDF 到 SVG、PDF/A1B 和 PDF/A2A 的转换。此外&#xff0c;该版本还修复了许多已知问题。下面列出了更多详细信息。 …

Modbus转Profinet,不会编程也能用!轻松快上手!

Modbus转Profinet是一种用于工业自动化领域的通信协议转换器&#xff0c;可以将Modbus协议转换为Profinet协议&#xff0c;实现设备之间的数据交换与通信。这个工具的使用非常简单&#xff0c;即使没有编程经验的人也可以轻松上手。即使不会编程的人也可以轻松快速上手使用Modb…

全球知名数字资产平台LBank 与 The Sandbox Korea 达成战略合作

全球知名数字资产平台LBank&#xff0c;携手韩国元宇宙创新者The Sandbox Korea&#xff0c;共同开启了一场数字与虚拟世界的奇妙之旅。自2023年11月22日起&#xff0c;这两大巨头正式结成战略联盟&#xff0c;以提升用户体验为核心目标&#xff0c;开启了全新的合作篇章。 在…

51系列--数码管显示的4X4矩阵键盘设计

本文介绍基于51单片机的4X4矩阵键盘数码管显示设计&#xff08;完整Proteus仿真源文件及C代码见文末链接&#xff09; 一、系统及功能介绍 本设计主控芯片选用51单片机&#xff0c;主要实现矩阵键盘对应按键键值在数码管上显示出来&#xff0c;矩阵键盘是4X4共计16位按键&…

Apipost一键压测参数化功能详解

最近更新中Apipost对UI页面进行了一些调整&#xff0c;另外一键压测功能支持参数化&#xff01;本篇文章将详细介绍这些改动&#xff01; API调试页面的细节改动 在请求区填入请求参数或脚本时会有相应的标识 如在Query中填入多个参数时上方会展示数量 在预、后执行脚本中写…

机器人中的数值优化之罚函数法

欢迎大家关注我的B站&#xff1a; 偷吃薯片的Zheng同学的个人空间-偷吃薯片的Zheng同学个人主页-哔哩哔哩视频 (bilibili.com) 本文ppt来自深蓝学院《机器人中的数值优化》 目录 1 L2-Penalty Method 1.1等式约束 1.2不等式约束 2 L1-Penalty Method 3 Barrier Method …

并发编程大杀器,京东多线程编排工具asyncTool

一、简介 并发编程大杀器&#xff0c;京东多线程编排工具asyncTool&#xff0c;可以解决任意的多线程并行、串行、阻塞、依赖、回调的并行框架&#xff0c;可以任意组合各线程的执行顺序&#xff0c;带全链路执行结果回调。多线程编排一站式解决方案。 二、特点 多线程编排&am…