八大排序——冒泡排序/归并排序

八大排序——冒泡排序/归并排序

一、冒泡排序

1.1 冒泡排序

1.2 冒泡排序优化

二、归并排序

1.1 归并排序(递归)

1.2 递归排序(非递归)


一、冒泡排序

1.1 冒泡排序

比较相邻的元素。如果第一个比第二个大,就交换它们两个。

void Bubble_Sort(int arr[], int len) // 定义冒泡排序函数,参数为数组和数组长度
{// 外层循环控制排序的总趟数,从0开始,到len-1结束for (int i = 0; i < len - 1; i++){// 内层循环负责每一趟排序中的实际比较和交换操作// 从0开始,到len-i-1结束,因为每趟排序结束后,最大的元素会“冒泡”到最后,不需要再参与比较for (int j = 0; j + 1 < len - i; j++){// 比较相邻的两个元素if (arr[j] > arr[j + 1]){// 如果左边的元素大于右边的元素,说明它们的顺序错误,需要交换int tmp = arr[j]; // 使用临时变量tmp来保存arr[j]的值arr[j] = arr[j + 1]; // 将arr[j+1]的值赋给arr[j]arr[j + 1] = tmp; // 将tmp的值赋给arr[j+1],完成交换}}}
}
  • 外层循环 for (int i = 0; i < len - 1; i++):控制排序的总趟数。对于一个长度为 len 的数组,只需要进行 len - 1 趟排序就可以将整个数组排好序。每趟排序都会将当前未排序部分的最大元素 “冒泡” 到末尾。
  • 内层循环 for (int j = 0; j + 1 < len - i; j++):在每一趟排序中,负责对相邻元素进行比较和交换。随着外层循环的进行,每趟排序后最大的元素已经在正确的位置(数组末尾),所以下一趟排序时,不需要再对这些已经排好序的元素进行比较,因此内层循环的结束条件是 j + 1 < len - i
  • j + 1 表示当前要比较的两个相邻元素中右边元素的索引。因为是比较相邻元素,所以左边元素索引为 j,右边元素索引为 j + 1
 

 

1.2 冒泡排序优化

数据要是已经默认有序了,则后续的趟数就不排序了

问题:怎么得出已有数据是否有序?

解决方法:跑一趟,跑完了都没有一次数据交换发生,也就是说都是左边值小于右边值

void Bubble_Sort(int arr[], int len)
{bool tag = true;for (int i = 0; i < len - 1; i++)//控制趟数{//每一趟开始时把tag重新置位真tag = true;for (int j = 0; j + 1 < len - i; j++)//j指向比较一对数据中左边的值,右边用j+1{if (arr[j] > arr[j + 1]){int tmp = arr[j];arr[j ] = arr[j+1];arr[j + 1] = tmp;tag = false;}}if (tag)//tag还是真,那么就默认递增有序,直接退出{return;}}
}

时间复杂度位n^2  空间复杂度1

稳定值:稳定 俩个俩个比

二、归并排序

将长度为n的待排序序列,看作n个长度为1的有序组,然后进行合并,合并成n/2个长度为2的有序组,然后接着合并,直到所有的数据都合并到同一个组为止

1.1 归并排序(递归)

