快排(动图详细版,快速理解)

news2024/11/27 6:37:09

注:本文主要介绍六大排序中的快排

在这里插入图片描述

文章目录

  • 前言
  • 一、三大法则
    • 1.1 Hoare法
    • 1.2 挖坑法
    • 1.3 双指针法(更加便捷)
    • 1.4 三种方法时间复杂度计算
  • 二、快排栈问题优化方式
    • 2.1 三数取中
    • 2.2 小区间优化
  • 三、非递归快排


前言

快速排序是Hoare于1962年提出的一种二叉树结构的交换排序方法,其基本思想为:任取待排序元素序列中的某元素作为基准值,按照该排序码将待排序集合分割成两子序列,左子序列中所有元素均小于基准值,右子序列中所有元素均大于基准值,然后最左右子序列重复该过程,直到所有元素都排列在相应位置上为止。


一、三大法则

1.1 Hoare法

什么是Hoare法则呢?
Hoare法是指在对数组进行排序时,定义两个变量,与一个在单子循环中不变的key值,右值先动找比key小的数字,找到后左值动,找比key大的数字,后进行交换以完成对数组的排序。

初始状态
初始状态

right先进行寻找,找到5<key3在这里插入图片描述

left进行寻找找到7>key,进行交换
哈哈哈

继续进行刚才的工作交换9/4
在这里插入图片描述

当左值与右值相等时,一次循环结束,left与right所在位置与初始的key位置进行Swap交换,进入递归循环。
在这里插入图片描述

1.Hoare法代码
void PartSort1(vector<int>& v, int begin, int end)
{
	//出递归判断
	if (begin >= end)
	{
		return;
	}
	int key = begin;
	int left = begin, right = end;
	while (left < right)
	{
		//寻找小于key的左值
		while (right > left && v[right] >= v[key])
		{
			right--;
		}
		//寻找大于key的右值
		while (right > left && v[left] <= v[key])
		{
			left++;
		}
		Swap(v[left], v[right]);
	}
	Swap(v[key], v[left]);
	//key左边都是小于key的数,key右边都是大于key的数字
	key = left;
	//进入递归,先递归左半部分小于key的区间,后递归右半部分大于key的区间
	QuickSort(v, begin, key - 1);
	QuickSort(v, key + 1, end);
}
int main()
{
	vector<int> v = { 8,12,5,3,6,4,7,91,5,16,35,21,52,2,1 };
	QuickSort(v, 0, v.size() - 1);
	PrintArray(v, v.size());
	return 0;
}

