有关排序的算法

目录

选择法排序

冒泡法排序

qsort排序(快速排序)

qsort排序整型

qsort排序结构体类型


排序是我们日常生活中比较常见的问题,这里我们来说叨几个排序的算法。

比如有一个一维数组 arr[8] ={2,5,3,1,7,6,4,8},我们想要把它排成升序,我们通过下面这几种不同的方式来进行排序!

选择法排序

这一种排序方式,首先第一轮认为第一个元素是最小的,把它的下标用 flag 记下来,不断与后面的元素进行比较,如果后面的元素有比它小的,就把 flag 改成比它小的元素下标,直到把整个数组下标遍历完,如果flag不等于最开始的下标就进行交换,这样就可以得到最小的那个数在第一位,依此类推,第二轮找到第二小的数字放在第二位,第三轮找到第三小的数字放在第三位……

当第七轮的时候已经找到了找到第七小的数字放在第七位,显然最后一位是最大的数字,所以一共进行七次就好了!

代码如下:

//选择法排序
#include<stdio.h>
int main()
{
	int arr[8] = { 2,5,3,1,7,6,4,8 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	int i = 0;
	int j = 0;
	int flag = 0;
	printf("排序前:\n");
	for (i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}
	for (i = 0; i < sz - 1; i++)
	{
		flag = i;
		for (j = i + 1; j < sz; j++)
		{
			if (arr[j] < arr[flag])
				flag = j;
			//如果后面的元素比flag为坐标的元素小,就把flag改成较小元素的坐标
		}
		if (flag != i)
		{
			int temp = arr[i];
			arr[i] = arr[flag];
			arr[flag] = temp
		}
	}
	printf("\n排序后:\n");
	for (i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}
	return 0;
}


当然,在学习了指针的基础上,我们可以把排序代码分装成函数的形式


#include<stdio.h>
void Print_arr(int* arr, int sz)
{
	for (int i = 0; i < sz; i++)
		printf("%d ", arr[i]);
}
void Choose_sort(int* arr, int sz)
{
	int flag = 0;
	for (int i = 0; i < sz - 1; i++)
	{
		flag = i;
		for (int j = i + 1; j < sz; j++)
		{
			if (arr[j] < arr[flag])
				flag = j;
		}
		if (flag != i)
		{
			int temp = arr[i];
			arr[i] = arr[flag];
			arr[flag] = temp;
		}
	}
}
int main()
{
	int arr[8] = { 2,5,3,1,7,6,4,8 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	printf("排序前:\n");
	Print_arr(arr, sz);
	Choose_sort(arr, sz);
	printf("\n排序后:\n");
	Print_arr(arr, sz);
	return 0;
}



冒泡法排序

这个与选择法排序有点相似,它的核⼼思想是两两相邻的元素进⾏⽐较,如果后面的元素比前面小,那么就立刻进行交换,第一轮最终会把最大的元素放在最后一位,依次往后面推进,在第七轮的时候,第二小的就在第二位了,所以只需要7趟就好了,每一趟就会找到一个元素放在相应的位置,所以每一趟比较的数组元素也会依次减1.

代码如下:


//冒泡排序
#include<stdio.h>
int main()
{
	int arr[8] = { 2,5,3,1,7,6,4,8 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	int i = 0;
	int j = 0;
	printf("排序前:\n");
	for (i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}
	for (i = 0; i < sz - 1; i++)
	{
		//i代表趟数
		for (j = 0 ; j < sz - 1 - i; j++)
		{
			//访问数组元素两两比较
			if ( arr[j+1]<arr[j])
			{
				int temp = arr[j];
				arr[j] = arr[j+1];
				arr[j+1] = temp;
			}		
		}	
	}
	printf("\n排序后:\n");
	for (i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}
	return 0;
}

我们也可以把排序代码分装成函数的形式:

#include<stdio.h>
void Print_arr(int* arr, int sz)
{
	for (int i = 0; i < sz; i++)
		printf("%d ", arr[i]);
}
void Bubble_sort(int* arr, int sz)
{
	int i = 0;
	int j = 0;
	for (i = 0; i < sz - 1; i++)
	{
		for (j = 0; j < sz - 1 - i; j++)
		{
			if (*(arr+j+1) < *(arr+j))
			{
				int temp = *(arr + j + 1);
				*(arr + j + 1) = *(arr + j);
				*(arr + j) = temp;
			}
			/*if (arr[j + 1] < arr[j])
			{
				int temp = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = temp;
			}*/
		}
	}
}
int main()
{
	int arr[8] = { 2,5,3,1,7,6,4,8 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	printf("排序前:\n");
	Print_arr(arr, sz);
	Bubble_sort(arr, sz);
	printf("\n排序后:\n");
	Print_arr(arr, sz);
	return 0;
}



我们来考虑一个问题,如果一个数组元素已经有序了,事实上,我们可以不用再进行排序了,那么应该怎么优化这个排序代码呢?

#include<stdio.h>
void Print_arr(int* arr, int sz)
{
	for (int i = 0; i < sz; i++)
		printf("%d ", arr[i]);
}
void Bubble_sort(int* arr, int sz)
{
	int i = 0;
	int j = 0;
	for (i = 0; i < sz - 1; i++)
	{
		int flag = 1;//最开始就假设有序
		for (j = 0; j < sz - 1 - i; j++)
		{
			if (*(arr + j + 1) < *(arr + j))
			{
				flag = 0;//进来就说明还没有有序,让flag=0
				int temp = *(arr + j + 1);
				*(arr + j + 1) = *(arr + j);
				*(arr + j) = temp;
			}
		}
		if (flag == 1)//一趟下来flag=1,说明没有机会让flag=0,已经有序
		{
			printf("\n已经有序!\n");
			break;
		}
	}
}
int main()
{
	int arr[8] = { 1,2,3,4,5,6,7,8 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	printf("排序前:\n");
	Print_arr(arr, sz);
	Bubble_sort(arr, sz);
	printf("\n排序后:\n");
	Print_arr(arr, sz);
	return 0;
}



这里我们就可以使用一个flag来进行标记,flag=1,就说明已经有序,跳出循环,当一个数组已经已经有序或者接近有序的时候就可以减少运算次数

qsort排序(快速排序)

想要使用qsort函数呢?我们就需要先对这个函数进行一定的了解。

打开cplusplus网站,我们可以找到相关信息:

qsort(quick sort)事实上是C语言中的一个库函数,底层使用的是快速排序的思想,

并且对任意类型数据都可以进行排序

我们来看看每一个参数

base:指向需要排序数组的首元素地址(指针)

num:base指向数组中的元素个数

size:bas指向的数组中一个元素的字节大小

compar:函数指针,传递函数的地址

compar应该设计成下面这个样子,同时它的返回值也有要求

 
int compar (const void* p1, const void* p2);

当p1指向的元素小于p2指向的元素时,返回一个小于0的数字

当p1指向的元素等于p2指向的元素时,返回0

当p1指向的元素大于p2指向的元素时,返回一个大于0的数字

qsort排序整型

//测试qsort排序整型

#include<stdio.h>
#include<stdlib.h>
void Print_arr(int* arr, int sz)
{
	for (int i = 0; i < sz; i++)
		printf("%d ", arr[i]);
}
int cmp_int(const void* p1, const void* p2)
{
	if (*(int*)p1 > *(int*)p2)
	{
		return 1;
	}
	//知道比较整型,强制类型转换为整型,然后解引用
	else if (*(int*)p1 < *(int*)p2)
	{
		return -1;
	}
	else
	{
		return 0;
	}
}
int main()
{
	int arr[8] = { 2,5,3,1,7,6,4,8 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	printf("排序前:\n");
	Print_arr(arr, sz);
	qsort(arr, sz, sizeof(arr[0]), cmp_int);
	printf("\n排序后:\n");
	Print_arr(arr, sz);
	return 0;
}

我们可以看见qsort进行了很好的排序,当然这里因为它的规则是

当p1指向的元素小于p2指向的元素时,返回一个小于0的数字

当p1指向的元素等于p2指向的元素时,返回0

当p1指向的元素大于p2指向的元素时,返回一个大于0的数字

所以我们可以把return语句直接写成:

return *((int*)p1) - *((int*)p2);

#include<stdio.h>
#include<stdlib.h>
void Print_arr(int* arr, int sz)
{
	for (int i = 0; i < sz; i++)
		printf("%d ", arr[i]);
}
int cmp_int(const void* p1, const void* p2)
{
	//return *((int*)p1) - *((int*)p2);//默认升序
	//知道比较整型,强制类型转换为整型,然后解引用
	return *((int*)p2) - *((int*)p1); // 降序
}
int main()
{
	int arr[8] = { 2,5,3,1,7,6,4,8 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	printf("排序前:\n");
	Print_arr(arr, sz);
	qsort(arr, sz, sizeof(arr[0]), cmp_int);
	printf("\n排序后:\n");
	Print_arr(arr, sz);
	return 0;
}


使用qsort默认是升序,如果想要降序,交换p1,p2的位置就可以了,比如上面的代码就可以实现降序。

qsort排序结构体类型

//qsort排序结构体类型
#include<stdio.h>
#include<stdlib.h>//qsort头文件
#include<string.h>//strcmp头文件
struct Student
{
	char name[20];
	int age;
};
void Print_arr(struct Student* arr, int sz)
{
	for (int i = 0; i < sz; i++)
		printf("%s %d\n", arr[i].name, arr[i].age);
}
int cmp_student_by_name(const void* p1, const void* p2)
{
	return strcmp(((struct Student*)p1)->name, ((struct Student*)p2)->name);
	//strcmp比较字符串,比较第一个不同字符的ASCII值
}
int main()
{
	struct Student arr[3] = { {"lihua",18},{"balla",56},{"guna",23} };
	//结构体数组
	int sz = sizeof(arr) / sizeof(arr[0]);
	printf("排序前:\n");
	Print_arr(arr, sz);
	qsort(arr, sz, sizeof(arr[0]), cmp_student_by_name);
	printf("\n排序后:\n");
	Print_arr(arr, sz);
	return 0;
}

这里依然是比较的时候强制类型转换为结构体类型,使用了结构体访问操作符【->】特殊的是比较字符串需要使用strcmp函数,不清楚的可以看看【数组的使用】那一篇博客对strcmp进行详细讲解。

我们也可以通过年龄来比较,代码如下:

#include<stdio.h>
#include<stdlib.h>//qsort头文件
//#include<string.h>//strcmp头文件
struct Student
{
	char name[20];
	int age;
};
void Print_arr(struct Student* arr, int sz)
{
	for (int i = 0; i < sz; i++)
		printf("%s %d\n", arr[i].name, arr[i].age);
}
int cmp_student_by_age(const void* p1, const void* p2)
{
	return (((struct Student*)p1)->age - ((struct Student*)p2)->age);
}
int main()
{
	struct Student arr[3] = { {"lihua",18},{"balla",56},{"guna",23} };
	//结构体数组
	int sz = sizeof(arr) / sizeof(arr[0]);
	printf("排序前:\n");
	Print_arr(arr, sz);
	qsort(arr, sz, sizeof(arr[0]), cmp_student_by_age);
	printf("\n排序后:\n");
	Print_arr(arr, sz);
	return 0;
}


当然排序算法永远不止于此,还有更多的内容等待着我们去发现,去应用。

加油吧!未来的顶尖程序员们!!!!

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

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

相关文章

【MAVEN学习 | 第1篇】Maven介绍与安装

文章目录 前言 一. Maven主要作用1.1 依赖管理1.2 项目构建 二. Maven安装和配置2.1 安装2.2 配置环境变量2.3 命令测试2.4 配置文件&#xff08;1&#xff09;依赖本地缓存位置&#xff08;本地仓库位置&#xff09;&#xff08;2&#xff09;配置国内阿里镜像&#xff08;3&a…

logback-spring.xml 小记

为什么不用logback.xml 名字 加载顺序:logback.xml>application.yml>logback-spring.xml 使用xml中使用到配置文件属性时,就会报错 为什么logback中记录不到运行时报错 logback获取不到堆栈错误 解决办法:在全局错误出使用log.error()指定输出 为什么打印不出来myba…

【面试实战】# 并发编程之线程池配置实战

1.先了解线程池的几个参数含义 corePoolSize (核心线程池大小): 作用: 指定了线程池维护的核心线程数量&#xff0c;即使这些线程处于空闲状态&#xff0c;它们也不会被回收。用途: 核心线程用于处理长期的任务&#xff0c;保持最低的线程数量&#xff0c;以减少线程的创建和…

【html】爱心跳动动画:CSS魔法背后的故事

效果展示&#xff1a; 代码介绍&#xff1a; 爱心跳动动画&#xff1a;CSS魔法背后的故事 在前端开发中&#xff0c;CSS不仅仅是一种用于控制网页样式的工具&#xff0c;它也是一种表达创意和想象力的艺术手段。今天&#xff0c;我要为大家介绍一段使用CSS实现的爱心跳动动画…

【计算方法】对分区间套解非线性方程

废话少说&#xff0c;直接上干货。 #include <stdio.h> #include <math.h>float f(float x) {// 函数return x*x*x - x - 1; }float root(float x1, float x2) {float mid, fmid;float e 1e-6;while ((x2 - x1) > e) {mid (x1 x2) / 2;fmid f(mid);// 判断中…

Android断点续传原理及实现

常见两种网络请求方式 一、 HttpURLConnection HttpURLConnection的setRequestProperty()方法&#xff0c;对我们要读取的字节部分进行控制&#xff0c;比如: 1.Range0-100代表只读取前100个字节。 2.Range100-500代表读取从第100个字节开始&#xff0c;读到第500个字节为止。…

从理论到实践掌握UML

统一建模语言&#xff08;UML&#xff09;是软件工程师用来设计软件系统的一种工具&#xff0c;就像是一套图形化的说明书。它让开发团队能够以图形化的方式来理解、设计和开发软件系统&#xff0c;比起用文字来描述&#xff0c;更加直观易懂。本文通过UML实例化的理论和实践相…

【漏洞复现】蓝凌EIS api.aspx 任意文件上传漏洞

免责声明&#xff1a; 本文内容旨在提供有关特定漏洞或安全漏洞的信息&#xff0c;以帮助用户更好地了解可能存在的风险。公布此类信息的目的在于促进网络安全意识和技术进步&#xff0c;并非出于任何恶意目的。阅读者应该明白&#xff0c;在利用本文提到的漏洞信息或进行相关测…

指针的深入理解(3)(包括数组名的理解、一维数组传参的本质以及指针数组的相关知识及使用)

文章目录 1 数组名的理解2 使用指针访问数组3 一维数组传参的本质4 指针数组5 指针数组的使用 1 数组名的理解 当我们运行以下代码&#xff1a; #include <stdio.h> int main() {int arr[10] { 0 };printf("%p\n", &arr[0]);printf("%p\n", a…

矩阵中严格递增的单元格数

class Solution { public:int maxIncreasingCells(vector<vector<int>>& mat) {int m mat.size(), n mat[0].size();// 开辟用来记录每个值对应的位置&#xff08;i,j&#xff09;map<int, vector<pair<int, int>>> mp;vector<int> …

收银系统源码-千呼新零售2.0【线下促销】

千呼新零售2.0系统是零售行业连锁店一体化收银系统&#xff0c;包括线下收银线上商城连锁店管理ERP管理商品管理供应商管理会员营销等功能为一体&#xff0c;线上线下数据全部打通。 适用于商超、便利店、水果、生鲜、母婴、服装、零食、百货等连锁店使用。 详细介绍请查看下…

文件重命名 一键批量重命名10万+文件 简单效率高!

单个文件重命名大家应该都会操作&#xff0c;但是有一些人由于工作的场景等的情况&#xff0c;需要做大量的文件重命名&#xff0c;比如影楼、电商、仓库管理、图片处理等各种行业&#xff0c;都经常需要把一批文件&#xff0c;按一定的格式和规律给文件重命名。 一、批量文件重…

创建Docker容器与外部机通信(独立IP的方式)

需求&#xff1a;希望外部可以直接通过不同IP地址访问宿主机上的Docker容器&#xff0c;而不需要端口映射&#xff08;同一个IP不同的端口与外部通讯&#xff09;&#xff0c;这通常涉及到在宿主机的网络层面进行更高级的配置&#xff0c;比如使用IP伪装&#xff08;IP masquer…

HTML李峋同款跳动的爱心代码(双爱心版)

目录 写在前面 跳动的爱心 完整代码 代码分析 系列推荐 最后想说 写在前面 在浩瀚的网络世界中&#xff0c;总有一些小惊喜能触动我们的心弦。今天&#xff0c;就让我们用HTML语言&#xff0c;探索既神秘又浪漫的李峋同款跳动的爱心代码吧。 首先&#xff0c;让我们一起…

Linux系统编程——进程信号

目录 一&#xff0c;信号预备 1.1 生活中的信号 1.2 技术应用中的信号 1.3 signal函数捕捉信号 1.3 信号的发送与记录 1.4 信号的常见处理方式 二&#xff0c;信号的产生 2.1 核心转储 2.1.1 环境配置 2.1.2 利用core文件进行调试 2.1.3 core dump标志 2.2 通过系统…

【C语言】解决C语言报错:Null Pointer Dereference

文章目录 简介什么是Null Pointer DereferenceNull Pointer Dereference的常见原因如何检测和调试Null Pointer Dereference解决Null Pointer Dereference的最佳实践详细实例解析示例1&#xff1a;未初始化的指针示例2&#xff1a;释放内存后未将指针置为NULL示例3&#xff1a;…

STM32HAL库--NVIC和EXTI

1. 外部中断实验 1.1 NVIC和EXTI简介 1.1.1 NVIC简介 NVIC 即嵌套向量中断控制器&#xff0c;全称 Nested vectored interrupt controller。是ARM Cortex-M处理器中用于管理中断的重要组件。负责处理中断请求&#xff0c;分配优先级&#xff0c;并协调中断的触发和响应。 它是…

【会议征稿,IEEE出版】第四届电气工程与机电一体化技术国际学术会议(ICEEMT 2024,7月5-7)

第四届电气工程与机电一体化技术国际学术会议&#xff08;ICEEMT 2024&#xff09;定于2024年7月5-7日在浙江省杭州市隆重举行 。会议主要围绕“电气工程”、“机电一体化” 等研究领域展开讨论&#xff0c;旨在为电气工程、机电一体化等领域的专家学者、工程技术人员、技术研发…

STM32项目分享:智慧农业(机智云)系统

目录 一、前言 二、项目简介 1.功能详解 2.主要器件 三、原理图设计 四、PCB硬件设计 1.PCB图 2.PCB板打样焊接图 五、程序设计 六、实验效果 七、资料内容 项目分享 一、前言 项目成品图片&#xff1a; 哔哩哔哩视频链接&#xff1a; https://www.bilibili.c…

如何灵活运用keil工具进行问题分析(2)— 定位FreeRTOS的栈溢出导致hardfault问题

前言 &#xff08;1&#xff09;如果有嵌入式企业需要招聘湖南区域日常实习生&#xff0c;任何区域的暑假Linux驱动实习岗位&#xff0c;可C站直接私聊&#xff0c;或者邮件&#xff1a;zhangyixu02gmail.com&#xff0c;此消息至2025年1月1日前均有效 &#xff08;2&#xff0…