C++:排序算法
目录
一、插入排序
1.直接插入排序
2.希尔排序
二、交换排序
1.冒泡排序
2.快速排序
三、选择排序
1.简单选择排序
2.堆排序
四、归并排序
1.二路归并排序的递归实现
2.二路归并排序的非递归实现
一、插入排序
1.直接插入排序
直接插入排序的基本思想是:依次将待排序序列中的每一个记录插入到已排好序的序列中,直到全部记录都排好序。(记录就是排序问题中的数据元素)
平均时间复杂度为O(n^2)。
直接插入排序是一种稳定的排序方法。
待排序记录基本有序时,直接插入排序的效率很高。
vector<int> nums = { 5,0,1,2,7,3,9,6,4,8 }; //待排序序列for (int i = 1; i < nums.size(); i++) //将第1个记录当作有序序列,从第2个记录开始执行插入操作
{int temp = nums[i]; //暂存当前记录,当前记录之前都是有序的int j;for (j = i - 1; j >= 0 && temp < nums[j]; j--) //从后往前遍历有序序列{nums[j + 1] = nums[j]; //记录后移1位}nums[j + 1] = temp; //插入记录
}
2.希尔排序
希尔排序(Shell sort)是对直接插入排序的一种改进,当待排序列基本有序以及待排序记录个数较少时,直接插入排序的效率都很高,于是将序列分割以及让序列向基本有序发展。
希尔排序的基本思想是:先将整个待排序序列分割成若干个子序列,在子序列内分别进行直接插入排序。
时间复杂度为O(nlog2n)~O(n^2)。(前一个2为底数)
由于在希尔排序过程中记录是跳跃移动的,因此希尔排序是不稳定的。
vector<int> nums = { 5,0,1,2,7,3,9,6,4,8 }; //待排序序列for (int d = nums.size() / 2; d >= 1; d = d / 2) //以增量d来分割子序列并进行直接插入排序//最后一趟排序时d=1,即不分割,此时序列已基本有序
{for (int i = d; i < nums.size(); i++) //从这里开始类似于直接插入排序{int temp = nums[i]; //暂存待排序记录int j;for (j = i - d; j >= 0 && temp < nums[j]; j -= d){nums[j + d] = nums[j]; //记录后移d位}nums[j + d] = temp; //插入记录}
}
二、交换排序
1.冒泡排序
冒泡排序(bubble sort)的基本思想是:两两比较相邻记录,如果反序则交换,直到没有反序的记录为止。每趟排序都将使得序列的右边多一个有序记录。
平均时间复杂度为O(n^2)。
冒泡排序是稳定的排序方法。
vector<int> nums = { 5,0,1,2,7,3,9,6,4,8 }; //待排序序列for (int i = 0; i < nums.size() - 1; i++) //只需排n-1趟
{for (int j = 0; j < nums.size() - 1 - i; j++) //遍历无序序列{if (nums[j] > nums[j + 1]) //若反序,则交换{int temp = nums[j];nums[j] = nums[j + 1];nums[j + 1] = temp;}}
}
2.快速排序
快速排序(quick sort)是对冒泡排序的一种改进,减少了总的比较次数和移动次数。
快速排序的基本思想是:选定一个轴值(pivot,即比较的基准),将待排序记录划分成两部分,左侧记录均小于或等于轴值,右侧记录均大于或等于轴值,然后分别对这两部分重复上述过程,直到整个序列有序。可以直接选择第一个记录作为轴值。
平均时间复杂度是O(nlog2n)。(2为底数)
快速排序是不稳定的排序。
快速排序的平均时间性能是迄今为止所有内排序算法中最好的,因此得到广泛应用。
vector<int> nums = { 5,0,1,2,7,3,9,6,4,8 }; //待排序序列/*作一次划分,参数是被划分的序列的左右下标*/
int partition(int left, int right)
{int i = left, j = right;while (i < j) //多次左、右侧扫描{while (i < j && nums[i] <= nums[j]) //j指向比i所指的数还小的数(右侧扫描){j--;}if (i < j) //若i还在j左边,交换两数,即把较大者往右放{int temp = nums[i];nums[i] = nums[j];nums[j] = temp;i++;}while (i < j && nums[i] <= nums[j]) //i指向比j所指的数还大的数(左侧扫描){i++;}if (i < j) //若i还在j左边,交换两数,即把较大者往右放{int temp = nums[i];nums[i] = nums[j];nums[j] = temp;j--;}}return i; //此时i=j,已划分完毕(i的左边全小于它,右边全大于它)
}/*快速排序函数,递归执行,参数是待排序序列的左右下标*/
void quick_sort(int left, int right)
{if (left >= right) //子序列只剩一个记录,无需再排{return;}else{int pivot = partition(left, right); //作一次划分quick_sort(left, pivot - 1); //对左侧子序列进行快速排序quick_sort(pivot + 1, right); //对右侧子序列进行快速排序}
}quick_sort(0, nums.size() - 1); //调用函数对序列nums进行快速排序
三、选择排序
1.简单选择排序
简单选择排序(simple select sort)的基本思想是:在无序序列中找出最小的记录,然后放在无序序列的最左端,重复该过程,直到序列全部有序。
平均时间复杂度为O(n^2)。
简单选择排序是不稳定的排序。
vector<int> nums = { 5,0,1,2,7,3,9,6,4,8 }; //待排序序列for (int i = 0; i < nums.size()-1; i++) //只需选择n-1次
{int index = i; //index存最小数的下标,初始化为最左侧下标for (int j = i + 1; j < nums.size(); j++) //遍历无序序列{if (nums[j] < nums[index]) //若遍历到的数更小,index存其下标{index = j;}}if (index != i) //若最小数不在最左侧,则移到最左侧{int temp = nums[i];nums[i] = nums[index];nums[index] = temp;}
}
2.堆排序
堆排序是简单选择排序的改进,改进的着眼点是在选出最小记录的同时,也找出较小记录,减少了记录的比较次数。
堆排序的基本思想是:首先将待排序序列调整成一个堆,将堆顶移走作为最大者,并将剩余记录再调整成堆,又将堆顶移走作为次大者,依此类推,直到得到整个有序序列。
平均时间复杂度为O(nlog2n)。(2为底数)
堆排序是不稳定的排序。
堆排序对待排序序列的初始状态并不敏感,相对于快速排序,这是堆排序最大的优点。
vector<int> nums = { 5,0,1,2,7,3,9,6,4,8 }; //待排序序列/*堆调整,参数为待排序列,被调整节点和最后一个节点的下标(用于防止数组越界)*/
void sift(vector<int>& nums, int sorted_num, int last)
{int parent(sorted_num); //父节点int child(2 * sorted_num + 1); //左孩子节点while (child <= last) //尚未越界{//将child指向孩子中的较大者,child<last意味着有右孩子if (child < last && nums[child] < nums[child + 1]) {child++; //child+1即指向右孩子}if (nums[parent] > nums[child]) //父节点更大,满足堆条件,结束{break;}else //否则,交换父子节点并更新父子节点{int temp = nums[parent];nums[parent] = nums[child];nums[child] = temp;parent = child;child = 2 * parent + 1;}}
}/*堆排序函数,参数是待排序列*/
void heap_sort(vector<int>& nums)
{//初始化堆,最后一个分支节点的下标为nums.size()/2-1 for (int i = nums.size() / 2 - 1; i >= 0; i--) {sift(nums, i, nums.size() - 1);}//将堆顶和最后一个节点交换,再重建堆,每交换一次堆减少一个元素(j--)for (int j = nums.size() - 1; j > 0; j--) {int temp = nums[0];nums[0] = nums[j];nums[j] = temp;sift(nums, 0, j - 1);}
}heap_sort(nums); //对序列nums进行堆排序
四、归并排序
归并排序(merge sort)的基本思想是:将若干个有序序列逐步归并,最终归并为一个有序序列。
常用的是二路归并排序,其基本思想是:将待排序列划分为两个长度相等的子序列,分别对这两个子序列进行排序,再将这两个有序子序列合并成一个有序序列。
平均时间复杂度为O(nlog2n)。(2为底数)
二路归并排序是一种稳定的排序方法。
1.二路归并排序的递归实现
vector<int> nums = { 5,0,1,2,7,3,9,6,4,8 }; //待排序序列/*用于合并两个相邻子序列[left_1, right_1]和[right_1 + 1, right_2], 得到[left_1, right_2]*/
void merge(int left_1, int right_1, int right_2)
{int* temp = new int[nums.size()]; //申请一个合并辅助空间int i = left_1, j = right_1 + 1, k = left_1;while (i <= right_1 && j <= right_2) //当两个序列都还有待排元素时{if (nums[i] <= nums[j]) //取较小者放入辅助空间{temp[k++] = nums[i++];}else{temp[k++] = nums[j++];}}while (i <= right_1) //若第二个序列无待排元素{temp[k++] = nums[i++]; //将第一个序列剩余元素全部放入辅助空间}while (j <= right_2) //若第一个序列无待排元素{temp[k++] = nums[j++]; //将第二个序列剩余元素全部放入辅助空间}for (i = left_1; i <= right_2; i++) //将合并结果放回原序列{nums[i] = temp[i];}delete[] temp; //释放合并辅助空间
}/*二路归并排序的递归算法,对[left,right]进行排序*/
void merge_sort(int left, int right)
{if (left == right) //只有1个记录,递归结束{return;}else{int mid = (left + right) / 2; //分割为两个子序列merge_sort(left, mid); //对前半部分归并排序merge_sort(mid + 1, right); //对后半部分归并排序merge(left, mid, right); //将两个子序列归并}
}merge_sort(0, nums.size() - 1); //对序列nums归并排序
2.二路归并排序的非递归实现
二路归并排序的递归实现是一种自顶向下的方法,形式简洁但效率相对较差。二路归并排序的非递归实现是一种自底向上的方法,算法效率较高,但算法较复杂。
vector<int> nums = { 5,0,1,2,7,3,9,6,4,8 }; //待排序序列/*用于合并两个相邻子序列[left_1, right_1]和[right_1 + 1, right_2], 得到[left_1, right_2]*/
void merge(int left_1, int right_1, int right_2)
{int* temp = new int[nums.size()]; //申请一个合并辅助空间int i = left_1, j = right_1 + 1, k = left_1;while (i <= right_1 && j <= right_2) //当两个序列都还有待排元素时{if (nums[i] <= nums[j]) //取较小者放入辅助空间{temp[k++] = nums[i++];}else{temp[k++] = nums[j++];}}while (i <= right_1) //若第二个序列无待排元素{temp[k++] = nums[i++]; //将第一个序列剩余元素全部放入辅助空间}while (j <= right_2) //若第一个序列无待排元素{temp[k++] = nums[j++]; //将第二个序列剩余元素全部放入辅助空间}for (i = left_1; i <= right_2; i++) //将合并结果放回原序列{nums[i] = temp[i];}delete[] temp; //释放合并辅助空间
}/*执行一趟归并排序*/
void merge_pass(int h)
{int i(0);while (i + 2 * h <= nums.size()) //有两个长度为h的子序列{merge(i, i + h - 1, i + 2 * h - 1); //合并前两个子序列i = i + 2 * h; //准备合并下两个子序列}if (i + h < nums.size()) //有两个长度分别等于h和小于h的子序列,合并它们{merge(i, i + h - 1, nums.size() - 1);}
}/*二路归并排序的非递归算法*/
void merge_sort()
{int h(1); //初始子序列长度为1while (h < nums.size()){merge_pass(h);h = 2 * h;}
}merge_sort(); //对序列nums归并排序
相关文章:

