快速排序的三路划分方法和归并排序的递归和非递归实现

news2024/11/24 15:54:32

目录

快速排序的三路划分方法 

 归并排序的递归实现

 归并排序的非递归实现

快速排序的三路划分方法 

首先快排的时间复杂度为O(N*logN),空间复杂度O(logN),不稳定。

三路划分:将数据分为三份;可以提高当数据中出现多个重复数字时的效率。

 如上图所示,小于key的值移动到左边,等于key的值放在中间,大于key的值移动到右边。

具体操作如下图所示:

核心思想:

  1. 比key小的值移动到左边 
  2. 与key相等的值,往后移动 
  3. 比key大的值移动到右边 
  4. 与key相等的值移动到了中间

 对于key的取值,我们选用随机取值的方法取值。因为如果使用三数取中的话,面对特殊用例的时候,可能大量区间选key让你选到比较小或者比较大的,导致性能下降。

代码:

#include <stdio.h>      /* printf, scanf, puts, NULL */
#include <stdlib.h>     /* srand, rand */
#include <time.h>       /* time */
#include <sting.h>

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

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

int GetMidIndex(int* a, int begin, int end)
{
	int mid = begin+rand()%(end-begin);
	if (a[begin] < a[mid])
	{
		if (a[begin] > a[end])
		{
			return begin;
		}
		else if (a[mid] < a[end])
		{
			return mid;
		}
		else
		{
			return end;
		}
	}
	else//a[begin]>a[mid]
	{
		if (a[mid] > a[end])
		{
			return mid;
		}
		else if (a[begin] < a[end])
		{
			return begin;
		}
		else
		{
			return end;
		}
	}
}


void QuickSort(int* a, int begin, int end)
{
	if (begin >= end)
	{
		return;
	}
	if ((end - begin + 1) < 15)
	{
		//小区间用直接插入代替,减少递归调用次数
		InsertSort(a + begin, end-begin+1);
	}
	else
	{
		int mid =GetMidIndex(a,begin,end);
		Swap(&a[begin],&a[mid]);

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

		while(cur<=right)
		{
			if(a[cur]<key)
			{
				Swap(&a[cur],&a[left]);
				++cur;
				++left;
			}
			else if(a[cur]>key)
			{
				Swap(&a[cur],&a[right]);
				--right;
			}
			else
			{
				cur++;
			}
		}
		//[begin,left-1][left,right] [right+1,end]左边小右边大,中间的不处理
		QuickSort(a, begin, left-1);
		QuickSort(a, right+1, end);
	}
}

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

int main()
{
    int a[]={2,1,2,7,2,2,4,5,2,8}; 
    QuickSort(a,0,sizeof(a)\sizeof(int)-1);
    PrintArray(a, sizeof(a) / sizeof(int));
    return 0;
}

 运行结果:

 归并排序的递归实现

归并排序的时间复杂度为O(N*logN),空间复杂度O(N),稳定。 

以升序为例,对于无序的数据,不断将数据划分为两个子区间,当每个子区间划分为只有一个数的时候认为有序,然后对每个子区间进行归并排序

对于两个有序的子区间,依次比较,取小的尾插

当其中一个子区间尾插完,剩下的依次尾插到数组里;具体图下图所示。

代码:

void _MergeSort(int* a, int begin, int end, int* tmp)
{
	if (begin >= end)
	{
		return;
	}
	int mid = (begin + end) / 2;
	_MergeSort(a, begin, mid, tmp);      //递归让子区间有序
	_MergeSort(a, mid + 1, end, tmp);

	//归并 [begin,mid][mid+1,end]
	int i = begin;
	int begin1 = begin, end1 = mid;
	int begin2 = mid + 1, end2 = end;
	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 + begin, tmp + begin, sizeof(int) * (end - begin + 1));
}

// 归并排序递归实现
void MergeSort(int* a, int n)
{
	int* tmp = (int*)malloc(sizeof(int) * (n));
	if(tmp==NULL)
	{
		perror("malloc failed");
		exit(-1);
	}
	
	_MergeSort(a, 0, n - 1, tmp);

	free(tmp);
	tmp = NULL;
}

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

int main()
{
    int a[]={10,6,7,1,3,9,4,2};
    MergeSort(a,sizeof(a)\sizeof(int));
    PrintArray(a, sizeof(a)\sizeof(int));
    return 0;
}

运行结果截图

 归并排序的非递归实现

思想和递归的思想差不多,定义一个rangeN来控制数据跳动的步长,达到将数据分为子区间的效果。如下图所示。(begin1和end1作为左子区间的边界,begin2和end2作为右子区间的边界。)

但是控制不好会越界,越界访问需要注意的情况有

  1. end1 会越界
  2. begin2和end2越界
  3. end2越界

 对于越界的边界,我们需要重新修正。