排序结果
![在这里插入图片描述](https://img-blog.csdnimg.cn/a5636b9a6b024053b2ed668c7b897e73.png

1.2 挖坑法

挖坑法原理与Hoare法一致,不过相较于Hoare法更易理解它遵循着两个原则
1.先将第一个数据存放在临时变量key中。
2.左边是坑的话,右边先走找小,找到后与左坑值交换,右位变成坑位。
3.左边再找大值,交换循环。

初始状态
在这里插入图片描述

right找到第一个小于key的值5,然后将5给与坑所在位置,将right位置为坑
在这里插入图片描述

left开始找大
在这里插入图片描述

left找到第一个大于key的数7,与坑置换,并将left位置设为坑
在这里插入图片描述

多次置换后left==right时,坑的左边都是小于key的数,坑的右边都是大于key1的数,将key赋值于坑所在位置,单词排序成功,进入递归
在这里插入图片描述

2.挖坑法代码
void QuickSort(vector<int>& v, int begin, int end)
{
	if (begin >= end)
	{
		return;
	}
	int left = begin, right = end;
	int key = v[left], hole = left;
	while (left < right)
	{
		//找右值
		while (left < right && v[right] >= key)
		{
			--right;
		}
		//入坑,与坑的替换
		v[hole] = v[right];
		hole=right;
		while (left < right && v[left] <= key)
		{
			++left;
		}
		v[hole] = key;
		hole = left;
	}
	v[hole] = key;
	//进入递归,先递归左半部分小于key的区间,后递归右半部分大于key的区间
	QuickSort(v, begin, hole - 1);
	QuickSort(v, hole + 1, end);
}
int main()
{
	vector<int> v = { 8,12,5,3,6,4,7,91,5,16,35,21,52,2,1 };
	QuickSort(v, 0, v.size() - 1);
	PrintArray(v, v.size());
	return 0;
}

排序结果与Hoare相同

1.3 双指针法(更加便捷)

1.cur找比key小的,找到后停下。
2.prev++,prev与cur所在交换。

初始状态,这边我定义cur从第二个位置开始,当然它也可以从第一个位置开始,具体可以在程序中改进
在这里插入图片描述

当prev与cur相同时不进行交换,继续便利寻找可交换的数字找到第一组7/3,进行交换
在这里插入图片描述

找到第二组交换数据9/4,进行交换
在这里插入图片描述

多次交换后我们可以发现cur走到了最后的位置,此时,一次循环结束,当然不要忘记将初始设置的key与最后prev位置的数字进行交换。我们就可以得到以prev为分界线的左边小,右边大的两个数据区间,进行递归排序
在这里插入图片描述

结果
在这里插入图片描述

3.双指针法代码
void QuickSort(vector<int>& v, int begin, int end)
{
	if (begin > end)
	{
		return;
	}
	int prev = begin, cur = begin+1;
	int key = begin;
	while (cur <= end)
	{	
		//当prev与cur相等时交换的写法
		/*if (v[cur] < v[key])
		{
			prev++;
			Swap(v[prev], v[cur]);
		}*/
		//当prev与cur相等时直接跳过不交换的写法
		if (v[cur] < v[key] && ++prev != cur)
		{
			Swap(v[prev], v[cur]);
		}
		cur++;
	}
	Swap(v[prev], v[key]);
	key = prev;
	QuickSort(v, begin, key - 1);
	QuickSort(v, key + 1, end);
}
int main()
{
	vector<int> v = { 8,12,5,3,6,4,7,91,5,16,35,21,52,2,1 };
	QuickSort(v, 0, v.size() - 1);
	PrintArray(v, v.size());
	return 0;
}

1.4 三种方法时间复杂度计算

这里较难描述,我直接给出答案以及答案出现的情乱
快排的时间复杂度最理想下可达到O(n*logn)
当一组数据趋近于有序(逆序、正序)时,时间复杂度可达O(n * n)
这是为什么呢?

话不多说直接上图
在这里插入图片描述
这张图是不是和二叉树很像,当每次key都能选到,中间值时,它的时间复杂度就是n*logn。

在这里插入图片描述
而当所排数组趋近于有序数组时,就会出现如上图所示的情况,而我们又知道,进行递归时,CPU需要不停的进行栈帧的开辟,如果遇到趋近于有序的数组时,时间复杂度为O(n * n),我们得不到想要的有序数组,还会使编译器崩溃,那它怎么能叫快排的,徒有其表吗。
接下来要讲两种规避这种情况的优化方式。
1.三数取中
2.小区间优化

二、快排栈问题优化方式

2.1 三数取中

三数取中法选key,可以解决上述最坏情况有序(顺序、逆序)的问题。
有效避免因为深度遍历而开过多栈,引起的栈溢出问题。
思维图:

初始状态
在这里插入图片描述

mid为中值
在这里插入图片描述

end为中值
在这里插入图片描述

begin为中值
在这里插入图片描述

//中值判断函数
int GetMidIndex(vector<int>& v, int begin, int end)
{
	int mid = (begin + end) / 2;
	if (v[begin] < v[mid])
	{
		if (v[mid] < v[end])
		{
			return mid;
		}
		else if (v[begin] > v[end])
		{
			return begin;
		}
		else
		{
			return end;
		}
	}
	else // v[begin] > v[mid]
	{
		if (v[mid] > v[end])
		{
			return mid;
		}
		else if (v[begin] < v[end])
		{
			return begin;
		}
		else
		{
			return end;
		}
	}
}
//加入中止判断的快排
void QuickSort(vector<int>& v, int begin, int end)
{
	if (begin > end)
	{
		return;
	}
	//加入中值判断
	int mid = GetMidIndex(v, begin, end);
	Swap(v[begin], v[mid]);
	int prev = begin, cur = begin+1;
	int key = begin;
	while (cur <= end)
	{
		/*if (v[cur] < v[key])
		{
			prev++;
			Swap(v[prev], v[cur]);
		}*/
		if (v[cur] < v[key] && ++prev != cur)
		{
			Swap(v[prev], v[cur]);
		}
		cur++;
	}
	Swap(v[prev], v[key]);
	key = prev;
	QuickSort(v, begin, key - 1);
	QuickSort(v, key + 1, end);
}

2.2 小区间优化

小区间优化,字如其名,在进行递归排序时,会无限制的进行栈帧开辟,但是我们所用的内存空间的栈区往往最大就只有8M大小的空间,有概率会爆栈
经过多次排序后的数据在每个小区间会十分集中。
此时进行小区间的优化可以避免少开70%~90%的栈帧。
方法: 当小区间元素小于10/15时,使用直接插入排序进行排序。
思维图:

在所排数组非常大的情况下,如下图,会无线的开辟栈帧
在这里插入图片描述

适当的裁剪,换取更高的效率,减少百分之八十五左右的栈帧开辟
在这里插入图片描述

//直接插入排序
void InsertSort(vector<int>& v, int n)
{
	for (int i = 0; i < n - 1; ++i)
	{
		int end = i;
		int tmp = v[end + 1];
		while (end >= 0)
		{
			if (tmp < v[end])
			{
				v[end + 1] = v[end];
				--end;
			}
			else
			{
				break;
			}
		}
		v[end + 1] = tmp;
	}
}
//加入三数取中与小区间优化的快排
void QuickSort(vector<int>& v, int begin, int end)
{
	if (begin >= end)
	{
		return;
	}
	//小区间优化,防止递归深度过大,进行的剪枝行为,后使用直接插入排序进行小范围排序
	if (end - begin + 1 < 10)
	{
		InsertSort(v, end);
	}
	else
	{
		//三数取中
		int mid = GetMidIndex(v, begin, end);
		Swap(v[begin], v[mid]);
		int prev = begin, cur = begin + 1;
		int key = begin;
		while (cur <= end)
		{
			/*if (v[cur] < v[key])
			{
				prev++;
				Swap(v[prev], v[cur]);
			}*/
			if (v[cur] < v[key] && ++prev != cur)
			{
				Swap(v[prev], v[cur]);
			}
			cur++;
		}
		Swap(v[prev], v[key]);
		key = prev;
		QuickSort(v, begin, key - 1);
		QuickSort(v, key + 1, end);
	}
}

递归类快排,整体代码

#include <iostream>
#include <stack>
#include <vector>

using namespace std;

//交换
void Swap(int& a, int& b)
{
	int tmp = a;
	a = b;
	b = tmp;
}

//打印
void PrintArray(vector<int> v,int n)
{
	for (int i = 0; i < n; ++i)
	{
		cout << v[i] << " ";
	}
	printf("\n");
}

//三数取中
int GetMidIndex(vector<int>& v, int begin, int end)
{
	int mid = (begin + end) / 2;
	if (v[begin] < v[mid])
	{
		if (v[mid] < v[end])
		{
			return mid;
		}
		else if (v[begin] > v[end])
		{
			return begin;
		}
		else
		{
			return end;
		}
	}
	else // v[begin] > v[mid]
	{
		if (v[mid] > v[end])
		{
			return mid;
		}
		else if (v[begin] < v[end])
		{
			return begin;
		}
		else
		{
			return end;
		}
	}
}

//直接插入排序 O(n*n)
void InsertSort(vector<int>& v, int n)
{
	for (int i = 0; i < n - 1; ++i)
	{
		int end = i;
		int tmp = v[end + 1];
		while (end >= 0)
		{
			if (tmp < v[end])
			{
				v[end + 1] = v[end];
				--end;
			}
			else
			{
				break;
			}
		}
		v[end + 1] = tmp;
	}
}

//一、Hoare法
void QuickSort(vector<int>& v, int begin, int end)
{
	if (begin >= end)
	{
		return;
	}
	int key = begin;
	int left = begin, right = end;
	while (left < right)
	{
		while (right > left && v[right] >= v[key])
		{
			right--;
		}
		while (right > left && v[left] <= v[key])
		{
			left++;
		}
		Swap(v[left], v[right]);
	}
	Swap(v[key], v[left]);
	key = left;
	QuickSort(v, begin, key - 1);
	QuickSort(v, key + 1, end);
}
 
//二、挖坑法
//先将第一个数据存放在临时变量key中
//左边是坑的话,右边先走找小,找到后与左坑值交换,右位变成坑位
//左边再找大值,交换循环
void QuickSort(vector<int>& v, int begin, int end)
{
	if (begin >= end)
	{
		return;
	}
	int mid = GetMidIndex(v, begin, end);
	Swap(v[begin], v[mid]);
	int left = begin, right = end;
	int key = v[left];
	int hole = left;
	while (left < right)
	{
		while (left < right && v[right] >= key)
		{
			--right;
		}
		v[hole] = v[right];
		hole=right;
		while (left < right && v[left] <= key)
		{
			++left;
		}
		v[hole] = v[left];
		hole = left;
	}
	v[hole] = key;
	QuickSort(v, begin, hole - 1);
	QuickSort(v, hole + 1, end);
}
 
//三、前后指针法
//1.cur找比key小的,找到后停下
//2.prev++,prev与cur所在交换
void QuickSort(vector<int>& v, int begin, int end)
{
	if (begin > end)
	{
		return;
	}
	int prev = begin, cur = begin+1;
	int key = begin;
	while (cur <= end)
	{
		/*if (v[cur] < v[key])
		{
			prev++;
			Swap(v[prev], v[cur]);
		}*/
		if (v[cur] < v[key] && ++prev != cur)
		{
			Swap(v[prev], v[cur]);
		}
		cur++;
	}
	Swap(v[prev], v[key]);
	key = prev;
	QuickSort(v, begin, key - 1);
	QuickSort(v, key + 1, end);
}
//三数取中+小区间优化快排
void QuickSort(vector<int>& v, int begin, int end)
{
	if (begin >= end)
	{
		return;
	}
	//小区间优化,防止递归深度过大,进行的剪枝行为,后使用直接插入排序进行小范围排序
	if (end - begin + 1 < 10)
	{
		InsertSort(v, end);
	}
	else
	{
		//三数取中
		int mid = GetMidIndex(v, begin, end);
		Swap(v[begin], v[mid]);
		int prev = begin, cur = begin + 1;
		int key = begin;
		while (cur <= end)
		{
			/*if (v[cur] < v[key])
			{
				prev++;
				Swap(v[prev], v[cur]);
			}*/
			if (v[cur] < v[key] && ++prev != cur)
			{
				Swap(v[prev], v[cur]);
			}
			cur++;
		}
		Swap(v[prev], v[key]);
		key = prev;
		QuickSort(v, begin, key - 1);
		QuickSort(v, key + 1, end);
	}
}

int main()
{
	vector<int> v = { 8,12,5,3,6,4,7,91,5,16,35,21,52,2,1 };
	QuickSort(v, 0, v.size() - 1);
	PrintArray(v, v.size());
	return 0;
}

三、非递归快排

非递归快排借助进行操作,是一种分治思维的延申。
因为栈的出入规则是先进后出。
我们要对排序区间进行划分,每次的出栈、入栈操作就是递归中处理数据、子区间划分操作。

原理图:

在这里插入图片描述
程序:

//非递归快排
void QuickSortNonr(vector<int>& v, int begin, int end)
{
	//自定义栈为ST,定义栈st,并初始化栈,将头尾位置压入栈
	//成功压入后我们得到需要的排序空间的头和尾
	//依次进行出栈入栈,重新定义排序区间,模拟递归排序
	ST st;
	StackInit(&st);
	StackPush(&st, begin);
	StackPush(&st, end);

	while (!StackEmpty(&st))
	{
		int right = StackTop(&st);
		StackPop(&st);
		int left = StackTop(&st);
		StackPop(&st);
		//调用单次快排,单次排序
		int key = QuickSort(a, left, right);
		// [left, keyi-1] keyi [keyi+1, right]
		if (key + 1 < right)
		{
			//进行右区间入栈操作,进入模拟递归进入操作
			StackPush(&st, key + 1);
			StackPush(&st, right);
		}

		if (left < key - 1)
		{
			//进行左区间入栈操作,进入模拟递归进入操作
			StackPush(&st, left);
			StackPush(&st, key - 1);
		}
	}
	//排序完毕销毁
	StackDestroy(&st);
}

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

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

相关文章

生活污水处理设备选购指南

生活污水中含有大量的有机物&#xff08;如蛋白质、碳水化合物、脂肪、尿素、氨氮等&#xff09;及大量的病原微生物&#xff0c;可导致传染病蔓延流行。因此&#xff0c;生活污水在排放前&#xff0c;需要进行处理。那么如何正确的选择生活污水处理设备呢&#xff1f; 一、生活…

移动机器人设计与实践-基础概念汇总

如下全文在关键词提示词等脚本交互下&#xff0c;由文图版本生成式人工智能在1分钟内创作完成。 AI自动生成文章评分已经远超大部分博文评分值。 人类社会经历过农业时代&#xff08;最强代表汉唐&#xff09;-工业时代&#xff08;最强代表日不落帝国&#xff09;-信息时代&a…

利用MyBatis实现CRUD操作

文章目录一、添加按姓名查询用户记录功能1、添加按姓名查询的映射语句2、在用户映射器接口里添加按姓名查询用户记录的方法3、添加按姓名查询用户记录的测试方法4、测试按姓名查询用户记录二、插入表记录1、在UserMapper.xml里增加映射语句 - insert2、在UserMapper接口里增加i…

【三十天精通Vue 3】第七天 Vue 3 响应式系统详解

✅创作者&#xff1a;陈书予 &#x1f389;个人主页&#xff1a;陈书予的个人主页 &#x1f341;陈书予的个人社区&#xff0c;欢迎你的加入: 陈书予的社区 &#x1f31f;专栏地址: 三十天精通 Vue 3 文章目录引言一、Vue 3 响应式系统概述1.1 响应式系统的简介1.2 响应式系统…

【软件设计师14】UML建模

UML建模 稳定出一个&#xff0c;但是由于UML的图比较多&#xff0c;所以这种题比数据流图和数据库难度高 一般都会考用例图和类图&#xff0c;再附加其他的图 1. 用例图 包含关系include&#xff1a;比如登记外借信息必须先有用户登录 扩展关系extend&#xff1a;修改书籍…

C语言--文件操作--一起深入了解文件相关函数的知识

目录前言1.什么是文件1.1程序文件1.2数据文件1.3文件名2.文件的打开与关闭2.1文件指针2.2文件的打开与关闭fopen函数fclose函数3.文件的顺序读写3.1对比一组函数fputc函数fgetc函数fputs函数fgets函数fprintf函数fscanf函数fwrite函数fread函数4.1对比一组函数sprintfsscanf5.文…

ClickUp的最佳替代品,可更好地管理项目

ClickUp 是项目管理类的常见工具&#xff0c;它因团队协作、沟通、免费试用和强大功能等因素受到用户的喜爱。 该工具支持你清晰组织多个项目、进行团队协作并跟踪项目目标的实时进度。不同的视图选项使您能够为所有活动构建完美的工作流程。 尽管它很受欢迎&#xff0c;但用户…

ics-05(命令执行漏洞及伪协议读取)

打开链接&#xff0c;似曾相识的感觉&#xff08;前面做过一道题叫ics-06&#xff0c;那道题是对id的一个爆破&#xff09; 尝试后发现只有设备维护中心可以跳转 这和我们使用御剑扫描出来的结果是一样的 使用PHP伪协议读取 index.php 页面 构造payload&#xff08;在愚人杯ht…

小黑跟尚香一起疯狂星期四,然后慢慢跑回家,生活逐渐明朗,完赛了副中心全程马拉松的leetcode之旅:752. 打开转盘锁

宽度优先搜索法 class Solution:def openLock(self, deadends: List[str], target: str) -> int:# 目的地在死亡数组里if target in deadends:return -1# 起点在死亡数字里if 0000 in deadends:return -1# 起点就是目标字符串if 0000 target:return 0# 定义前向函数def pr…

Python与c语言的区别与联系

Python与c语言都是一种机器学习语言&#xff0c;进过长时间的学习和总结&#xff0c;我将Python与c语言的一些特点总结成以下几点&#xff0c;不全面还望多多指正。 1、因为C语言是编译型语言&#xff0c;python是解释型语言&#xff0c;所以python的执行速度没有C语言那么快。…

回归预测 | MATLAB实现GA-GRU遗传算法优化门控循环单元的数据多输入单输出回归预测

回归预测 | MATLAB实现GA-GRU遗传算法优化门控循环单元的数据多输入单输出回归预测 目录回归预测 | MATLAB实现GA-GRU遗传算法优化门控循环单元的数据多输入单输出回归预测效果一览基本介绍程序设计参考资料效果一览 基本介绍 MATLAB实现GA-GRU遗传算法优化门控循环单元的数据多…

详解Nginx代理WordPress搭建个人网站系统

1、搭建环境说明 服务器&#xff1a;Red Hat Enterprise Linux Server release 7.9 (Maipo) PHP&#xff1a;php-8.2.4 PHP: Downloads Nginx: 1.24.0 http://nginx.org/en/download.html WordPress:6.2 Download – WordPress.org Mysql&#xff1a;5.7.22 MySQL Communit…

【Java EE】-网络编程(一) 网络初识

作者&#xff1a;学Java的冬瓜 博客主页&#xff1a;☀冬瓜的主页&#x1f319; 专栏&#xff1a;【JavaEE】 主要内容&#xff1a;单机、局域网、广域网、交换机、路由器。IP地址&#xff0c;端口号&#xff0c;协议&#xff0c;五元组。 协议分层&#xff0c;OSI七层网络模型…

【开源项目】SpringBoot实现接口加密解密

需求背景 在我们日常的Java开发中&#xff0c;免不了和其他系统的业务交互&#xff0c;或者微服务之间的接口调用 如果我们想保证数据传输的安全&#xff0c;对接口出参加密&#xff0c;入参解密。 但是不想写重复代码&#xff0c;我们可以提供一个通用starter&#xff0c;提…

数据结构系列17——lambda表达式

目录 1. 基本概念 2. 基本语法 3. 函数式接口 4. Lambda表达式的基本使用 4.1 语法精简 5. 变量捕获 6. Lambda在集合当中的使用 1. 基本概念 Lambda表达式是Java SE 8中一个重要的新特性。lambda表达式允许你通过表达式来代替功能接口。 lambda表达式就和方法一样,它提供了一…

再聊ChatGPT(关于安全,隐私和法律方面的风险)

我在上一篇博文中有谈到ChatGPT 发展可能会经历的一些阶段。ChatGPT的必经阶段&#xff1a;野蛮生长时代-管理层监管与风险提示-号召国产化-规范化常态化。 昨天刚好看到监管部门发文 说明监管部门已经意识到到ChatGPT野蛮生长阶段&#xff0c;其实是存在很多漏洞和问题的。 …

2022年 全国职业院校技能大赛(中职组)网络安全赛项 正式赛卷 A模块 做题记录

评分标准文件及环境 评分标准&#xff1a;ZZ-2022029 网络安全赛项正式赛卷.zip 自己做的Linux靶机&#xff1a; 自己做的Windows靶机&#xff1a; 文章目录评分标准文件及环境A-1 任务一 登录安全加固1. 密码策略&#xff08;Windows&#xff0c;Linux&#xff09;a. 最小密码…

年少不知回损好,却把插损当作宝

一博高速先生成员&#xff1a;黄刚 因为本期要讲的是插损和回损的关系&#xff0c;因此本文的开头&#xff0c;我们还是首先回顾下S参数的概念。首先我们需要知道S参数其实是个黑匣子&#xff0c;什么是黑匣子呢&#xff0c;那就是我们其实不需要知道它包含了哪些链路结构&…

steam游戏搬砖项目怎么做?月入过万的steam搬砖项目教程拆解

steam游戏搬砖项目怎么做?月入过万的steam搬砖项目教程拆解 大家好&#xff0c;我是童话姐姐&#xff0c;今天继续来聊Steam搬砖项目。 Steam搬砖项目也叫CSGO搬砖项目&#xff0c;它并不是什么刚面世的新项目&#xff0c;是已经存在至少七八年的一个资深老牌项目。这个项目…

QT4与QT5兼容问题

QT4 与QT5 兼容&#xff0c;源码差异部分通过QT_VERSION 宏来区分 常见区别 widgets prinsupport charts 等模块一如方式&#xff0c;Qt5 将QtWidgets QtPrintsupport 模块从QtGui 中分离出来&#xff0c;QT4 中没有qjson4 和 charts 模块&#xff0c;需要特殊处理 在pro文件…