排序八卦炉之冒泡、快排【完整版】

文章目录

  • 1.冒泡排序
    • 1.1代码实现
    • 1.2复杂度
  • 2.快速排序
    • 2.1人物及思想介绍【源于百度】
    • 2.2hoare【霍尔】版本
      • 1.初识代码
      • 2.代码分析
      • 3.思其因果
    • 2.3挖坑版本
      • 1.初始代码
      • 2.代码分析
      • 3.思想比较
    • 2.4指针版本
      • 1.初识代码
      • 2.代码分析
      • 3.问题探讨
    • 2.5集体优化
    • 2.6极致优化
    • 2.7非递归版本
      • 1.初识代码
      • 2.代码分析
    • 2.8相关博客及完整代码

在这里插入图片描述

1.冒泡排序

在这里插入图片描述

1.1代码实现

//插入排序  O(N)~O(N^2)
//冒泡排序  O(N)~O(N^2)
//当数据有序 二者均为O(N)
//当数据接近有序或局部有序 插排更优
void BubbleSort(int* a, int n)
{
	assert(a);
	int flag = 1;
	for (int i = 0; flag && i < n - 1; ++i)
	{
		flag = 0;
		for (int j = 0; j < n - 1 - i; ++j)
		{
			if (a[j] > a[j + 1])
			{
				Swap(&a[j - 1], &a[j]);
				flag = 1;
			}
		}
	}
}

1.2复杂度

  1. 最坏:
    比较n-1轮
    每一轮比较次数:n n-1 n-2 n-3 … 1 ≈ N^2
  2. 最优:
    比较n-1轮
    数据有序–每一轮只判断不比较 – N

2.快速排序

2.1人物及思想介绍【源于百度】

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

2.2hoare【霍尔】版本

1.初识代码

//霍尔版本
int PartSort1(int* a, int begin, int end)
{

	int left = begin, right = end, x = left;
	while (left < right)
	{
		//右找小
		while (left < right && a[right] >= a[x])
			--right;

		//左找大
		while (left < right && a[left] <= a[x])
			++left;

		Swap(&a[left], &a[right]);
	}

	Swap(&a[x], &a[left]);
	x = left;

	return x;
}
void QuickSort(int* a, int begin, int end)    
{
	//begin:左区间左边界下标 
	//end  :右区间右边界下标
	//begin==end:数据量=1 无需排序 直接返回
	//begin>end :无效区间 无需排序 直接返回
	if (begin >= end)
		return;

	int x = PartSort1(a, begin, end);

	// [begin, x - 1] x [x + 1, end]
	QuickSort(a, begin, x - 1);
	QuickSort(a, x+1, end);
}

2.代码分析

在这里插入图片描述

3.思其因果

Q:为什么a[x]【作为基准值key】置于左侧 – 右边先移动?
A:目的是为了保证相遇位置的值<=key 从而把key与相遇值交换 不打乱“左放小,右放大”的思想
在这里插入图片描述

2.3挖坑版本

1.初始代码

//挖坑版本
int PartSort2(int* a, int begin, int end)
{
	int x = begin, key = a[begin];

    while (begin < end)
	{
		while (begin < end && a[end] >= key)
			--end;
		a[x] = a[end];
		x = end;


		while (begin < end && a[begin] <= key)
			++begin;
		a[x] = a[begin];
		x = begin;
	}

	a[x] = key;
	return x;
}
void QuickSort(int* a, int begin, int end)    
{
	//begin:左区间左边界下标 
	//end  :右区间右边界下标
	//begin==end:数据量=1 无需排序 直接返回
	//begin>end :无效区间 无需排序 直接返回
	if (begin >= end)
		return;

	int x = PartSort1(a, begin, end);

	// [begin, x - 1] x [x + 1, end]
	QuickSort(a, begin, x - 1);
	QuickSort(a, x+1, end);
}

2.代码分析

在这里插入图片描述

3.思想比较

霍尔版本:右找小 左找打 大小交换 依次递归
挖坑版本:记录key值 x位–置空 右找小入坑 坑位更新 左找大入坑 坑位更新 依次递归

在这里插入图片描述

2.4指针版本

1.初识代码