#define  _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>

// 归并排序非递归实现
void MergeSortNonR(int* a, int n)
{
	int* tmp = (int*)malloc(sizeof(int) * n);
	if (tmp == NULL)
	{
		perror("malloc fail");
		exit(-1);
	}

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

			// end1 begin2 end2 越界
			// 修正区间  ->拷贝数据 归并完了整体拷贝 or 归并每组拷贝
			if (end1 >= n)
			{
				end1 = n - 1;
				// 不存在区间
				begin2 = n;
				end2 = n - 1;
			}
			else if (begin2 >= n)
			{
				// 不存在区间
				begin2 = n;
				end2 = n - 1;
			}
			else if (end2 >= n)
			{
				end2 = n - 1;
			}

			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, tmp, sizeof(int) * (n));
		rangeN *= 2;
	}
	free(tmp);
	tmp = NULL;
}

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

int main()
{
	int a[] = { 10,6,7,1,3,9,4,2 };
	MergeSortNonR(a, sizeof(a)/sizeof(int));
	PrintArray(a, sizeof(a)/sizeof(int));
	return 0;
}

运行结果截图:

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

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

相关文章

青岛大学_王卓老师【数据结构与算法】Week04_03_双向链表_学习笔记

本文是个人学习笔记&#xff0c;素材来自青岛大学王卓老师的教学视频。 一方面用于学习记录与分享&#xff0c;另一方面是想让更多的人看到这么好的《数据结构与算法》的学习视频。 如有侵权&#xff0c;请留言作删文处理。 课程视频链接&#xff1a; 数据结构与算法基础–…

2022(特等奖)C2592儿童安全监护与救援指挥系统

作品介绍 1 需求分析 现如今人口拐卖犯罪已成为世界上增长最快、最有利可图的犯罪之一&#xff0c;年利润仅次于毒品和军火&#xff0c;其中儿童拐卖犯罪最为引人注目&#xff0c;且被拐数量惊人&#xff0c;已成为国际社会共同关注的问题。2021年4月&#xff0c;国务院发布了…

Kafka入门, 消费者工作流程

kafka消费方式 pull(拉)模式&#xff1a; consumer采用从broker中主动拉取数据。 Kafka采用这种方式。 push(推)模式&#xff1a; Kafka没有采用这种方式&#xff0c;因为由broker决定消息发送速率&#xff0c;很难适应所有消费者的速率。例如推送速度是50m/s&#xff0c;consu…

云原生时代,如何通过 KubeSphere x 极狐GitLab 构建安全应用?

本文整理自云原生 Meetup 杭州站上&#xff0c;极狐(GitLab) DevOps 技术布道师马景贺的演讲。 当听到云原生的时候&#xff0c;你会想起什么&#xff1f; 可能很多人很自然地就会想到 Kubernetes、容器、微服务、开源等等&#xff0c;这些关键词是我们接触云原生绕不开的话题。…

CleanMyMac X4.13中文版mac电脑优化加速工具

CleanMyMac X 可以卸掉系统的额外负担 让您的电脑明显提速 不要再因为运行缓慢的 Mac 而拖慢您的效率。CleanMyMac X已经正式发布&#xff0c;作为最新的系统清理和应用管理软件&#xff0c;可以让用户一键智能化清理Mac电脑&#xff0c;自动扫描Mac上的所有文件&#xff0c;包…

Day44

思维导图 练习 全局变量&#xff0c;int monster 10000;定义英雄类hero&#xff0c;受保护的属性string name&#xff0c;int hp,int attck&#xff1b;公有的无参构造&#xff0c;有参构造&#xff0c;虚成员函数 void Atk(){blood-0;}&#xff0c;法师类继承自英雄类&#…

【操作系统】一些重要的概念

创作不易&#xff0c;本篇文章如果帮助到了你&#xff0c;还请点赞 关注支持一下♡>&#x16966;<)!! 主页专栏有更多知识&#xff0c;如有疑问欢迎大家指正讨论&#xff0c;共同进步&#xff01; &#x1f525;c系列专栏&#xff1a;C/C零基础到精通 &#x1f525; 给大…

敏捷开发SCRUM工具

目录 1 Scurm开发工具1.1 白板1.2 PingCode1.3 VersionOne1.4 Atlassian Jira 2 PingCode进行Scurm开发2.1 角色管理2.2 创建敏捷项目2.3 需求管理2.4 迭代2.5 版本管理 1 Scurm开发工具 1.1 白板 上面我们说了Scurm框架的操作流程&#xff0c;下面我们看下支持Scurm开发框架的…

SpringBoot3【③ 数据访问】

