123.【C语言】数据结构之快速排序挖坑法和前后指针法

目录

1.挖坑法

执行流程

代码

运行结果

可读性好的代码

2.前后指针法(双指针法)

执行流程

单趟排序代码

将单趟排序代码改造后

写法1

简洁的写法

3.思考题


1.挖坑法

执行流程

"挖坑法"顾名思义:要有坑位,一开始将关键值放入临时变量key中,在数组中形成一个坑位

左边做key,右边先走,先right找到小,将小值放入坑位中,坑位被转移

left找到大,将大值放入坑位中,坑位被转移 

重复上述过程

最终left和right相遇,在坑位填上key的值,单趟快速排序结束,之后对左右两个区间排序,递归处理,写成完整的挖坑法的快速排序

注意:对比120.【C语言】数据结构之快速排序(详解Hoare排序算法)文章写的Hoare快速排序,本方法无需交换函数

代码

void QuickSort_Hole(int* arr, int left, int right)//挖坑法(对着Hoare排序修改即可
{
	if (left > right)
		return;

	int begin = left;
	int end = right;
	int key = arr[left];//对比Hoare排序,不需要key的下标key_i,且不能保存下标,否则值覆盖会丢失数据
	while (left < right)
	{
		//由于key_i==left,因此right指针先走
		//右边找小
		while (left < right && arr[right] >= key)
		{
			right--;
		}
 
		arr[left] = arr[right];//填坑位
		//左边找大
		while (left < right && arr[left] <=key)
		{
			left++;
		}
		arr[right] = arr[left];//填坑位
	}
	arr[left] = key;//此时left==right
	QuickSort_Hoare(arr, begin,  left- 1);
	QuickSort_Hoare(arr, left + 1, end);
}

main.c写入以下代码

#include "Sort.h"
int main()
{
	int arr[] = { 6,1,2,7,9,3,4,5,10,8 };
	printf("排序前:");
	PrintArray(arr, sizeof(arr) / sizeof(arr[0]));
	QuickSort_Hole(arr, 0,sizeof(arr) / sizeof(arr[0])-1);
	printf("排序后:");
	PrintArray(arr, sizeof(arr) / sizeof(arr[0]));
	return 0;
}

运行结果

虽然能完成快速排序,但该代码的可读性较差,建议专门定义一个变量hole_i表示坑位的下标,则arr[hole_i]表示坑位,可写成如下形式

可读性好的代码

//可读性好,有hole_i变量
void QuickSort_Hole(int* arr, int left, int right)//挖坑法(对着Hoare排序修改即可
{
	if (left > right)
		return;

	int begin = left;
	int end = right;
	int key = arr[left];//对比Hoare排序,不需要key的下标key_i,且不能保存下标,否则值覆盖会丢失数据
	int hole_i = left;//记录坑的下标
	while (left < right)
	{
		//由于key_i==left,因此right指针先走
		//右边找小
		while (left < right && arr[right] >= key)
		{
			right--;
		}
		arr[hole_i] = arr[right];//填补坑位
		hole_i = right;//修改坑位下标

		//左边找大
		while (left < right && arr[left] <= key)
		{
			left++;
		}
		arr[hole_i] = arr[left];//填补坑位
		hole_i = left;//修改坑位下标
	}
	arr[hole_i] = key;//此时left==right

	QuickSort_Hoare(arr, begin, hole_i - 1);
	QuickSort_Hoare(arr, hole_i + 1, end);
}

2.前后指针法(双指针法)

执行流程

设前指针prev和后指针cur

设排升序,单趟快排流程

1.最开始prev指向arr[0],cur指向arr[1]

2.cur找到比key(key==arr[key_i])小的值,prev++,arr[cur]和arr[prev]位置的值交换,cur++

3.cur找到比key大的值,cur++

4.重复1和2,直到cur遇到数组的边界时,让arr[key_i]和arr[prev]互换,单趟快排结束

设key_i==0,则arr[key_i]==6,数组长度为n,对[0,n]这一闭区间排序

 

 

 

 

 

 

 

 

 

从图中可以看出两点

1.prev要么紧跟着cur(prev+1==cur);要么和cur中间间隔比key大的一段区间;

2.把比key大的值往右翻,比key小的值,翻到左边

 arr[prev]的左边比6小,右边比6大,之后对绿色和蓝色区域再快速排序

单趟排序代码


    int prev = 0;
    int cur = 1;
    int key_i = 0;
    while (cur < n)
    {
        if (arr[cur] > arr[key_i])
        {
            cur++;
        }
        else
        {
            prev++;
            if (cur != prev)//避免自己和自己交换,无意义
            {
                Swap(&arr[cur], &arr[prev]);
            }
            cur++;
        }
    }
    Swap(&arr[key_i], &arr[prev]);

将单趟排序代码改造后

写法1