#include <stdio.h> // 引入标准输入输出头文件,用于使用 printf 和 scanf 函数
#include <stdlib.h> // 引入标准库头文件,用于使用内存分配函数 malloc 和 exit 函数
#include <string.h> // 引入字符串操作头文件,用于使用 memset 函数// 函数声明,用于在主函数之后定义,显示排序后的数组
void Show(int arr[], int len);// 合并两个有序子数组到临时数组 brr 中,然后再复制回原数组 arr
void Merge(int arr[], int len, int left, int mid, int right, int* brr) {int i = left; // 初始化指针 i 指向左边子数组的起始位置int j = mid + 1; // 初始化指针 j 指向右边子数组的起始位置int k = left; // 初始化指针 k 指向临时数组 brr 的起始位置while (i <= mid && j <= right) { // 当两个子数组中都有元素时if (arr[i] <= arr[j]) { // 如果左边的元素小于等于右边的元素brr[k] = arr[i]; // 将左边的元素放入临时数组 brri++; // 左边子数组的指针后移k++; // 临时数组的指针后移} else { // 如果左边的元素大于右边的元素brr[k] = arr[j]; // 将右边的元素放入临时数组 brrj++; // 右边子数组的指针后移k++; // 临时数组的指针后移}}while (j <= right) { // 复制右边子数组中剩余的元素brr[k++] = arr[j++];}while (i <= mid) { // 复制左边子数组中剩余的元素brr[k++] = arr[i++];}for (int i = left; i <= right; i++) { // 将合并后的有序数组复制回原数组 arrarr[i] = brr[i];}
}// 递归地将数组分成两半,并对每一半进行排序,然后合并
void Divide(int arr[], int len, int left, int right, int* brr) {if (left < right) { // 如果左边界小于右边界,则继续递归int mid = (left + right) / 2; // 计算中间索引Divide(arr, len, left, mid, brr); // 对左半部分递归调用 Divide 函数Divide(arr, len, mid + 1, right, brr); // 对右半部分递归调用 Divide 函数Merge(arr, len, left, mid, right, brr); // 合并两个有序子数组}
}// 归并排序的入口函数
void Merge_Sort(int arr[], int len) {int* brr = (int*)malloc(len * sizeof(int)); // 动态分配一个临时数组 brr,用于合并时存放数据if (brr == NULL) { // 如果内存分配失败fprintf(stderr, "Memory allocation failed\n"); // 打印错误信息到标准错误输出exit(EXIT_FAILURE); // 退出程序}Divide(arr, len, 0, len - 1, brr); // 从数组的起始索引到结束索引进行递归排序free(brr); // 释放临时数组 brr 的内存
}// 显示数组内容的函数
void Show(int arr[], int len) {for (int i = 0; i < len; i++) { // 遍历数组printf("%d ", arr[i]); // 打印数组的每个元素}printf("\n"); // 打印换行符
}int main() {int arr[] = {122, 222, 11, 357, 333, 12, 111, 789, 654, 356}; // 初始化一个待排序的数组int len = sizeof(arr) / sizeof(arr[0]); // 计算数组的长度Merge_Sort(arr, len); // 调用归并排序函数对数组进行排序Show(arr, len); // 显示排序后的数组return 0; // 程序正常结束,返回 0
}

1.2 递归排序(非递归)

#include <stdio.h>
#include <stdlib.h>// 函数声明,用于显示排序后的数组
void Show(int arr[], int len);// 合并两个有序子数组到临时数组brr中,然后再复制回原数组arr
void Merge(int arr[], int len, int left, int mid, int right, int* brr)
{int i = left;int j = mid + 1;int k = left;while (i <= mid && j <= right){if (arr[i] <= arr[j]){brr[k] = arr[i];i++;k++;}else{brr[k] = arr[j];j++;k++;}}while (j <= right){brr[k++] = arr[j++];}while (i <= mid){brr[k++] = arr[i++];}for (int i = left; i <= right; i++){arr[i] = brr[i];}
}// 非递归的分治函数
//gap是当前子数组的长度
void Merge_No_Recursion(int arr[], int len, int gap, int* brr)
{int left1 = 0;int right1 = left1 + gap - 1;int left2 = right1 + 1;int right2 = left2 + gap - 1 < len ? left2 + gap - 1 : len - 1;int k = 0;while (left2 < len){int i = left1;int j = left2;while (i <= right1 && j <= right2){if (arr[i] <= arr[j]){brr[k] = arr[i];i++;k++;}else{brr[k] = arr[j];j++;k++;}}while (j <= right2){brr[k++] = arr[j++];}while (i <= right1){brr[k++] = arr[i++];}left1 = right2 + 1;right1 = left1 + gap - 1;left2 = right1 + 1;right2 = left2 + gap - 1 < len ? left2 + gap - 1 : len - 1;}while (left1 < len){brr[k++] = arr[left1++];}for (int i = 0; i < len; i++){arr[i] = brr[i];}
}// 归并排序的非递归版本
void Merge_Sort_No_Recursion(int arr[], int len)
{int* brr = (int*)malloc(len * sizeof(int));if (brr == NULL)exit(EXIT_FAILURE);for (int gap = 1; gap < len; gap *= 2 ){Merge_No_Recursion(arr, len, gap, brr);}free(brr);
}// 显示数组的函数
void Show(int arr[], int len) {for (int i = 0; i < len; i++) {printf("%d ", arr[i]);}printf("\n");
}int main() {int arr[] = { 120000, 230000, -100, 195, 71, 89, 42, 8, 902, 894, 194, 80, 194, 128, 90, 18, 490, 18, 409, 180, 95, 12, 489, 404 };int len = sizeof(arr) / sizeof(arr[0]);Merge_Sort_No_Recursion(arr, len);Show(arr, len);return 0;
}

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

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

相关文章

区块链随学随记

前情提要&#xff1a;本人技术栈为ganachehardhatpython ganache提供的是本地的区块链环境&#xff0c;相当于模拟以太坊&#xff0c;这样可以允许多个账户在本机交互。hardhat和remix都是区块链ide&#xff0c;用于编写和部署合约助记词有个数规定&#xff0c;只有满足这些个数…

Android原生开发基础

Android实战 Android 原生开发基础 知识点1 介绍了解2 系统体系架构3 四大应用组件4 移动操作系统优缺点5 开发工具6 配置工具7 下载相关资源8JDK下载安装流程9配置好SDK和JDK环境10 第一个Hello word11 AS开发前常用设置12模拟器使用运行13 真机调试14 AndroidUI基础布局15 加…

网页版 deepseek 对话问答内容导出为 PDF 文件和 Word 文件的浏览器插件下载安装和使用说明

文章目录 网页版 deepseek 浏览器扩展应用程序插件1. 预览效果2. 功能介绍3. 浏览器扩展应用程序下载3.1. 下载方式13.2. 下载方式24. 安装教程4.1. Chrome 浏览器安装步骤4.2. Edge 浏览器安装步骤5. 使用说明网页版 deepseek 浏览器扩展应用程序插件 1. 预览效果 预览效果 导…

DBdriver使用taos数据库

首先创建连接 连接后比如数据库里有三个库 选择其中的hypon 选中localhost&#xff0c;右键sql编辑器&#xff0c;打开sql控制台 就插入了一条数据

【前端】【面试】如何实现图片渐进式加载?有几种方法

前端图片渐进式加载 一、技术原理解析 渐进式加载是通过分阶段、按需加载图片&#xff0c;以提升用户体验和页面性能的优化技术。主要包括以下实现方式&#xff1a; 懒加载&#xff1a;基于IntersectionObserver API&#xff0c;当图片进入浏览器视口时才发起加载请求&#…

Spring Boot 中的条件注解

Spring Boot条件注解的汇总&#xff1a; 注解作用判断依据使用场景ConditionalOnBean容器中存在指定Bean时&#xff0c;被注解的配置或Bean定义生效指定Bean在容器中存在依赖其他已存在Bean时配置相关功能ConditionalOnCheckpointRestore在特定检查点恢复相关条件满足时生效满…

leetcode11-盛水最多的容器

leetcode 11 思路 问题分析 拆解问题&#xff0c;面积 底 * 高 宽度&#xff1a;两个竖直线之间的距离&#xff0c;显然是 right - left高度&#xff1a;容器的水位受限于较短的那根竖直线的高度&#xff0c;所以高度为 min(height[left], height[right]) 本题其实很容易…

HTTP:十二.HTTPS

HTTPS 概述 超文本传输安全协议(英语:HyperText Transfer Protocol Secure,缩写:HTTPS;常称为HTTP over TLS、HTTP over SSL或HTTP Secure)是一种通过计算机网络进行安全通信的传输协议。HTTPS经由HTTP进行通信,利用TLS加密数据包。 HTTPS的主要目的是提供对网站服务器…

MySQL数据库(14)—— 使用C操作MySQL

目录 一&#xff0c;下载库 二&#xff0c;安装库 三&#xff0c;使用库 3.1 连接数据库 3.2 发送SQL 3.3 获取结果 问题&#xff1a;为什么不使用C&#xff1f; 解答&#xff1a;使用C的库已经可以完成绝大部分MySQL操作了&#xff0c;并且C的库的使用更加复杂&#xff…

Redis故障防御体系:构建七层免疫系统的设计哲学

当Redis遭遇写入阻塞或服务崩溃时&#xff0c;本质上是系统边界的多重防御机制被击穿。本文摒弃碎片化的解决方案&#xff0c;从系统工程的全局视角&#xff0c;构建七层递进式防御体系&#xff0c;揭示高可用架构的深层设计逻辑。 第一层&#xff1a;动态资源调度 —— 内存的…

在线文本客服系统核心功能解析

在线文本客服系统核心功能解析 在互联网大厂的Java求职者面试中&#xff0c;经常会被问到关于在线文本客服系统的实现和设计。本文通过一个故事场景来展示这些问题的实际解决方案。 第一轮提问 面试官&#xff1a;马架构&#xff0c;欢迎来到我们公司的面试现场。请问您对在…

学成在线。。。

一:讲师管理 介绍:可以实现对讲师的分页展示,多条件组合分页查询,对讲师的添加,修改,删除操作。 针对于添加来说,使用requestBody注解,搭配postmapping接收数据,使用service层的对象,调用mapper方法,向数据库中保存数据。 修改: 先根据讲师id,查询出讲师,再去…

Webug3.0通关笔记17 中级进阶(第01-05关)

目录 第一关 出来点东西吧 1.打开靶场 2.源码分析 3.源码修正 4.文件包含漏洞渗透 第二关 提交方式是怎样的啊&#xff1f; 1.打开靶场 2.源码分析 3.渗透实战 &#xff08;1&#xff09;bp改包法 &#xff08;2&#xff09;POST法渗透 第三关 我还是一个注入 1.打开…

C语言复习笔记--内存函数

在复习完字符函数和字符串函数之后,今天让我们复习一下内存函数吧.这一块的东西不太多,并且与之前的字符串函数有一些地方很相似,所以这里应该会比较轻松. memcpy使用和模拟实现 老规矩,先看函数原型 void * memcpy ( void * destination, const void * source, size_t num );…

【Unity AR开发插件】一、高效热更新:Unity AR 插件结合 HybridCLR 与 ARFoundation 的开源仓库分享

摘要 本篇博客详细介绍了我基于 HybridCLR 与 AR Foundation 的 Unity AR 开发插件&#xff0c;旨在为开发者提供高效的跨平台热更新方案。文章从背景与动机出发&#xff0c;覆盖一键安装工具、环境配置、热更新数据制作与示例程序运行等核心模块&#xff0c;并展示代码结构与使…

数据分析(四):Python Pandas数据输入输出全流程指南

Python Pandas数据输入输出全流程指南 1. 引言 数据输入输出(I/O)是数据分析工作流中最基础也是最重要的环节之一。Pandas提供了丰富的数据读写接口&#xff0c;支持从各种文件格式和数据库中加载数据&#xff0c;以及将处理后的数据保存到不同存储系统中。本文将全面介绍Pan…

人工智能与机器学习:Python从零实现性回归模型

🧠 向所有学习者致敬! “学习不是装满一桶水,而是点燃一把火。” —— 叶芝 我的博客主页: https://lizheng.blog.csdn.net 🌐 欢迎点击加入AI人工智能社区! 🚀 让我们一起努力,共创AI未来! 🚀 前言 在 AI 的热潮中,很容易忽视那些让它得以实现的基础数学和技…

Ubuntu18.04更改时区(图文详解)

Ubuntu18.04更改时区 1、前言2、更改时区3、总结 1、前言 记录一下Ubuntu18.04更改时区的过程&#xff0c;方便自己日后回顾&#xff0c;也可以给有需要的人提供帮助。 2、更改时区 输入下面的指令&#xff0c;进行时区选择 tzselect输入4选择亚洲&#xff0c;输入9选择中…

vue2 项目使用vite2 升级 vite4 后,对别名的解析有问题,导致打包后项目无法正常运行

问题描述&#xff1a; 之前使用的 vite2 版本&#xff0c;需要在 vite.config 里配置 vue 别名&#xff0c;不然会有commonjs 的依赖包找不到 vue&#xff0c;因为 vite 默认使用 esm 版本。 vue: vue/dist/vue.common.prod.js 在 vite2 中可以正常进行打包上线&#xff0c;…

民办生从零学C的第十二天:指针(1)

每日励志&#xff1a;拼搏十年&#xff0c;征战沙场&#xff0c;不忘初心&#xff0c;努力成为一个浑身充满铜臭味的有钱人。 一.内存和地址 1.内存 计算机内存是一系列存储单元的集合&#xff0c;每个存储单元都有唯一的地址来标识。这些存储单元用于存储程序的数据和指令。…