C++:排序算法
目录 一、插入排序 1.直接插入排序 2.希尔排序 二、交换排序 1.冒泡排序 2.快速排序 三、选择排序 1.简单选择排序 2.堆排序 四、归并排序 1.二路归并排序的递归实现 2.二路归并排序的非递归实现 一、插入排序 1.直接插入排序 直接插入排序的基本思想是ÿ…...

期货日内稳赢策略:双15交易法详解
Eagle Trader的考试不仅涵盖了CFD交易,期货交易的考生人数也颇为可观。与外汇市场相比,期货在国内市场的普及程度更高,参与的群体也更为广泛。这得益于期货市场在国内相对成熟的监管体系,使得交易员对期货有了更深入的了解和信任。…...

2024年10月第2个交易周收盘总结:怎样卖出!
计划自己的交易,交易自己的计划。 跟随市场而情绪波动,最终一定会导向失败! 连续、平稳、冷静地惯彻交易计划,比什么都重要! 交易本身是极其简单和清楚的,让事情变复杂的原因不是行情走势和交易本身&…...

mysql 不支持utf8mb4_0900_ai_ci
Unknowncollation:‘utf8mb4_0900_ai_ci’ 解决方案: 1. 升级mysql为8.0以上(不包含8.0) 2. 修改编码类型: utf8mb4_0900_ai_ci/utf8mb4_0900_ci 修改为utf8_general_ci utf8mb4修改为utf8 utf8mb4_0900_ai_ci 是一种 MySQL 数…...