void QuickSort_Prev_And_Cur_Pointer(int* arr,int left,int right)
{
	if (left >= right)
	{
		return;
	}

	int prev = left;
	int cur = prev+1;
	int key_i = left;
	while (cur <= right)//由于是闭区间,因此cur<=right!!cur可以取等
	{
		if (arr[cur] > arr[key_i])
		{
			cur++;
		}
		else
		{
			prev++;
			if (cur != prev)//避免自己和自己交换,无意义
			{
				Swap(&arr[cur], &arr[prev]);
			}
			cur++;
		}
	}
	Swap(&arr[key_i], &arr[prev]);

	QuickSort_Prev_And_Cur_Pointer(arr, left, prev - 1);
	QuickSort_Prev_And_Cur_Pointer(arr, prev + 1, right);
}
QuickSort_Prev_And_Cur_Pointer(arr, 0,sizeof(arr) / sizeof(arr[0])-1);//一定有-1

一定要注意while (cur <= right)一定要取等!!

简洁的写法

	while (cur <= right)//由于是闭区间,因此cur<=right!!cur可以取等
	{
		if (arr[cur] < arr[key_i] && ++prev != cur)
		{
			Swap(&arr[cur], &arr[prev]);
		}
		cur++;
	}

上述提到的这两种方法仍然需要递归,过多数会导致栈溢出,下篇文章会讲解决方法

3.思考题

key在右边时(即arr[key_i]==arr[right]),前后指针法怎么写?

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

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

相关文章

国产信创实践(国能磐石服务器操作系统CEOS +东方通TongHttpServer)

替换介绍&#xff1a; 国能磐石服务器操作系统CEOS 对标 Linux 服务器操作系统&#xff08;Ubuntu, CentOS&#xff09; 东方通TongHttpServer 对标 Nginx 负载均衡Web服务器 第一步&#xff1a; 服务器安装CEOS映像文件&#xff0c;可直接安装&#xff0c;本文采用使用VMware …

Linux中SSH服务(二)

一、基于公私钥的认证&#xff08;免密登录&#xff09; 1、Windows免密登录Linux Windows推荐安装Cygwin软件&#xff1a;Cygwin 1.1Windows上面生成公私钥 之前已经生成过了&#xff0c;所以显示公私钥已存在 lovezywLAPTOP-AABHB5ED ~ $ ssh-keygen Generating public/pr…

Linux-----进程通讯(管道Pipe)

目录 进程不共享内存 匿名管道 通过匿名管道实现通讯 有名管道 库函数mkfifo() 案例 进程不共享内存 不同进程之间内存是不共享的。是相互独立的。 #include <stdio.h> #include <stdlib.h> #include <errno.h>int num 0;int main(int argc, char con…

[工具]git克隆远程仓库到本地快速操作流程

一、新建空目录 二、初始化本地仓库 git init 初始化成功后&#xff0c;会在当前目录生成一个.git的目录。 三、关联远程仓库 git remote add origin <URL>这一步让本地仓库与远程仓库进行关联&#xff0c;origin是远程仓库的别名&#xff0c;可以自定义。 四、克隆…

机器学习之贝叶斯分类器和混淆矩阵可视化

贝叶斯分类器 目录 贝叶斯分类器1 贝叶斯分类器1.1 概念1.2算法理解1.3 算法导入1.4 函数 2 混淆矩阵可视化2.1 概念2.2 理解2.3 函数导入2.4 函数及参数2.5 绘制函数 3 实际预测3.1 数据及理解3.2 代码测试 1 贝叶斯分类器 1.1 概念 贝叶斯分类器是基于贝叶斯定理构建的分类…

基于phpstudy快速搭建本地php环境(Windows)

好好生活&#xff0c;别睡太晚&#xff0c;别爱太满&#xff0c;别想太多。 2025.1.07 声明 仅作为个人学习使用&#xff0c;仅供参考 对于CTF-Web手而言&#xff0c;本地PHP环境必不可少&#xff0c;但对于新手来说从下载PHP安装包到配置PHP环境是个非常繁琐的事情&#xff0…

张朝阳惊现CES展,为中国品牌 “代言”的同时,或将布局搜狐新战略!

每年年初&#xff0c;科技圈的目光都会聚焦在美国拉斯维加斯&#xff0c;因为这里将上演一场被誉为 “科技春晚” 的年度大戏 ——CES 国际消费电子展。作为全球规模最大、最具影响力的科技展会之一&#xff0c;CES 吸引了来自 160 多个国家的创新者和行业领导者&#xff0c;是…

Ollama VS LocalAI:本地大语言模型的深度对比与选择指南

随着人工智能技术的快速发展&#xff0c;大语言模型逐渐成为多个行业的重要工具。从生成内容到智能问答&#xff0c;大模型展现了强大的应用潜力。然而&#xff0c;云端模型的隐私性、使用成本和网络依赖等问题也促使更多用户关注本地化解决方案。Ollama 和 LocalAI 是近年来备…