int PartSort3(int* a, int begin, int end)
{   //prv:previous  cp:current pointer
	
	int prv = begin, cp = begin + 1, x = begin;

	while (cp <= end)
	{
		if (a[cp] < a[x] && ++prv != cp)
			Swap(&a[prv], &a[cp]);

		++cp;
	}
	Swap(&a[prv], &a[x]);
	x = prv;
	
	return x;
}
void QuickSort(int* a, int begin, int end)    
{
	//begin:左区间左边界下标 
	//end  :右区间右边界下标
	//begin==end:数据量=1 无需排序 直接返回
	//begin>end :无效区间 无需排序 直接返回
	if (begin >= end)
		return;

	int x = PartSort3(a, begin, end);

	// [begin, x - 1] x [x + 1, end]
	QuickSort(a, begin, x - 1);
	QuickSort(a, x+1, end);
}

2.代码分析

在这里插入图片描述

3.问题探讨

在这里插入图片描述

2.5集体优化

//快速排序   O(N * logN)
//对任意区间三值取中位数
int GetMid_X(int* a, int begin, int end)
{
	int mid = (begin + end) / 2;

	if (a[begin] < a[mid])
	{
		if (a[mid] < a[end])
			return mid;
		else if (a[begin] < a[end])
			return end;
		else
			return begin;
	}
	else //a[begin] >= a[mid]
	{
		if (a[mid] > a[end])
			return mid;
		else if (a[begin] < a[end])
			return begin;
		else
			return end;
	}
}
//霍尔版本
int PartSort1(int* a, int begin, int end)
{
	int left = begin, right = end, x = left;

	//确定更合适的key
	int mid_x = GetMid_X(a, begin, end);
	Swap(&a[x], &a[mid_x]);

	while (left < right)
	{
		//右找小
		while (left < right && a[right] >= a[x])
			--right;

		//左找大
		while (left < right && a[left] <= a[x])
			++left;

		Swap(&a[left], &a[right]);
	}

	Swap(&a[x], &a[left]);
	x = left;

	return x;
}
//挖坑版本
int PartSort2(int* a, int begin, int end)
{
	int x = begin;
	
	//确定更合适的key
	int mid_x = GetMid_X(a, begin, end);
	Swap(&a[x], &a[mid_x]); 
	int key = a[x];
    
	while (begin < end)
	{
		while (begin < end && a[end] >= key)
			--end;
		a[x] = a[end];
		x = end;


		while (begin < end && a[begin] <= key)
			++begin;
		a[x] = a[begin];
		x = begin;
	}

	a[x] = key;
	return x;
}  
//指针版本
int PartSort3(int* a, int begin, int end)
{   //prv:previous  cp:current pointer
	
	int prv = begin, cp = begin + 1, x = begin;
	
	//确定更合适的key
	int mid_x = GetMid_X(a, begin, end);
	Swap(&a[x], &a[mid_x]);

	while (cp <= end)
	{
		if (a[cp] < a[x] && ++prv != cp)
			Swap(&a[prv], &a[cp]);

		++cp;
	}
	Swap(&a[prv], &a[x]);
	x = prv;
	
	return x;
}
void QuickSort(int* a, int begin, int end)    
{
	//begin:左区间左边界下标 
	//end  :右区间右边界下标
	//begin==end:数据量=1 无需排序 直接返回
	//begin>end :无效区间 无需排序 直接返回
	if (begin >= end)
		return;

	int x = PartSort2(a, begin, end);

	// [begin, x - 1] x [x + 1, end]
	QuickSort(a, begin, x - 1);
	QuickSort(a, x+1, end);
}

2.6极致优化

在这里插入图片描述

在这里插入图片描述

2.7非递归版本

递归版本存在的问题:若递归层次太深 导致栈溢出问题
递归改非递归的方法:

  1. 直接改循环 – 斐波那契数列、归并排序等
  2. 数据结构的栈(Stack)模拟递归【Stack的空间是从堆申请的 堆内存比栈内存大】

1.初识代码

