爆款云主机2核4G限时秒杀,88元/年起!
查看详情

活动

天翼云最新优惠活动,涵盖免费试用,产品折扣等,助您降本增效!
热门活动
  • 618智算钜惠季 爆款云主机2核4G限时秒杀,88元/年起!
  • 免费体验DeepSeek,上天翼云息壤 NEW 新老用户均可免费体验2500万Tokens,限时两周
  • 云上钜惠 HOT 爆款云主机全场特惠,更有万元锦鲤券等你来领!
  • 算力套餐 HOT 让算力触手可及
  • 天翼云脑AOne NEW 连接、保护、办公,All-in-One!
  • 中小企业应用上云专场 产品组合下单即享折上9折起,助力企业快速上云
  • 息壤高校钜惠活动 NEW 天翼云息壤杯高校AI大赛,数款产品享受线上订购超值特惠
  • 天翼云电脑专场 HOT 移动办公新选择,爆款4核8G畅享1年3.5折起,快来抢购!
  • 天翼云奖励推广计划 加入成为云推官,推荐新用户注册下单得现金奖励
免费活动
  • 免费试用中心 HOT 多款云产品免费试用,快来开启云上之旅
  • 天翼云用户体验官 NEW 您的洞察,重塑科技边界

智算服务

打造统一的产品能力,实现算网调度、训练推理、技术架构、资源管理一体化智算服务
智算云(DeepSeek专区)
科研助手
  • 算力商城
  • 应用商城
  • 开发机
  • 并行计算
算力互联调度平台
  • 应用市场
  • 算力市场
  • 算力调度推荐
一站式智算服务平台
  • 模型广场
  • 体验中心
  • 服务接入
智算一体机
  • 智算一体机
大模型
  • DeepSeek-R1-昇腾版(671B)
  • DeepSeek-R1-英伟达版(671B)
  • DeepSeek-V3-昇腾版(671B)
  • DeepSeek-R1-Distill-Llama-70B
  • DeepSeek-R1-Distill-Qwen-32B
  • Qwen2-72B-Instruct
  • StableDiffusion-V2.1
  • TeleChat-12B

应用商城

天翼云精选行业优秀合作伙伴及千余款商品,提供一站式云上应用服务
进入甄选商城进入云市场创新解决方案
办公协同
  • WPS云文档
  • 安全邮箱
  • EMM手机管家
  • 智能商业平台
财务管理
  • 工资条
  • 税务风控云
企业应用
  • 翼信息化运维服务
  • 翼视频云归档解决方案
工业能源
  • 智慧工厂_生产流程管理解决方案
  • 智慧工地
建站工具
  • SSL证书
  • 新域名服务
网络工具
  • 翼云加速
灾备迁移
  • 云管家2.0
  • 翼备份
资源管理
  • 全栈混合云敏捷版(软件)
  • 全栈混合云敏捷版(一体机)
行业应用
  • 翼电子教室
  • 翼智慧显示一体化解决方案

合作伙伴

天翼云携手合作伙伴,共创云上生态,合作共赢
天翼云生态合作中心
  • 天翼云生态合作中心
天翼云渠道合作伙伴
  • 天翼云代理渠道合作伙伴
天翼云服务合作伙伴
  • 天翼云集成商交付能力认证
天翼云应用合作伙伴
  • 天翼云云市场合作伙伴
  • 天翼云甄选商城合作伙伴
天翼云技术合作伙伴
  • 天翼云OpenAPI中心
  • 天翼云EasyCoding平台
天翼云培训认证
  • 天翼云学堂
  • 天翼云市场商学院
天翼云合作计划
  • 云汇计划
天翼云东升计划
  • 适配中心
  • 东升计划
  • 适配互认证

开发者

开发者相关功能入口汇聚
技术社区
  • 专栏文章
  • 互动问答
  • 技术视频
资源与工具
  • OpenAPI中心
开放能力
  • EasyCoding敏捷开发平台
培训与认证
  • 天翼云学堂
  • 天翼云认证
魔乐社区
  • 魔乐社区

支持与服务

为您提供全方位支持与服务,全流程技术保障,助您轻松上云,安全无忧
文档与工具
  • 文档中心
  • 新手上云
  • 自助服务
  • OpenAPI中心
定价
  • 价格计算器
  • 定价策略
基础服务
  • 售前咨询
  • 在线支持
  • 在线支持
  • 工单服务
  • 建议与反馈
  • 用户体验官
  • 服务保障
  • 客户公告
  • 会员中心
增值服务
  • 红心服务
  • 首保服务
  • 客户支持计划
  • 专家技术服务
  • 备案管家

了解天翼云

天翼云秉承央企使命,致力于成为数字经济主力军,投身科技强国伟大事业,为用户提供安全、普惠云服务
品牌介绍
  • 关于天翼云
  • 智算云
  • 天翼云4.0
  • 新闻资讯
  • 天翼云APP
基础设施
  • 全球基础设施
  • 信任中心
最佳实践
  • 精选案例
  • 超级探访
  • 云杂志
  • 分析师和白皮书
  • 天翼云·创新直播间
市场活动
  • 2025智能云生态大会
  • 2024智算云生态大会
  • 2023云生态大会
  • 2022云生态大会
  • 天翼云中国行