第10篇:防火墙与入侵检测系统
目录 引言 10.1 防火墙的基本概念 10.2 防火墙的分类 10.3 防火墙策略的配置与实现 10.4 入侵检测系统(IDS) 10.5 防火墙与IDS的结合 10.6 总结 第10篇:防火墙与入侵检测系统 引言 在当今的数字世界中,网络安全已经成为企…...

Jmeter监控服务器性能
目录 ServerAgent 安装 打开Jmeter ServerAgent 在Jmeter上监控服务器的性能比如CPU,内存等我们需要用到ServerAgent,这里可以下载我分享 ServerAgent-2.2.3.zip 链接: https://pan.baidu.com/s/1oZKsJGnrZx3iyt15DP1IYA?pwdedhs 提取码: edhs 安装…...

通过前端UI界面创建VUE项目
通过前端UI界面创建VUE项目,是比较方面的一种方式,下面我们详细分析一下流程: 1、找到合适目录 右键鼠标,点击在终端打开 2、开始创建 输入 vue ui 浏览器弹出页面 3、点击Create项目 显示已有文件列表,另外可以点击…...

Python网络爬虫:分析淘宝商品热度与销量[进阶深度优化]
要更全面和深入地介绍基于Python的网络爬虫系统,分析淘宝商品买卖热度、销量以及统计热点关键词,我们可以进一步扩展内容,涵盖更多技术细节、优化策略、数据分析、以及机器学习的结合,形成一个功能强大、可靠的爬虫系统。下面是进一步的补充。 1. 爬虫策略的深度优化 为了…...