int PartSort3(int* a, int begin, int end)
{   //prv:previous  cp:current pointer
	int prv = begin, cp = begin + 1, x = begin;
	//确定更合适的key
	int mid_x = GetMid_X(a, begin, end);
	Swap(&a[x], &a[mid_x]);
	while (cp <= end)
	{
		if (a[cp] < a[x] && ++prv != cp)
			Swap(&a[prv], &a[cp]);
		++cp;
	}
	Swap(&a[prv], &a[x]);
	x = prv;
	return x;
}
void QuickSort_NonRecursion(int* a, int begin, int end)
{
	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 x = PartSort3(a, left, right);
		 
		if (x + 1 < right)
		{
			StackPush(&st, x + 1);
			StackPush(&st, right);
		}
		// [left, x-1] x [x+1, right]
		if (left < x - 1)
		{
			StackPush(&st, left);
			StackPush(&st, x - 1);
		}
	}
	StackDestroy(&st);
}

2.代码分析

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2.8相关博客及完整代码

点击 [qsort与bubble之间不为人知的关系](htt p://t.csdn.cn/filuW) 查看博主之前关于分析这两个排序的博客。

//快速排序   O(N * logN)
int count = 0;  //测试递归次数
//对任意区间三值取中位数
int GetMid_X(int* a, int begin, int end)
{
	int mid = (begin + end) / 2;

	if (a[begin] < a[mid])
	{
		if (a[mid] < a[end])
			return mid;
		else if (a[begin] < a[end])
			return end;
		else
			return begin;
	}
	else //a[begin] >= a[mid]
	{
		if (a[mid] > a[end])
			return mid;
		else if (a[begin] < a[end])
			return begin;
		else
			return end;
	}
}
//霍尔版本
int PartSort1(int* a, int begin, int end)
{
	int left = begin, right = end, x = left;

	//确定更合适的key
	int mid_x = GetMid_X(a, begin, end);
	Swap(&a[x], &a[mid_x]);

	while (left < right)
	{
		//右找小
		while (left < right && a[right] >= a[x])
			--right;

		//左找大
		while (left < right && a[left] <= a[x])
			++left;

		Swap(&a[left], &a[right]);
	}

	Swap(&a[x], &a[left]);
	x = left;

	return x;
}
//挖坑版本
int PartSort2(int* a, int begin, int end)
{
	int x = begin;
	
	//确定更合适的key
	int mid_x = GetMid_X(a, begin, end);
	Swap(&a[x], &a[mid_x]); 
	int key = a[x];
    
	while (begin < end)
	{
		while (begin < end && a[end] >= key)
			--end;
		a[x] = a[end];
		x = end;


		while (begin < end && a[begin] <= key)
			++begin;
		a[x] = a[begin];
		x = begin;
	}

	a[x] = key;
	return x;
}  
//指针版本
int PartSort3(int* a, int begin, int end)
{   //prv:previous  cp:current pointer
	int prv = begin, cp = begin + 1, x = begin;
	//确定更合适的key
	int mid_x = GetMid_X(a, begin, end);
	Swap(&a[x], &a[mid_x]);
	while (cp <= end)
	{
		if (a[cp] < a[x] && ++prv != cp)
			Swap(&a[prv], &a[cp]);
		++cp;
	}
	Swap(&a[prv], &a[x]);
	x = prv;
	return x;
}

void QuickSort(int* a, int begin, int end)
{
	count++;
	//begin:左区间左边界下标 
	//end  :右区间右边界下标
	//begin==end:数据量=1 无需排序 直接返回
	//begin>end :无效区间 无需排序 直接返回
	if (begin >= end)
		return;

	int x = PartSort3(a, begin, end);

	// [begin, x - 1] x [x + 1, end]
	QuickSort(a, begin, x - 1);
	QuickSort(a, x+1, end);
}

/*
void QuickSort(int* a, int begin, int end)
{
	count++;
	if (begin >= end)
		return;
	
	if (end - begin > 10)
	{
		int x = PartSort3(a, begin, end);
		
		// [begin, x-1] x [x+1, end]
		QuickSort(a, begin, x - 1);
		QuickSort(a, x + 1, end);
	}
	else 
		InsertSort(a + begin, end - begin + 1);
}
*/
//非递归版本
void QuickSort_NonRecursion(int* a, int begin, int end)
{
	ST st;
	StackInit(&st);

	StackPush(&st, begin);
	StackPush(&st, end);

	while (!StackEmpty(&st))
	{
		int end = StackTop(&st);
		StackPop(&st);
		int begin = StackTop(&st);
		StackPop(&st);

		int x = PartSort3(a, begin, end);
		 
		if (x + 1 < end)
		{
			StackPush(&st, x + 1);
			StackPush(&st, end);
		}
		// [begin, x-1] x [x+1, end]
		if (begin < x - 1)
		{
			StackPush(&st, begin);
			StackPush(&st, x - 1);
		}
	}
	StackDestroy(&st);
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【ConcurrentHashMap1.7源码】十分钟带你深入ConcurrentHashMap并发解析

ConcurrentHashMap1.7源码 四个核心要点 初始化PUT扩容GET Unsafe 初始化 五个构造方法 /*** Creates a new, empty map with the default initial table size (16).*/public ConcurrentHashMap() {}/*** Creates a new, empty map with an initial table size* accommodati…

FFmpeg下载安装及Windows开发环境设置

1 FFmpeg简介 FFmpeg&#xff1a;FFmpeg是一套可以用来记录、转换数字音频、视频&#xff0c;并能将其转化为流的开源计算机程序。采用LGPL或GPL许可证。它提供了录制、转换以及流化音视频的完整解决方案。项目的名称来自MPEG视频编码标准&#xff0c;前面的"FF"代表…

【Spring】Spring中的设计模式

文章目录 责任链模式工厂模式适配器模式代理模式模版方法观察者模式构造器模式 责任链模式 Spring中的Aop的通知调用会使用责任链模式责任链模式介绍 角色&#xff1a;抽象处理者&#xff08;Handler&#xff09;具体处理者&#xff08;ConcreteHandler1&#xff09;客户类角…

【Spring Cloud 五】OpenFeign服务调用

这里写目录标题 系列文章目录背景一、OpenFeign是什么Feign是什么Feign的局限性 OpenFeign是什么 二、为什么要有OpenFeign三、如何使用OpenFeign服务提供者order-servicepom文件yml配置文件启动类实体ParamController 服务消费者user-servicepom文件yml配置文件启动类接口类Us…

微信小程序真机防盗链referer问题处理

公司使用百度云存储一些资源&#xff0c;然后现在要做防盗链&#xff0c;在CDN加入Referer白名单后发现PC是正常的&#xff0c;微信小程序无法正常访问资源了。然后是各种查啊&#xff0c;然后发现是微信小程序不支持Referer的修改&#xff0c;且在小程序开发工具是Referer是固…

ATFX汇评:非农就业报告来袭,汇市或迎剧烈波动

ATFX汇评&#xff1a;美国非农就业报告每月发布一次&#xff0c;其中非农就业人口和失业率两项数据最受关注。7月季调后非农就业人口&#xff0c;将于今日20:30公布&#xff0c;前值为20.9万人&#xff0c;预期值20万人&#xff1b;7月失业率&#xff0c;同一时间公布&#xff…

极光笔记 | 浅谈企业级SaaS产品的客户成长旅程管理(上)—— 分析篇

本文作者&#xff1a;陈伟&#xff08;极光用户体验部高级总监&#xff09; “企业级SaaS产品与C端互联网产品特征差异很大&#xff0c;有些甚至是截然相反&#xff0c;这些特征也会成为后续客户成长旅程的重要影响变量。本文就如何设计并服务好企业级SaaS产品客户成长旅程进行…

概念解析 | 利用IAA迭代自适应方法实现高精度角度估计

利用IAA迭代自适应方法实现高精度角度估计 注1:本文系“概念辨析”系列之一,致力于简洁清晰地解释、辨析复杂而专业的概念。本次辨析的概念是:IAA迭代自适应方法在雷达角度估计中的应用。 背景介绍 在雷达目标检测与定位中,准确估计目标角度是实现高精度定位的关键。传统的基于…

面试热题(前中序遍历构建树)

给定两个整数数组 preorder 和 inorder &#xff0c;其中 preorder 是二叉树的先序遍历&#xff0c; inorder 是同一棵树的中序遍历&#xff0c;请构造二叉树并返回其根节点。 题目中是给定两个数组&#xff0c;一个是存放这颗树的前序遍历的数组&#xff0c;一个是存放这棵树的…

消息队列项目(2)

我们使用 SQLite 来进行对 Exchange, Queue, Binding 的硬盘保存 对 Message 就保存在硬盘的文本中 SQLite 封装 这里是在 application.yaml 中来引进对 SQLite 的封装 spring:datasource:url: jdbc:sqlite:./data/meta.dbusername:password:driver-class-name: org.sqlite.…

字典与数组第5讲:数组区域内,数组公式的编辑和删除

【分享成果&#xff0c;随喜正能量】我们的心和宇宙本是相通的&#xff0c;所以生命内在蕴含了无限的智慧&#xff0c;但在没有开发没有证悟之前&#xff0c;生命是渺小而短暂的……..。 《VBA数组与字典方案》教程&#xff08;10144533&#xff09;是我推出的第三套教程&#…

cmake配置Qt工程

cmake 工程配置 # 指定版本和项目 cmake_minimum_required(VERSION 3.10) set(TARGET_NAME labelDeviceView) project(${TARGET_NAME} ) include(${CMAKE_CURRENT_LIST_DIR}/../../../../../../ossLib/ossLib/env.cmake) set(CMAKE_PREFIX_PATH "D:/Qt6/6.5.2/msvc2019…

MyBatis核心 - SqlSession如何通过Mapper接口生成Mapper对象

书接上文 MyBatis – 执行流程 我们通过SqlSession获取到了UserMapper对象&#xff0c;代码如下&#xff1a; // 获取SqlSession对象 SqlSession sqlSession sqlSessionFactory.openSession();// 执行查询操作 try {// 获取映射器接口UserMapper userMapper sqlSession.get…

第3章 数据和C

本章介绍以下内容&#xff1a; 关键字&#xff1a;int 、short、long、unsigned、char、float、double、_Bool、_Complex、_Imaginary 运算符&#xff1a;sizeof() 函数&#xff1a;scanf() 整数类型和浮点数类型的区别 如何书写整型和浮点型常数&#xff0c;如何声明这些类型的…

计蒜客T1116——验证子串

C实现验证子串的功能:今天复习了一下数据结构的串部分的内容&#xff0c;突然想起来子串匹配的实现&#xff0c;于是计蒜客随便找一道题写一下&#xff0c;核心的代码为裁剪子串和字符串比较两个内容&#xff0c;建议理解背诵&#xff0c;考研大概率会考。 子串裁剪 string Sf…

小鱼深度产品测评之:阿里云容器服务器ASK,一款不需购买节点,即可直接部署容器应用。

容器服务器ASK测评 1、引言2、帮助文档3、集群3.1集群列表3.1.1 详情3.1.1.1概览 tab3.1.1.2基本信息 tab3.1.1.4集群资源 tab3.1.1.5 集群日志 tab3.1.1.6 集群任务 tab 3.1.2 应用管理3.1.2.1 详情3.1.2.2 详情3.1.2.3 伸缩3.1.2.4 监控 3.1.3 查看日志3.1.3.1 集群日志3.1.3…

AcWing 24:机器人的运动范围 ← BFS、DFS

【题目来源】https://www.acwing.com/problem/content/description/22/【题目描述】 地上有一个 m 行和 n 列的方格&#xff0c;横纵坐标范围分别是 0∼m−1 和 0∼n−1。 一个机器人从坐标 (0,0) 的格子开始移动&#xff0c;每一次只能向左&#xff0c;右&#xff0c;上&#…

nginx服务

web服务&#xff1a; 国外主流的网站服务还是apache 国内主流的网站服务是&#xff1a;nginx Nginx网站服务 nginx是一个高性能、轻量级的web服务软件。 nginx的特点&#xff1a; 1.稳定性相对较高。&#xff08;但是没有apache稳定&#xff09; 2.系统资源消耗低。体现在处理h…

“科创中国”青百会轮值主席吴甜:以大语言模型为代表的AI将引发产业变革

8月1日&#xff0c;“科创中国”青年百人会&#xff08;后文简称青百会&#xff09;联合百度举办“青创汇”高端对话&#xff0c;围绕人工智能技术创新与产业发展交流研讨&#xff0c;同时正式成立“科创中国”青年百人会女性工作委员会。该委员会将鼓励更多女性投身科技创新事…

如何隐藏开源流媒体EasyPlayer.js视频H.265播放器的实时录像按钮?

目前我们TSINGSEE青犀视频所有的视频监控平台&#xff0c;集成的都是EasyPlayer.js版播放器&#xff0c;它属于一款高效、精炼、稳定且免费的流媒体播放器&#xff0c;可支持多种流媒体协议播放&#xff0c;包括WebSocket-FLV、HTTP-FLV&#xff0c;HLS&#xff08;m3u8&#x…