【C++】B2101 计算矩阵边缘元素之和

博客主页&#xff1a; [小ᶻ☡꙳ᵃⁱᵍᶜ꙳] 本文专栏: C 文章目录 &#x1f4af;前言&#x1f4af;题目背景与描述题目描述输入格式输出格式输入输出样例说明与提示 &#x1f4af;分析与解决方案解法一&#xff1a;我的做法代码实现解题思路优点与局限性 解法二&#xff1…

保护性暂停原理

什么是保护性暂停&#xff1f; 保护性暂停&#xff08;Guarded Suspension&#xff09;是一种常见的线程同步设计模式&#xff0c;常用于解决 生产者-消费者问题 或其他需要等待条件满足后再继续执行的场景。通过这种模式&#xff0c;一个线程在执行过程中会检查某个条件是否满…

穷举vs暴搜vs深搜vs回溯vs剪枝系列一>字母大小写全排列

题目&#xff1a; 解析&#xff1a; 代码&#xff1a; private List<String> ret;private StringBuffer path;public List<String> letterCasePermutation(String s) {ret new ArrayList<>();path new StringBuffer();dfs(s,0);return ret;}private voi…

解决nginx多层代理后应用部署后访问发现css、js、图片等样式加载失败

一般是采用前后端分离部署方式&#xff0c;被上一层ng代理后&#xff0c;通过域名访问报错&#xff0c;例如&#xff1a;sqx.com.cn/应用代理路径。 修改nginx配置&#xff0c;配置前端页面的路径&#xff1a; location / {proxy_pass http://前端页面所在服务器的IP:PORT;pro…

前端-计算机网络篇

一.网络分类 1.按照网络的作用范围进行分类 &#xff08;1&#xff09;广域网WAN(Wide Area Network) 广域网的作用范围通常为几十到几千公里,因而有时也称为远程网&#xff08;long haul network&#xff09;。广域网是互联网的核心部分&#xff0c;其任务是长距离运送主机…

挑战20天刷完leecode100

2025.1.5 二分查找 1 搜索插入位置 就是简单的二分查找 注意开闭就行 这里有一句话就是nums是升序的 如果他不是严格递增 就是有相同的数字的情况下应该怎么写? int lower_bound(vector<int>& nums, int target) {int left 0, right (int) nums.size() - 1; …

Android原生开发同一局域网内利用socket通信进行数据传输

1、数据接收端代码如下&#xff0c;注意&#xff1a;socket 接收信息需要异步运行&#xff1a; // port 端口号自定义一个值&#xff0c;比如 8888&#xff0c;但需和发送端使用的端口号保持一致 ServerSocket serverSocket new ServerSocket(port); while (true) {//这里为了…

Linux 获取文本部分内容

Linux获取文本部分内容 前言场景获取前几行内容获取末尾几行内容获取中间内容head 命令 tail 命令 结合sed 命令awk 命令 前言 test.log 文本内容如下&#xff1a; &#xff08;注意&#xff1a;内容 a1004和a1005之间有一空行&#xff09; [rootgaussdb002 tmp]# cat test.…

常见的端口号大全,2025年整理

端口号是网络通信的基础&#xff0c;它定义了不同服务的入口和出口。了解服务端口号不仅有助于网络配置&#xff0c;还能提升问题排查效率。在实际应用中&#xff0c;熟悉常见端口号可以帮助你快速定位网络故障、优化服务性能&#xff0c;并确保网络安全。 一、常见的网络服务…

音视频入门基础:MPEG2-PS专题(6)——FFmpeg源码中,获取PS流的视频信息的实现

音视频入门基础&#xff1a;MPEG2-PS专题系列文章&#xff1a; 音视频入门基础&#xff1a;MPEG2-PS专题&#xff08;1&#xff09;——MPEG2-PS官方文档下载 音视频入门基础&#xff1a;MPEG2-PS专题&#xff08;2&#xff09;——使用FFmpeg命令生成ps文件 音视频入门基础…

【Arthas命令实践】heapdump实现原理

&#x1f3ae; 作者主页&#xff1a;点击 &#x1f381; 完整专栏和代码&#xff1a;点击 &#x1f3e1; 博客主页&#xff1a;点击 文章目录 使用原理 使用 dump java heap, 类似 jmap 命令的 heap dump 功能。 【dump 到指定文件】 heapdump arthas-output/dump.hprof【只 …

【JavaEE】—— SpringBoot项目集成百度千帆AI大模型(对话Chat V2)

本篇文章在SpringBoot项目中集成百度千帆提供的大模型接口实现Chat问答效果&#xff1a; 一、百度智能云 百度千帆大模型平台是百度智能云推出的一个企业级一站式大模型与AI原生应用开发及服务平台。 注册地址&#xff1a;https://qianfan.cloud.baidu.com/ 注册成功后&…