golang从http请求中读取xml格式的body,并转成json
推荐学习文档 golang应用级os框架,欢迎stargolang应用级os框架使用案例,欢迎star案例:基于golang开发的一款超有个性的旅游计划app经历golang实战大纲golang优秀开发常用开源库汇总想学习更多golang知识,这里有免费的golang学习笔…...

RestTemplate 学习笔记
简介 RestTemplate是一个执行HTTP请求的同步阻塞式工具类,它仅仅只是在 HTTP 客户端库(例如 JDK HttpURLConnection,Apache HttpComponents,okHttp 等)基础上,封装了更加简单易用的模板方法 API,…...

数据抓取时,使用动态IP要注意哪些?
在充满竞争和数据驱动的商业环境中,动态IP已成为数据抓取过程中不可或缺的工具。动态IP的应用能有效提高抓取成功率,但同时也伴随着一系列需要注意的问题。在本文中,我们将详细探讨在数据抓取时使用动态IP时应注意的事项,以确保抓…...

C++类的构造函数
1、what 类的特殊成员函数,用来初始化类对象的数据成员。 只要类对象被创建,就会被执行。 构造函数的名字和类名相同,可以包含“0”个(其实有一个编译器生成的合成默认构造函数,只是看不见而已)、1个或多个构造函数,没有返回值,不同构造函数使用参数数量或参数类型进行…...

第21~22周Java主流框架入门-Spring 3.SpringJDBC事务管理
Spring JDBC模块与事务管理课程总结 1. 课程介绍 本课程主要讲解Spring框架中的JDBC模块及其事务管理的相关内容,重点包括以下三个方面: Spring JDBC模块及核心对象JDBC Template的使用 通过学习如何使用Spring JDBC模块,了解JDBC Template…...

C++ —— 类和对象
目录 介绍类和对象 一. 类和对象——类的定义 1.访问限定符 2.类域 作用操作符:: 3.对象大小 类的实例化 内存对齐规则 4.this指针 this指针会出现的问题 5.C语言结构体与C类对比 封装的本质 C类的优点 二 .类和对象——关于成员 1.类的默认成员函数 I.构造函数 构…...

安全见闻笔记
目录 安全见闻... 1 编程语言... 1 函数式编程语言... 1 数据科学和机器学习领域... 2 Web 全栈开发... 2 移动开发... 2 嵌入式系统开发... 2 其他... 2 操作系统... 2 裸板程序... 3 操作系统... 3 网络通讯... 4 计算机硬件... 4 网络硬件... 4 移动设备硬件…...

visual studio使用vcpkg无法定位程序输入点于XXX动态链接库***.dll上
第一个解决办法:将vcpkg的bin文件夹添加到系统变量 vcpkg\installed\x64-windows\bin vcpkg\installed\x64-windows\debug\bin 第二个解决办法:将bin文件夹添加到调试->环境中...