整合SSM场景 SpringBoot 整合 Spring、SpringMVC、MyBatis 进行数据访问场景开发 1. 创建SSM整合项目 勾选的情况下会导入这些包 <!-- https://mvnrepository.com/artifact/org.mybatis.spring.boot/mybatis-spring-boot-starter --> <dependency><groupId>…

JMeter进行websocket测试

在做websocket性能测试的时候找了几个测试工具都暂时没有对websocket的支持&#xff0c;发现jmeter好像对websockect支持。但是使用jmeter时需要安装插件&#xff0c;下面一起看一下。 jmeter下载安装&#xff1a; 官网下载 https://jmeter.apache.org/download_jmeter.cgi 也…

【Java用法】Java在Linux下获取当前程序路径以及在Windows下获取当前路径对比

Java在Linux下获取当前程序路径以及在Windows下获取当前路径对比 log.info("分隔符&#xff1a;File.separator[{}]", File.separator); log.info("用户主目录&#xff1a;user.home[{}]", System.getProperties().getProperty("user.home")); l…

(模拟) 31. 下一个排列——【Leetcode每日一题】

❓ 31. 下一个排列 难度&#xff1a;中等 整数数组的一个 排列 就是将其所有成员以序列或线性顺序排列。 例如&#xff0c;arr [1,2,3] &#xff0c;以下这些都可以视作 arr 的排列&#xff1a;[1,2,3]、[1,3,2]、[3,1,2]、[2,3,1] 。 整数数组的 下一个排列 是指其整数的…

loki 的memberlist查看

本文来自&#xff1a;loki 的memberlist查看 | 老五笔记 loki作为目前比较 通用的日志类数据管理软件&#xff0c;使用起来具有一定的门槛。loki既可以支持单机版使用&#xff0c;也可以为了应对大规模数据而采用集群模式进行部署。 而在集群模式下&#xff0c;需要在配置文件…

You need to use a Theme.AppCompat theme (or descendant) with this activity

You need to use a Theme.AppCompat theme (or descendant) with this activity 最近使用Android Studio新建了个 Jetpack Compose项目&#xff0c;但创建java Activity时报错“You need to use a Theme.AppCompat theme (or descendant) with this activity”。 两种解决办法…

ipad可以用别的品牌的手写笔吗?ipad专用笔替代品

要知道&#xff0c;这款正版苹果的电容笔&#xff0c;单单一支价格都要接近上千元。事实上&#xff0c;对于那些没有很多预算的人来说&#xff0c;平替电容笔是一个很好的选择。一支苹果原装的电容笔&#xff0c;价格是平替电容笔的四倍&#xff0c;但这种平替电容笔&#xff0…

Uniapp开发的开源盲盒系统源码

最近比较火的盲盒系统&#xff0c;该项目是基于uniapp开发的盲盒项目&#xff0c;有需要的朋友可以联系我&#xff0c;运营级的项目&#xff0c;本次开源的是uniapp前端模板&#xff0c;选用技术为JAVA&#xff0c;采用框架&#xff1a;spring bootmybatisvue开发。 通过node安…

day2 QT按钮与容器

目录 按钮 1、QPushButton 2、QToolButton 3、QRadioButton 4、QCheckBox 示例 容器 ​编辑 1. QGroupBox&#xff08;分组框&#xff09; 2. QScrollArea&#xff08;滚动区域&#xff09; 3. QToolBox&#xff08;工具箱&#xff09; 4. QTabWidget&#xff08;选…

LLaMA

LLaMA 1&#xff0c;llama 参数范围7B 13B 33B 65B 在万亿token上训练的模型&#xff0c; 2,研究重点 研究表明&#xff0c;最好的模型性能不是由最大的模型体积实现&#xff0c;而是在更多的数据上训练较小的模型实现 工作重点是通过使用比通常更多的token&#xff0c;训练一系…

05-Redis初步使用

关系型数据的ACID特性:事务的四大特性:原子性,一致性,隔离性,持久性 关系型数据库应对的三高问题:高并发,高效率,高扩展 关系型数据库和非关系型数据库 关系型数据库的数据存储在表中,无法应对陡增的数据 非关系型数据库使用键值对的方式进行存储数据:redis可以用作缓存 r…

U-Boot移植 - 3_U-Boot 命令使用

文章目录 U-Boot 命令使用1. 信息查询命令2. 环境变量操作命令2.1 修改环境变量2.2 新建环境变量2.3 删除环境变量 3. 内存操作命令3.1 md 命令3.2 nm 命令3.3 mm 命令3.4 mw 命令3.5 cp 命令3.6 cmp 命令 4. 网络操作命令4.1 ping 命令4.2 dhcp 命令4.3 nfs 命令4.4 tftp 命令…