天翼云
  • 活动
  • 智算服务
  • 产品
  • 解决方案
  • 应用商城
  • 合作伙伴
  • 开发者
  • 支持与服务
  • 了解天翼云
      • 文档
      • 控制中心
      • 备案
      • 管理中心

      DS初阶:八大排序之归并排序、计数排序

      首页 知识中心 其他 文章详情页

      DS初阶:八大排序之归并排序、计数排序

      2025-05-09 08:20:32 阅读次数:5

      复杂度,序列,归并,排序,数组,递归

      一、归并排序

      1.1 思想

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

       DS初阶:八大排序之归并排序、计数排序

      还有一个关键点就是:归并一定要先拷贝到一个新数组里面,再拷贝到原数组!! 

      1.2 递归实现归并排序

      根据上面的思路,我们来实现代码:

      void _MergeSort(int* a, int begin, int end, int* temp)
      {
      	if (begin == end)
      		return;//设置递归返回条件
      	int mid = (begin + end) / 2;
      	//开始分解
      	_MergeSort(a, begin, mid, temp);//左区间归并
      	_MergeSort(a, mid+1, end, temp);//右区间归并
      	//开始进行总归并
      	int begin1 = begin, end1 = mid;//设置指针指向左区间
      	int begin2 = mid + 1, end2 = end;//设置指针指向右区间
      	int i = begin;//用来遍历拷贝数组
      	while (begin1 <= end1 && begin2 <= end2)//只要有一个先拷贝完,就跳出循环
      	{
      		//谁小谁尾插
      		if (a[begin1] < a[begin2])
      			temp[i++] = a[begin1++];
      		else
      			temp[i++] = a[begin2++];
      	}
      	//这个时候其中一个区间先遍历完了,这个时候另一个没有遍历的区间插入就可以了
      	//以下两个while只会执行一个
      	while (begin1 <= end1)
      		temp[i++] = a[begin1++];
      	while (begin2<=end2)
      		temp[i++] = a[begin2++];
      	//归并完成,将temp的数据拷贝回去
      	memcpy(a + begin, temp + begin, sizeof(int) * (end - begin + 1));//因为递归,拷贝的不一定就是从头开始的,左闭右闭个数要+1;
      }
      void MergeSort(int* a, int n)
      {
      	int* temp = (int*)malloc(sizeof(int) * n);
      	if (temp == NULL)
      	{
      		perror("malloc fail");
      		exit(1);
      	}
      	//开辟成功,开始进行递归
      	_MergeSort(a, 0, n - 1, temp);
      }

      要注意:递归的返回条件是begin==end!!因此归并排序每次拆分都是从中间拆分的,所以不可能会出现区间不存在的情况!! 只有可能是区间只有一个元素的情况

      1.3 非递归实现归并排序

      怎么去思考非递归实现归并排序呢??我们来画图理解:

      DS初阶:八大排序之归并排序、计数排序

      那我们其实可以通过指针来实现各个子区间的有序,直接在原数组上建立两个指针

      我们设置一个gap来分割区间

      DS初阶:八大排序之归并排序、计数排序

      这里的问题就是,如何控制每次归并的子序列的范围?以及什么时候结束归并?

      一、gap 控制几个为一组归并(gap一开始从1开始),则:

      第一个子序列的起始是begin1 = i, end1 = i + gap -1;

      第二个子序列的起始是begin2 = i+gap, end2 = i + 2 *gap - 1;

      其中i是遍历一遍待排序的数组的下标,i从0开始。i每次应该跳2*gap步。

      二、gap控制的是每次几个为一组我们 一开始是1个,2个、4个、8个,显然是2的倍数,所以gap每次乘等2即可!也不能一直让gap*=2下去,gap不可能大于等于数组的长度,所以当超过数组的长度是结束!

      代码实现:

      void MergeSortNonR(int* a, int n)
      {
      	int* temp = (int*)malloc(sizeof(int) * n);
      	if (temp == NULL)
      	{
      		perror("malloc fail");
      		exit(1);
      	}
      	//开辟成功
      	int gap = 1;
      	while (gap < n)
      	{
      		int j = 0;//用来遍历拷贝数组
      		for (int i = 0; i < n; i += 2 * gap)
      		{
      			int begin1 = i, end1 = i + gap - 1;
      			int begin2 = i + gap, end2 = i + 2 * gap - 1;
      			while (begin1 <= end1 && begin2 <= end2)//只要有一个先拷贝完,就跳出循环
      			{
      				//谁小谁尾插
      				if (a[begin1] < a[begin2])
      					temp[j++] = a[begin1++];
      				else
      					temp[j++] = a[begin2++];
      			}
      			//这个时候其中一个区间先遍历完了,这个时候另一个没有遍历的区间插入就可以了
      			//以下两个while只会执行一个
      			while (begin1 <= end1)
      				temp[j++] = a[begin1++];
      			while (begin2 <= end2)
      				temp[j++] = a[begin2++];
      			//归并完成,将temp的数据拷贝回去
      		}
      		memcpy(a, temp, sizeof(int) * n);//一起拷贝回去
      		gap *= 2;//设置条件
      	}
      }

      这样对吗?测试一下

      DS初阶:八大排序之归并排序、计数排序 如果我们将数加到10个呢??

      DS初阶:八大排序之归并排序、计数排序

      越界了!!因为我们之前那个情况是8个元素恰好是2的次方,所以无论怎么分割再归并,都不会越界,所以这个时候我们要考虑边界情况!! 

      DS初阶:八大排序之归并排序、计数排序

      修正版本1:

      void MergeSortNonR(int* a, int n)
      {
      	int* temp = (int*)malloc(sizeof(int) * n);
      	if (temp == NULL)
      	{
      		perror("malloc fail");
      		exit(1);
      	}
      	//开辟成功
      	int gap = 1;
      	while (gap < n)
      	{
      		int j = 0;//用来遍历拷贝数组
      		for (int i = 0; i < n; i += 2 * gap)
      		{
      			int begin1 = i, end1 = i + gap - 1;
      			int begin2 = i + gap, end2 = i + 2 * gap - 1;
      			if (end1 >= n || begin2 >= n)
      				break;
      			if (end2 >= n)//修正
      				end2 = n - 1;
      			while (begin1 <= end1 && begin2 <= end2)//只要有一个先拷贝完,就跳出循环
      			{
      				//谁小谁尾插
      				if (a[begin1] <= a[begin2])
      					temp[j++] = a[begin1++];
      				else
      					temp[j++] = a[begin2++];
      			}
      			//这个时候其中一个区间先遍历完了,这个时候另一个没有遍历的区间插入就可以了
      			//以下两个while只会执行一个
      			while (begin1 <= end1)
      				temp[j++] = a[begin1++];
      			while (begin2 <= end2)
      				temp[j++] = a[begin2++];
      			//归并一次,拷贝一次
      			memcpy(a + i, temp + i, sizeof(int) * (end2-i+1));//一起拷贝回去
      		}
      		gap *= 2;//设置条件
      	}
      }
      

      修改版本2:

      void MergeSortNonR2(int* a, int n)
      {
      	int* temp = (int*)malloc(sizeof(int) * n);
      	if (temp == NULL)
      	{
      		perror("malloc fail");
      		exit(1);
      	}
      	//开辟成功
      	int gap = 1;
      	while (gap < n)
      	{
      		int j = 0;//用来遍历拷贝数组
      		for (int i = 0; i < n; i += 2 * gap)
      		{
      			int begin1 = i, end1 = i + gap - 1;
      			int begin2 = i + gap, end2 = i + 2 * gap - 1;
      			if (end1 >= n)
      			{
      				end1 = n - 1;//修正end1
      				//然后为了让begin2和end2不走循环,直接让他们区间不存在
      				begin2 = n;
      				end2 = n - 1;
      			}
      			else if (begin2 >= n)
      			{
      				//不存在区间
      				begin2 = n;
      				end2 = n - 1;
      			}
      			else if (end2 >= n)
      			{	//修正end2
      				end2 = n - 1;
      			}
      			while (begin1 <= end1 && begin2 <= end2)//只要有一个先拷贝完,就跳出循环
      			{
      				//谁小谁尾插
      				if (a[begin1] <= a[begin2])
      					temp[j++] = a[begin1++];
      				else
      					temp[j++] = a[begin2++];
      			}
      			//这个时候其中一个区间先遍历完了,这个时候另一个没有遍历的区间插入就可以了
      			//以下两个while只会执行一个
      			while (begin1 <= end1)
      				temp[j++] = a[begin1++];
      			while (begin2 <= end2)
      				temp[j++] = a[begin2++];
      		}
      		gap *= 2;//设置条件
      		memcpy(a, temp, sizeof(int) * n);
      	}
      }

      1.4 归并排序的优化

      假设我们的数据非常大,比如100万个数据,一开始的拆分效率是很高的,但是当数据变得很少的时候比如8个,这个时候再继续拆,效率其实很低的

      DS初阶:八大排序之归并排序、计数排序

      我们当递归只剩大概10个元素的时候,停止递归,使用直接插入排序

      void _MergeSort(int* a, int begin, int end, int* temp)
      {
      	if (begin == end)
      		return;//设置递归返回条件
      	if (end - begin + 1 < 10)
      	{
      		InsertSort(a+begin, end - begin + 1);//优化
      		return;
      	}
      	int mid = (begin + end) / 2;
      	//开始分解
      	_MergeSort(a, begin, mid, temp);//左区间归并
      	_MergeSort(a, mid+1, end, temp);//右区间归并
      	//开始进行总归并
      	int begin1 = begin, end1 = mid;//设置指针指向左区间
      	int begin2 = mid + 1, end2 = end;//设置指针指向右区间
      	int i = begin;//用来遍历拷贝数组
      	while (begin1 <= end1 && begin2 <= end2)//只要有一个先拷贝完,就跳出循环
      	{
      		//谁小谁尾插
      		if (a[begin1] < a[begin2])
      			temp[i++] = a[begin1++];
      		else
      			temp[i++] = a[begin2++];
      	}
      	//这个时候其中一个区间先遍历完了,这个时候另一个没有遍历的区间插入就可以了
      	//以下两个while只会执行一个
      	while (begin1 <= end1)
      		temp[i++] = a[begin1++];
      	while (begin2<=end2)
      		temp[i++] = a[begin2++];
      	//归并完成,将temp的数据拷贝回去
      	memcpy(a + begin, temp + begin, sizeof(int) * (end - begin + 1));//因为递归,拷贝的不一定就是从头开始的,左闭右闭个数要+1;
      }
      void MergeSort(int* a, int n)
      {
      	int* temp = (int*)malloc(sizeof(int) * n);
      	if (temp == NULL)
      	{
      		perror("malloc fail");
      		exit(1);
      	}
      	//开辟成功,开始进行递归
      	_MergeSort(a, 0, n - 1, temp);
      }
      

      1.5 复杂度分析

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

      他像二叉树的后序遍历,高度是logN,每一层合计归并时O(N)遍历一遍数组

      空间复杂度:O(N)

      N为辅助数组的长度,和原数组的长度一样!

      二、计数排序

      2.1 思想

      思想:计数排序又称为鸽巢原理,是对哈希直接定址法的变形应用,是一种非比较排序!

      步骤:

      1、统计相同元素的出现次数

      2、根据统计的结果将序列回收到原来的序列中 

      2.2 计数排序的实现

      DS初阶:八大排序之归并排序、计数排序

      代码实现:

      void CountSort(int* a, int n)
      {
      	int min = a[0], max = a[0];//根据最值来确定范围
      	//遍历原数组找范围
      	for (int i = 0; i < n; i++)
      	{
      		if (a[i] < min)
      			min = a[i];
      		if (a[i] > max)
      			max = a[i];
      	}
      	//确定新数组的构建范围
      	int range = max - min + 1;
      	int* temp = (int*)calloc(range, sizeof(int));//因为要初始化0,所以用calloc
      	//也可以先用malloc,然后用memset(temp,0,sizeof(int)*range)
      	if (temp == NULL)
      	{
      		perror("calloc fail");
      		exit(1);
      	}
      	//开辟成功后,开始遍历原数组计数
      	for (int i = 0; i < n; i++)
      		temp[a[i] - min]++;
      	//遍历完后,计数也完成了,开始遍历计数数组,恢复原数组
      	int k = 0;//用来恢复原数组
      	for (int j = 0; j < range; j++)
      		while (temp[j]--)//一直减到0,就会跳下一层循环,直到遍历完!!
      			a[k++] = j + min;
      }

      2.3 复杂度分析

      时间复杂度:O(MAX(N,范围))
      空间复杂度:O(范围)

      2.4 计数排序的缺陷

      1,只适合范围相对集中的数据

      2、只适用与整型,因为只有整型才能和下标建立联系

      三、内排序和外排序

      DS初阶:八大排序之归并排序、计数排序

      四、稳定性 

      DS初阶:八大排序之归并排序、计数排序

      五、八大排序对比

      4.1 代码实现测速度

      void TestOP()//测试速度
      {
      	srand((unsigned int)time(NULL));
      	const int N = 10000;
      	int* a1 = (int*)malloc(sizeof(int) * N);
      	int* a2 = (int*)malloc(sizeof(int) * N);
      	int* a3 = (int*)malloc(sizeof(int) * N);
      	int* a4 = (int*)malloc(sizeof(int) * N);
      	int* a5 = (int*)malloc(sizeof(int) * N);
      	int* a6 = (int*)malloc(sizeof(int) * N);
      	int* a7 = (int*)malloc(sizeof(int) * N);
      	int* a8 = (int*)malloc(sizeof(int) * N);
      
      
      	for (int i = 0; i < N; ++i)
      	{
      		a1[i] = rand();
      		a2[i] = a1[i];
      		a3[i] = a1[i];
      		a4[i] = a1[i];
      		a5[i] = a1[i];
      		a6[i] = a1[i];
      		a7[i] = a1[i];
      		a8[i] = a1[i];
      
      	}
      	//clock计入程序走到当前位置的时间
      	int begin1 = clock();
      	InsertSort(a1, N);
      	int end1 = clock();
      
      	int begin2 = clock();
      	ShellSort(a2, N);
      	int end2 = clock();
      
      	int begin3 = clock();
      	SelectSort(a3, N); 
      	int end3 = clock();
      
      	int begin4 = clock();
      	BubbleSort(a4, N); 
      	int end4 = clock();
      
      	int begin5 = clock();
      	HeapSort(a5, N);
      	int end5 = clock();
      
      	int begin6 = clock();
      	QuickSort(a6, 0, N - 1);
      	int end6 = clock();
      
      	int begin7 = clock();
      	MergeSort(a7, N);
      	int end7 = clock();
      
      	int begin8 = clock();
      	CountSort(a8, N);
      	int end8 = clock();
      
      	printf("InsertSort:%d\n", end1 - begin1);
      	printf("ShellSort:%d\n", end2 - begin2);
      	printf("SelectSort:%d\n", end3 - begin3);
      	printf("BubbleSort:%d\n", end4 - begin4);
      	printf("HeapSort:%d\n", end5 - begin5);
      	printf("QuickSort:%d\n", end6 - begin6);
      	printf("MergeSort:%d\n", end7 - begin7);
      	printf("CountSort:%d\n", end8 - begin8);
      
      	free(a1);
      	free(a2);
      	free(a3);
      	free(a4);
      	free(a5);
      	free(a6);
      	free(a7);
      	free(a8);
      
      }
      
      int main()
      {
      	TestOP();
      }

       测试一下:

      N=10000

      DS初阶:八大排序之归并排序、计数排序

      N=100000

      DS初阶:八大排序之归并排序、计数排序 DS初阶:八大排序之归并排序、计数排序

       我们发现:

      希尔排序、堆排序、快排、归并排、计数牌是一个量级的

      N=10000000

      DS初阶:八大排序之归并排序、计数排序

      直接插入排、选择排序、冒泡排序是一个量级的

      4.2 复杂度稳定性比较

      DS初阶:八大排序之归并排序、计数排序

      六、八大排序全部代码

      建议大家把博主的有关八大排序的代码都看一下

      主要是前三个文件,后面四个文件是为了快排的栈实现和队列实现准备的!!

      6.1 sort.h

      #pragma once
      #include<stdio.h>
      #include<stdlib.h>
      #include<string.h>
      #include<time.h>
      void ArrPrint(int* a, int n);//用来打印结果
      void Swap(int* p1, int* p2);//进行交换
      
      
      
      void InsertSort(int* a, int n);//直接插入排序
      
      void ShellSort(int* a, int n);//希尔排序
      
      void SelectSort(int* a, int n);//选择排序
      
      void AdjustDown(int* a, int n, int parent);//向下调整算法
      void HeapSort(int* a, int n);//堆排序
      
      void BubbleSort(int* a, int n);//冒泡排序
      
      int GetMidIndex(int* a, int left, int right);//快排优化——三数取中
      int GetMidIndex2(int* a, int left, int right);//三数取中再优化
      int PartSort1(int* a, int left, int right);//hoare基准排序
      int PartSort2(int* a, int left, int right);//挖坑基准排序
      int PartSort3(int* a, int left, int right);//前后指针基准排序
      void QuickSort(int* a, int left, int right);//递归快排
      void QuickSort2(int* a, int left, int right);//三路归并快排
      void QuickSortNonR1(int* a, int left, int right);//栈实现非递归快排
      void QuickSortNonR2(int* a, int left, int right);//队列实现非递归快排
      
      void HeapSort(int* a, int n);//堆排序
      
      void BubbleSort(int* a, int n);//冒泡排序
      
      
      void _MergeSort(int* a, int begin, int end,int *temp);//归并排序的子函数(用来递归)
      void MergeSort(int* a, int n);//归并排序
      void MergeSortNonR(int* a, int n);//归并排序非递归
      void MergeSortNonR2(int* a, int n);//归并排序非递归版本2
      
      
      void CountSort(int* a, int n);//计数排序

      6.2 sort.c

      #include"Sort.h"
      #include"Stack.h"
      #include"Queue.h"
      void ArrPrint(int* a, int n)
      {
      	for (int i = 0; i < n; i++)
      		printf("%d ", a[i]);
      }
      void Swap(int* p1, int* p2)
      {
      	int temp = *p1;
      	*p1 = *p2;
      	*p2 = temp;
      }
      
      
      
      void InsertSort(int* a, int n)
      {
      	for (int i = 0; i < n - 1; i++)
      	{
      		int end = i;
      		int temp = a[i+1];
      		while (end >= 0)
      		{
      			if (a[end] > temp)//如果前面的数比后面的数大,就前面元素插入到后面的位置
      				a[end + 1] = a[end];
      			else
      				break;
      			--end;
      		}
      		a[end + 1] = temp;//不写在循环里面,是避免end减成-1,此时说明新加入的牌是最小的,正好放在一开始的位置
      	}
      }
      
      
      void ShellSort(int* a, int n)
      {
      	//gap>1  预排序
      	//gap=1 直接插入排序
      	int gap = n;
      	while (gap > 1)
      	{
      		gap = gap / 3 + 1;//这是为了保证gap最后一定为1
      		for (int i = 0; i < n - gap; i++)
      		{
      			int end = i;
      			int temp = a[i + gap];
      			while (end >= 0)
      			{
      				if (a[end] > temp)//如果前面的数比后面的数大,就前面元素插入到后面的位置
      					a[end + gap] = a[end];
      				else
      					break;
      				end -= gap;
      			}
      			a[end + gap] = temp;
      		}
      	}
      }
      //
      void SelectSort(int* a, int n)
      {
      	int left = 0; 
      	int right = n - 1;
      	while (left < right)
      	{
      		int min = left;
      		int max = left;
      		for (int i = left+1; i <= right; i++)
      		{
      		
      			if (a[min] > a[i])
      			    min = i;
      		    if (a[max] < a[i])
      				max = i;
      		}
      		//这里要考虑一种情况,就是如果最大的数恰好就在最左端,那么就会导致第二次swap换到后面的就不是最大的数而是最小的数了
      		Swap(&a[min], &a[left]);
      		//如果max和begin重叠,修正一下
      		if (max == left)
      			max = min;
      		Swap(&a[max], &a[right]);
      		left++;
      		right--;
      	}
      }
      
      int GetMidIndex(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[right] < a[left])
      			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;
      	}
      }
      
      int GetMidIndex2(int* a, int left, int right)
      {
      	int mid = left + (rand() % (right - left));
      	if (a[left] < a[mid])
      	{
      		if (a[mid] < a[right])
      			return mid;
      		else if (a[right] < a[left])
      			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;
      	}
      }
      
      
      int PartSort1(int* a, int left, int right)//hoare基准排序
      {
      	int mid=GetMidIndex(a, left, right);
      	Swap(&a[mid], &a[left]);
      	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]);
      	}
      	//此时相遇了,把相遇的位置和keyi的位置交换
      	Swap(&a[left], &a[keyi]);
      	return left;
      }
      
      int PartSort2(int* a, int left, int right)//挖坑基准排序
      {
      	int mid = GetMidIndex(a, left, right);
      	Swap(&a[mid], &a[left]);
      	int key = a[left];//记住key的值
      	int hole = left;//开始挖坑
      	while (left < right)
      	{
      		//右先找比key大的
      		while (left < right && a[right] >= key)
      			right--;
      		//找到后,填坑,然后挖新坑
      		a[hole] = a[right];
      		hole = right;
      		//左找比key小的
      		while (left < right && a[left] <= key)
      			left++;
      		//找到后,填坑,然后挖新坑
      		a[hole] = a[left];
      		hole = left;
      	}
      	//此时相遇了,把key值放在坑里
      	a[hole] = key;
      	return hole;
      }
      
      int PartSort3(int* a, int left, int right) //前后指针基准排序
      {
      	int mid = GetMidIndex(a, left, right);
      	Swap(&a[mid], &a[left]);
      	int prev = left;
      	int cur = left + 1;
      	int keyi = left;
      	while (cur <= right)//cur走出数组循环停止
      	{
      		//cur一直在走,如果遇到比keyi小的,就停下来等perv走一步后交换,再接着走
      		if (a[cur] < a[keyi]&&++prev!=cur)
      			Swap(&a[prev], &a[cur]);
      		cur++;
      	}
      	//cur出去后,prev的值和keyi交换
      	Swap(&a[keyi], &a[prev]);
      	return prev;
      }
      
      
      void QuickSort(int* a, int left, int right)
      {
      	if (left >= right)
      		return;
      	int keyi = PartSort1(a, left, right);
      	//根据基准值去分割区间,继续进行基准排序
      	QuickSort(a, left, keyi - 1);
      	QuickSort(a, keyi+1,right);
      }
      
      void QuickSort2(int* a, int left, int right)
      {
      	if (left >= right)
      		return;
      	int mid = GetMidIndex2(a, left, right);
      	Swap(&a[mid], &a[left]);
      	int phead = left;
      	int pcur = left + 1;
      	int ptail = right;
      	int key = a[left];
      	while (pcur <= ptail)
      	{
      		if (a[pcur] < key)
      		{
      			Swap(&a[pcur], &a[phead]);
      			pcur++;
      			phead++;
      		}
      		else if (a[pcur] > key)
      		{
      			Swap(&a[pcur], &a[ptail]);
      			ptail--;
      		}
      		else//a[pcur] = key
      			pcur++;
      	}
      	QuickSort2(a, left, phead - 1);
      	QuickSort2(a, ptail+1,right);
      }
      
      void QuickSortNonR1(int* a, int left, int right)
      {
      	Stack st;
      	StackInit(&st);
      	//把区间压进去,一定要先压右区间!!
      	StackPush(&st, right);
      	StackPush(&st, left);
      	while (!StackEmpty(&st))
      	{
      		//将数据弹出来进行进准计算
      		int left = StackTop(&st);
      		StackPop(&st);
      		int right= StackTop(&st);
      		StackPop(&st);
      		//进行基准计算
      		int keyi = PartSort3(a, left, right);
      	    //分割区间(left keyi-1)keyi(keyi+1,right)
      		//如果对应的区间还能分割,就继续压,要注意要先压后面在压前面
      		if (keyi + 1 < right)
      		{
      			StackPush(&st, right);
      			StackPush(&st, keyi+1);
      		}
      		if (keyi - 1 > left)
      		{
      			StackPush(&st, keyi-1);
      			StackPush(&st,left);
      		}
      	}
      	//会一直到栈为空,此时就拍好序了!!
      	StackDestory(&st);
      }
      
      
      void QuickSortNonR2(int* a, int left, int right)
      {
      	Queue q;
      	QueueInit(&q);
      	QueuePush(&q, left);
      	QueuePush(&q, right);
      	while (!QueueEmpty(&q))
      	{
      		int left = QueueFront(&q);
      		QueuePop(&q);
      		int right = QueueFront(&q);
      		QueuePop(&q);
      		int keyi = PartSort3(a, left, right);
      		if (keyi - 1 > left)
      		{
      			QueuePush(&q, left);
      			QueuePush(&q, keyi-1);
      		}
      		if (keyi + 1 <right)
      		{
      			QueuePush(&q, keyi +1);
      			QueuePush(&q, right);
      		}
      	}
      	QueueDestory(&q);
      }
      
      //向下调整算法
      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[child] > a[parent])
      		{
      			Swap(&a[child], &a[parent]);
      			//交换完后,让原来的孩子变成父亲,然后再去找新的孩子
      			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 >= 0)
      	{
      		Swap(&a[0], &a[end]);
      		AdjustDown(a, end, 0);
      		end--;
      	}
      }
      
      void BubbleSort(int* a, int n)
      {
      	for (int i = 0; i < n - 1; i++)
      		//每一趟拍好一个,最后排完n-1个,最后一个数就没必要比了
      	{
      		int flag = 1;//假设有序
      		for (int j = 0; j < n - i - 1; j++)//第一趟需要比较的n-1次,第二次需要比较n-2次……
      			//所以结束条件跟着i变化
      		{
      			if (a[j] > a[j + 1])
      			{
      				Swap(&a[j], &a[j + 1]);
      				flag = 0;//如果没有发生交换,说明不符合有序
      			}
      		}
      		if (flag == 1)
      			break;
      	}
      }
      
      void _MergeSort(int* a, int begin, int end, int* temp)
      {
      	if (begin == end)
      		return;//设置递归返回条件
      	if (end - begin + 1 < 10)
      	{
      		InsertSort(a+begin, end - begin + 1);//优化
      		return;
      	}
      	int mid = (begin + end) / 2;
      	//开始分解
      	_MergeSort(a, begin, mid, temp);//左区间归并
      	_MergeSort(a, mid+1, end, temp);//右区间归并
      	//开始进行总归并
      	int begin1 = begin, end1 = mid;//设置指针指向左区间
      	int begin2 = mid + 1, end2 = end;//设置指针指向右区间
      	int i = begin;//用来遍历拷贝数组
      	while (begin1 <= end1 && begin2 <= end2)//只要有一个先拷贝完,就跳出循环
      	{
      		//谁小谁尾插
      		if (a[begin1] < a[begin2])
      			temp[i++] = a[begin1++];
      		else
      			temp[i++] = a[begin2++];
      	}
      	//这个时候其中一个区间先遍历完了,这个时候另一个没有遍历的区间插入就可以了
      	//以下两个while只会执行一个
      	while (begin1 <= end1)//等于才能保证稳定性!!
      		temp[i++] = a[begin1++];
      	while (begin2<=end2)
      		temp[i++] = a[begin2++];
      	//归并完成,将temp的数据拷贝回去
      	memcpy(a + begin, temp + begin, sizeof(int) * (end - begin + 1));//因为递归,拷贝的不一定就是从头开始的,左闭右闭个数要+1;
      }
      void MergeSort(int* a, int n)
      {
      	int* temp = (int*)malloc(sizeof(int) * n);
      	if (temp == NULL)
      	{
      		perror("malloc fail");
      		exit(1);
      	}
      	//开辟成功,开始进行递归
      	_MergeSort(a, 0, n - 1, temp);
      }
      
      void MergeSortNonR(int* a, int n)
      {
      	int* temp = (int*)malloc(sizeof(int) * n);
      	if (temp == NULL)
      	{
      		perror("malloc fail");
      		exit(1);
      	}
      	//开辟成功
      	int gap = 1;
      	while (gap < n)
      	{
      		int j = 0;//用来遍历拷贝数组
      		for (int i = 0; i < n; i += 2 * gap)
      		{
      			int begin1 = i, end1 = i + gap - 1;
      			int begin2 = i + gap, end2 = i + 2 * gap - 1;
      			if (end1 >= n || begin2 >= n)
      				break;
      			if (end2 >= n)//修正
      				end2 = n - 1;
      			while (begin1 <= end1 && begin2 <= end2)//只要有一个先拷贝完,就跳出循环
      			{
      				//谁小谁尾插
      				if (a[begin1] <= a[begin2])
      					temp[j++] = a[begin1++];
      				else
      					temp[j++] = a[begin2++];
      			}
      			//这个时候其中一个区间先遍历完了,这个时候另一个没有遍历的区间插入就可以了
      			//以下两个while只会执行一个
      			while (begin1 <= end1)
      				temp[j++] = a[begin1++];
      			while (begin2 <= end2)
      				temp[j++] = a[begin2++];
      			//归并一次,拷贝一次
      			memcpy(a + i, temp + i, sizeof(int) * (end2-i+1));//一起拷贝回去
      		}
      		gap *= 2;//设置条件
      	}
      }
      
      void MergeSortNonR2(int* a, int n)
      {
      	int* temp = (int*)malloc(sizeof(int) * n);
      	if (temp == NULL)
      	{
      		perror("malloc fail");
      		exit(1);
      	}
      	//开辟成功
      	int gap = 1;
      	while (gap < n)
      	{
      		int j = 0;//用来遍历拷贝数组
      		for (int i = 0; i < n; i += 2 * gap)
      		{
      			int begin1 = i, end1 = i + gap - 1;
      			int begin2 = i + gap, end2 = i + 2 * gap - 1;
      			if (end1 >= n)
      			{
      				end1 = n - 1;//修正end1
      				//然后为了让begin2和end2不走循环,直接让他们区间不存在
      				begin2 = n;
      				end2 = n - 1;
      			}
      			else if (begin2 >= n)
      			{
      				//不存在区间
      				begin2 = n;
      				end2 = n - 1;
      			}
      			else if (end2 >= n)
      			{	//修正end2
      				end2 = n - 1;
      			}
      			while (begin1 <= end1 && begin2 <= end2)//只要有一个先拷贝完,就跳出循环
      			{
      				//谁小谁尾插
      				if (a[begin1] <= a[begin2])
      					temp[j++] = a[begin1++];
      				else
      					temp[j++] = a[begin2++];
      			}
      			//这个时候其中一个区间先遍历完了,这个时候另一个没有遍历的区间插入就可以了
      			//以下两个while只会执行一个
      			while (begin1 <= end1)
      				temp[j++] = a[begin1++];
      			while (begin2 <= end2)
      				temp[j++] = a[begin2++];
      		}
      		gap *= 2;//设置条件
      		memcpy(a, temp, sizeof(int) * n);
      	}
      }
      
      
      void CountSort(int* a, int n)
      {
      	int min = a[0], max = a[0];//根据最值来确定范围
      	//遍历原数组找范围
      	for (int i = 0; i < n; i++)
      	{
      		if (a[i] < min)
      			min = a[i];
      		if (a[i] > max)
      			max = a[i];
      	}
      	//确定新数组的构建范围
      	int range = max - min + 1;
      	int* temp = (int*)calloc(range, sizeof(int));//因为要初始化0,所以用calloc
      	//也可以先用malloc,然后用memset(temp,0,sizeof(int)*range)
      	if (temp == NULL)
      	{
      		perror("calloc fail");
      		exit(1);
      	}
      	//开辟成功后,开始遍历原数组计数
      	for (int i = 0; i < n; i++)
      		temp[a[i] - min]++;
      	//遍历完后,计数也完成了,开始遍历计数数组,恢复原数组
      	int k = 0;//用来恢复原数组
      	for (int j = 0; j < range; j++)
      		while (temp[j]--)//一直减到0,就会跳下一层循环,直到遍历完!!
      			a[k++] = j + min;
      }

      6.3 test.c

      #include"Sort.h"
      
      void TestOP()//测试速度
      {
      	srand((unsigned int)time(NULL));
      	const int N = 1000000;
      	int* a1 = (int*)malloc(sizeof(int) * N);
      	int* a2 = (int*)malloc(sizeof(int) * N);
      	int* a3 = (int*)malloc(sizeof(int) * N);
      	int* a4 = (int*)malloc(sizeof(int) * N);
      	int* a5 = (int*)malloc(sizeof(int) * N);
      	int* a6 = (int*)malloc(sizeof(int) * N);
      	int* a7 = (int*)malloc(sizeof(int) * N);
      	int* a8 = (int*)malloc(sizeof(int) * N);
      
      
      	for (int i = 0; i < N; ++i)
      	{
      		a1[i] = rand();
      		a2[i] = a1[i];
      		a3[i] = a1[i];
      		a4[i] = a1[i];
      		a5[i] = a1[i];
      		a6[i] = a1[i];
      		a7[i] = a1[i];
      		a8[i] = a1[i];
      
      	}
      	//clock计入程序走到当前位置的时间
      	int begin1 = clock();
      	//InsertSort(a1, N);
      	int end1 = clock();
      
      	int begin2 = clock();
      	ShellSort(a2, N);
      	int end2 = clock();
      
      	int begin3 = clock();
      	//SelectSort(a3, N); 
      	int end3 = clock();
      
      	int begin4 = clock();
      	//BubbleSort(a4, N); 
      	int end4 = clock();
      
      	int begin5 = clock();
      	HeapSort(a5, N);
      	int end5 = clock();
      
      	int begin6 = clock();
      	QuickSort(a6, 0, N - 1);
      	int end6 = clock();
      
      	int begin7 = clock();
      	MergeSort(a7, N);
      	int end7 = clock();
      
      	int begin8 = clock();
      	CountSort(a8, N);
      	int end8 = clock();
      
      	printf("InsertSort:%d\n", end1 - begin1);
      	printf("ShellSort:%d\n", end2 - begin2);
      	printf("SelectSort:%d\n", end3 - begin3);
      	printf("BubbleSort:%d\n", end4 - begin4);
      	printf("HeapSort:%d\n", end5 - begin5);
      	printf("QuickSort:%d\n", end6 - begin6);
      	printf("MergeSort:%d\n", end7 - begin7);
      	printf("CountSort:%d\n", end8 - begin8);
      
      	free(a1);
      	free(a2);
      	free(a3);
      	free(a4);
      	free(a5);
      	free(a6);
      	free(a7);
      	free(a8);
      
      }
      
      int main()
      {
      	TestOP();
      }

      6.4 stack.h

      #pragma once
      #include<stdio.h>
      #include<stdbool.h>
      #include<stdlib.h>
      #include<assert.h>
      
      typedef int STDataType;
      //支持动态增长的栈
      typedef struct Stack
      {
      	STDataType* a;
      	int top;//栈顶
      	int capacity;//栈容量
      }Stack;
      
      void StackInit(Stack* ps);//初始化栈
      void StackPush(Stack* ps, STDataType x);//入栈
      void StackPop(Stack* ps);//出栈
      STDataType StackTop(Stack* ps);//获取栈顶元素
      int StackSize(Stack* ps);//获取栈中有效元素个数
      bool StackEmpty(Stack* ps);//检测栈是否为空,为空返回true
      void StackDestory(Stack* ps);//销毁栈

      6.5 stack.c

      #include"Stack.h"
      
      void StackInit(Stack* ps)
      {
      	ps->a = NULL;
      	ps->top = ps->capacity = 0;
      }
      
      void StackPush(Stack* ps, STDataType x)
      {
      	assert(ps);
      	//判断是否需要扩容
      	if (ps->top == ps->capacity)
      	{
      		int newcapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;
      		STDataType* temp = (STDataType*)realloc(ps->a,sizeof(STDataType) * newcapacity);
      		if (temp == NULL)
      		{
      			perror("realloc fail");
      			exit(1);
      		}
      		ps->a = temp;
      		ps->capacity = newcapacity;
      	}
      	//压栈
      	ps->a[ps->top++] = x;
      }
      
      
      void StackPop(Stack* ps)
      {
      	assert(ps);
      	//如果栈为空,则没有删除的必要
      	assert(!StackEmpty(ps));
      	ps->top--;
      }
      
      STDataType StackTop(Stack* ps)
      {
      	assert(ps);
      	//如果栈为空,不可能有栈顶元素
      	assert(!StackEmpty(ps));
      	return ps->a[ps->top - 1];
      }
      
      int StackSize(Stack* ps)
      {
      	assert(ps);
      	return ps->top;
      }
      
      bool StackEmpty(Stack* ps)
      {
      	assert(ps);
      	return ps->top == 0;
      }
      
      void StackDestory(Stack* ps)
      {
      	free(ps->a);
      	ps->a = NULL;
      	ps->top = ps->capacity = 0;
      }
      
      
      

      6.6 queue.h

      #pragma once
      #include<stdio.h>
      #include<stdlib.h>
      #include<stdbool.h>
      #include<assert.h>
      typedef int QDatatype;//方便后面修改存储数据的数据类型
      typedef struct QueueNode//队列结点的数据结构
      {
      	QDatatype data;//存储数据
      	struct QueueNode* next;
      }QNode;
      
      typedef struct Queue
      {
      	QNode* phead;//指向队头,用于出队(头删)
      	QNode* ptail;//指向队尾,用于入队(尾插)
      	int size;//记录有效元素个数
      }Queue;//创建一个队列相关结构体
      void QueueInit(Queue* pq);//队列的初始化
      void QueuePush(Queue* pq, QDatatype x);//队列的入队(尾插)
      void QueuePop(Queue* pq);//队列的出队(头删)
      QDatatype QueueFront(Queue* pq);//获取队列头部元素
      QDatatype QueueBack(Queue* pq);//获取队列尾部元素
      int QueueSize(Queue* pq);//获取队列中有效元素个数
      bool QueueEmpty(Queue* pq);//判断队列是否为空
      void QueueDestory(Queue* pq);//队列的销毁
      
      

      6.7 queue.c

      #include"Queue.h"
      
      void QueueInit(Queue* pq)
      {
      	assert(pq);//判断传的是不是空指针
      	pq->phead = pq->ptail = NULL;
      	pq->size = 0;//因为队列不像栈一样,有一个top表示栈顶元素的下标
      	//所以如果我们想知道这个队列的有效数据个数,就必须遍历队列
      	//由于其先进先出的特性,我们默认只能访问到头元素和尾元素
      	//所以必须访问一个头元素,就出队列一次,这样才能实现遍历
      	//但是这样的代价太大了,为了方便,我们直接用size
      }
      
      void QueuePush(Queue* pq, QDatatype x)
      {
      	assert(pq);
          //入队必须从队尾入!
      	QNode* newnode = (QNode*)malloc(sizeof(QNode));//创建一个新节点
      	if (newnode==NULL)//如果新节点申请失败,退出程序
      	{
      		perror("malloc fail");
      	}
      	//新节点创建成功,给新节点初始化一下
      	newnode->data = x;
      	newnode->next = NULL;
      	//开始入队
      	//如果直接尾插的话,由于会用到ptail->next,所以得考虑队列为空的情况
      	if (pq->ptail== NULL)//如果为空,直接把让新节点成为phead和ptail
      	{
      		//按道理来说,如果ptail为空,phead也应该为空
      		// 但是有可能会因为我们的误操作使得phead不为空,这个时候一般是我们写错的问题
      		//所以使用assert来判断一下,有问题的话会及时返回错误信息
      		assert(pq->phead == NULL);
      		pq->phead = pq->ptail = newnode;
      	}
      	else
      	{
      		pq->ptail->next = newnode;
      		pq->ptail = newnode;
      	}
      	pq->size++;
      }
      
      void QueuePop(Queue* pq)
      {
      	assert(pq);
      	//如果队列为空,没有删除的必要
      	assert(!QueueEmpty(pq));
      	//队列中的出队列相当于链表的头删
      	//如果直接头删,那么如果队列只有一个有效数据的话,那么我们将phead的空间释放掉,但是没有将ptail给置空
      	//这样会导致ptail成为一个野指针,所以我们需要考虑只有一个节点多个节点的情况
      	if (pq->phead->next == NULL)//一个节点的情况,直接将这个节点释放并置空即可
      	{
      		free(pq->phead);
      		pq->phead = pq->ptail = NULL;//置空,防止野指针
      	}
      	else//多个节点的情况,直接头删
      
      	{
      		QNode* next = pq->phead->next;//临时指针记住下一个节点
      		free(pq->phead);
      		pq->phead = next;//让下一个节点成为新的头
      	}
      	pq->size--;
      }
      
      QDatatype QueueFront(Queue* pq)
      {
      	assert(pq);
      	assert(!QueueEmpty(pq));//队列如果为空,则不可能找得到队列头元素
      	//队列不为空的时候,直接返回phead指向的数据
      	return pq->phead->data;
      }
      
      QDatatype QueueBack(Queue* pq)
      {
      	assert(pq);
      	assert(!QueueEmpty(pq));//队列如果为空,则不可能找得到队尾元素
      	//队列不为空的时候,直接返回ptail指向的数据
      	return pq->ptail->data;
      }
      
      int QueueSize(Queue* pq)
      {
      	assert(pq);
      	return pq->size;
      }
      
      bool QueueEmpty(Queue* pq)//链表为空的情况,可以根据容量,也可以根据ptail==NULL&&phead==NULL
      {
      	assert(pq);
      	return pq->ptail == NULL && pq->phead == NULL;
      }
      
      void QueueDestory(Queue* pq)
      {
      	assert(pq);//判断传的是不是空指针
      	//要逐个节点释放
      	QNode* pcur = pq->phead;
      	while (pcur)
      	{
      		QNode* next = pcur->next;
      		free(pcur);
      		pcur = next;
      	}
      	pq->phead = pq->ptail = NULL;
      	pq->size = 0;
      }
      
      版权声明:本文内容来自第三方投稿或授权转载,原文地址:https://blog.csdn.net/weixin_51142926/article/details/136134334,作者:✿༺小陈在拼命༻✿,版权归原作者所有。本网站转在其作品的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如因作品内容、版权等问题需要同本网站联系,请发邮件至ctyunbbs@chinatelecom.cn沟通。

      上一篇:DS初阶:二叉树的链式结构及实现

      下一篇:Element学习(布局组件、案例操作)(4)

      相关文章

      2025-05-19 09:05:01

      【手把手带你刷好题】—— 61.按顺序打印i~j(递归)

      【手把手带你刷好题】—— 61.按顺序打印i~j(递归)

      2025-05-19 09:05:01
      打卡 , 递归
      2025-05-19 09:04:14

      复杂度的OJ练习

      复杂度的OJ练习

      2025-05-19 09:04:14
      代码 , 复杂度 , 思路 , 数组 , 算法
      2025-05-16 09:15:24

      jQuery遍历对象、数组、集合

      jQuery遍历对象、数组、集合

      2025-05-16 09:15:24
      jQuery , 对象 , 数组 , 遍历 , 集合
      2025-05-16 09:15:24

      如何将一串数字用函数的方法倒过来(C语言)

      如何将一串数字用函数的方法倒过来(C语言)

      2025-05-16 09:15:24
      函数 , 数字 , 数组
      2025-05-16 09:15:17

      递归,搜索,回溯算法(3)之穷举,暴搜,深搜,回溯,剪枝

      递归,搜索,回溯算法(3)之穷举,暴搜,深搜,回溯,剪枝

      2025-05-16 09:15:17
      回溯 , 子集 , 数组 , 算法 , 递归
      2025-05-16 09:15:17

      BFS解决最短路问题(4)_为高尔夫比赛砍树

      BFS解决最短路问题(4)_为高尔夫比赛砍树

      2025-05-16 09:15:17
      BFS , lt , 复杂度 , 算法
      2025-05-16 09:15:10

      【C/C++算法】蓝桥杯之递归算法(如何编写想出递归写法)

      【C/C++算法】蓝桥杯之递归算法(如何编写想出递归写法)

      2025-05-16 09:15:10
      结点 , 递归 , 遍历 , 链表 , 题目
      2025-05-16 09:15:10

      BFS解决FloodFill算法(3)_岛屿的最大面积

      BFS解决FloodFill算法(3)_岛屿的最大面积

      2025-05-16 09:15:10
      grid , 复杂度 , 算法
      2025-05-14 10:33:31

      计算机小白的成长历程——数组(1)

      计算机小白的成长历程——数组(1)

      2025-05-14 10:33:31
      strlen , 个数 , 元素 , 内存 , 十六进制 , 地址 , 数组
      2025-05-14 10:33:31

      计算机小白的成长历程——习题演练(函数篇)

      计算机小白的成长历程——习题演练(函数篇)

      2025-05-14 10:33:31
      函数 , 字符串 , 数组 , 知识点 , 编写 , 迭代 , 递归
      查看更多
      推荐标签

      作者介绍

      天翼云小翼
      天翼云用户

      文章

      33561

      阅读量

      5225013

      查看更多

      最新文章

      【手把手带你刷好题】—— 61.按顺序打印i~j(递归)

      2025-05-19 09:05:01

      jQuery遍历对象、数组、集合

      2025-05-16 09:15:24

      typescript 将数组清空

      2025-05-14 10:02:48

      java实现管线拓扑关系连通性分析

      2025-05-14 09:51:15

      java实现167. 两数之和 II - 输入有序数组

      2025-05-13 09:50:17

      java 深搜

      2025-05-13 09:50:17

      查看更多

      热门文章

      ArrayList动态数组对象 c# 1231

      2023-03-28 03:29:30

      js: json的序列化和反序列化

      2023-02-20 10:30:04

      jdk1.8HashMap扩容后链表拆分过程解析

      2022-12-28 07:22:30

      #yyds干货盘点# leetcode-dp-maxProduct

      2022-12-26 09:32:17

      leetcode-dp-53. 最大子数组和

      2022-12-26 09:32:17

      leetcode-dp-归纳法-爬楼梯

      2022-12-26 09:32:17

      查看更多

      热门标签

      linux java python javascript 数组 前端 docker Linux vue 函数 shell git 节点 容器 示例
      查看更多

      相关产品

      弹性云主机

      随时自助获取、弹性伸缩的云服务器资源

      天翼云电脑(公众版)

      便捷、安全、高效的云电脑服务

      对象存储

      高品质、低成本的云上存储服务

      云硬盘

      为云上计算资源提供持久性块存储

      查看更多

      随机文章

      Node.js报错:UnhandledPromiseRejectionWarning: Unhandled promise rejection

      每天一道LeeCode14 【最大连续1的个数】

      sort(排序) qsort(快排) bsearch(二分查找)

      给定一个正整数 x,我们将会写出一个形如 x (op1) x (op2) x (op3) x ... 的表达式 其中每个运算符 op1,op2,… 可以是加、减、乘、除之一

      一个数组arr是二叉树的中序遍历结果,每条边的开销是父节点和子节点的乘积,总开销是所有边的开销之和。请问最小总开销是多少?

      python学习——递归函数

      • 7*24小时售后
      • 无忧退款
      • 免费备案
      • 专家服务
      售前咨询热线
      400-810-9889转1
      关注天翼云
      • 旗舰店
      • 天翼云APP
      • 天翼云微信公众号
      服务与支持
      • 备案中心
      • 售前咨询
      • 智能客服
      • 自助服务
      • 工单管理
      • 客户公告
      • 涉诈举报
      账户管理
      • 管理中心
      • 订单管理
      • 余额管理
      • 发票管理
      • 充值汇款
      • 续费管理
      快速入口
      • 天翼云旗舰店
      • 文档中心
      • 最新活动
      • 免费试用
      • 信任中心
      • 天翼云学堂
      云网生态
      • 甄选商城
      • 渠道合作
      • 云市场合作
      了解天翼云
      • 关于天翼云
      • 天翼云APP
      • 服务案例
      • 新闻资讯
      • 联系我们
      热门产品
      • 云电脑
      • 弹性云主机
      • 云电脑政企版
      • 天翼云手机
      • 云数据库
      • 对象存储
      • 云硬盘
      • Web应用防火墙
      • 服务器安全卫士
      • CDN加速
      热门推荐
      • 云服务备份
      • 边缘安全加速平台
      • 全站加速
      • 安全加速
      • 云服务器
      • 云主机
      • 智能边缘云
      • 应用编排服务
      • 微服务引擎
      • 共享流量包
      更多推荐
      • web应用防火墙
      • 密钥管理
      • 等保咨询
      • 安全专区
      • 应用运维管理
      • 云日志服务
      • 文档数据库服务
      • 云搜索服务
      • 数据湖探索
      • 数据仓库服务
      友情链接
      • 中国电信集团
      • 189邮箱
      • 天翼企业云盘
      • 天翼云盘
      ©2025 天翼云科技有限公司版权所有 增值电信业务经营许可证A2.B1.B2-20090001
      公司地址:北京市东城区青龙胡同甲1号、3号2幢2层205-32室
      • 用户协议
      • 隐私政策
      • 个人信息保护
      • 法律声明
      备案 京公网安备11010802043424号 京ICP备 2021034386号