如何保护您的服务器免受 POODLE SSLv3 漏洞的影响
前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站。 简介 2014年10月14日,SSL加密协议第3版中的一个漏洞被披露。这个漏洞被称为POODLE(Padding Oracle On Downgrad…...

如何用pyhton修改1000+图片的名字?
import os oldpath input("请输入文件路径(在windows中复制那个图片文件夹的路径就可以):") #注意window系统中的路径用这个‘\分割,但是编程语言中一般都是正斜杠也就是’/‘ #这里写一个代码,将 \ > / path "" fo…...

使用fpm工具制作Vim.rpm包
背景:生产环境中的CentOS 7在安全扫描中被扫描出vim存在堆缓冲区溢出(CVE-2024-45306)等漏洞。根据漏洞说明,需要升级到最新版。 奈何CentOS 7已经停止维护了,所以,想在网上找一个最新版的vim.rpm相当不容易…...

Dorado7 全局缓存当前登录人信息 localStorage
登录成功时赋值 com.gs.mcf.view/index.js // like12 add,20240906,全局缓存当前登录人信息var currentName view.get(#userNameLb).get(tip);if(window.localStorage){localStorage.setItem("currentName", currentName);} 使用 // like12 add,20240906,全局缓存…...

【2024最新版】网络安全学习路线-适合入门小白
首先说明,我是一名CTF的web手,这是我自己亲身学习网络安全的路线,希望能够帮到大家,我虽然不是大牛,但我也希望能够帮助一些网安小白找到自己学习的方向,后面有就业的详细安全技术要求,如果真想…...

高可用之限流-07-token bucket 令牌桶算法
限流系列 开源组件 rate-limit: 限流 高可用之限流-01-入门介绍 高可用之限流-02-如何设计限流框架 高可用之限流-03-Semaphore 信号量做限流 高可用之限流-04-fixed window 固定窗口 高可用之限流-05-slide window 滑动窗口 高可用之限流-06-slide window 滑动窗口 sen…...

软件测试学习笔记丨Pycharm运行与调试
本文转自测试人社区,原文链接:https://ceshiren.com/t/topic/23454 Pycharm作为集成开发环境,除了可以编写脚本,还可以运行和调试自己的代码,下面就为大家介绍一下pycharm运行和调试代码的功能如何使用。 代码运行 编…...

flask基础学习
一、Python之flask、Django、Tornado框架 一)django 主要是用来搞快速开发的,他的亮点就是快速开发,节约成本。 正常的并发量不过10000,如果要实现高并发的话,就要对django进行二次开发,比如把整个笨重的框…...

【SSM详细教程】-04-Spring基于注解的组件扫描
精品专题: 01.《C语言从不挂科到高绩点》课程详细笔记 https://blog.csdn.net/yueyehuguang/category_12753294.html?spm1001.2014.3001.5482https://blog.csdn.net/yueyehuguang/category_12753294.html?spm1001.2014.3001.5482 02. 《SpringBoot详细教程》课…...

Keepalived:构建高可用性的秘密武器
Keepalived:构建高可用性的秘密武器 在现代的IT环境中,高可用性是确保业务连续性和用户体验的关键要素。一旦系统出现故障或停机,企业可能会面临巨大的经济损失和声誉损害。因此,实施高可用性解决方案至关重要。Keepalived作为一…...

【C++刷题】力扣-#228-汇总区间
题目描述 给定一个整数数组 nums,返回所有唯一的区间,这些区间包含数组中的每个数字,形式为 [a, b],其中 a 和 b 是数字的最小和最大值。 示例 示例 1: 输入: nums [0,1,2,4,5,7] 输出: [["0,2"],["4,5"],…...

交通银行核心系统分布式实践
1、背景:客户需求和痛点 交通银行已有核心ECIF、贷记卡核心、借记卡新核心等数百套系统上线OceanBase分布式数据库。其中,贷记卡(俗称信用卡)属于 A类核心业务系统,支撑了信用卡授权、用卡、额度、账务等核心业务功能,约7千万卡量,日交易量和数据量都在千万级别。 交通银行…...

深入剖析:.Net8 引入非root用户运行的新特性提升应用安全性
在云原生的时代,容器化技术如Docker和Kubernetes已经成为现代软件开发的重要基石。随着.Net8的发布,微软进一步优化了这些环境的支持,特别是在提升容器应用安全性方面迈出了重要一步。本文将深入探讨.Net8中非根用户功能的新增特性࿰…...

多签机制简明理解及实例说明
目录 Multisignature机制简明理解及实例说明 Multisignature机制中的公钥、私钥、Nonce及签名验签详解 加密货币托管账户的多重签名机制 Multisignature机制简明理解及实例说明 一、基本概念 Multisignature(多重签名)机制是一种先进的加密技术,它允许一笔交易必须由多…...