当前位置: 首页 > news >正文

C++ 数据结构算法 学习笔记(32) -五大排序算法

C++ 数据结构算法 学习笔记(32) -五大排序算法

选择算法

如下若有多个女生的身高需要做排序:

在这里插入图片描述

常规思维:

  1. 第一步先找出所有候选美女中身高最高的,与最后一个数交换

在这里插入图片描述

  1. 第二步再找出除最后一位美女外其它美女中的最高者,与倒数第二个美女交换位置

在这里插入图片描述

  1. 再找出除最后两位美女外其它美女中的最高者,与倒数第三个美女交换位置,因为倒数 第三个本身已是最大的,所以实际无需交换.

在这里插入图片描述

  1. 重复以上步骤,直到最后只剩下一人,此时,所有的美女均已按照身高由矮到高的 顺序排列

在这里插入图片描述

代码实现:

#include<stdio.h>
#include<stdlib.h>
void swap(int* num1, int* num2)//交换两个变量的值
{int temp = *num1;*num1 = *num2;*num2 = temp;
}void SelectSort1(int arr[], int len) {for (int i = 0; i < len - 1; i++) {int max = 0;for (int j = 1; j < len - i; j++) { //查找未排序的元素if (arr[j] > arr[max]) { //找到目前最小值max = j;}}//printf("max:%dbeauties%d\n",max,len-i-1);if (max != (len - i - 1)) {swap(&arr[max], &arr[len - i - 1]);}}
}
void SelectSort2(int arr[], int len) {int i, j;for (i = 0; i < len - 1; i++){int min = i;for (j = i + 1; j < len; j++) { //查找未排序的元素if (arr[j] < arr[min]) { //找到目前最小值min = j; //记录最小值}}swap(&arr[min], &arr[i]); //交换}
}
int main(void) {int beauties[] = { 163,161,158,165,171,170,163,159,162 };int len = sizeof(beauties) / sizeof(beauties[0]);SelectSort2(beauties, len);for (int i = 0; i < len; i++) {printf("%d ", beauties[i]);}system("pause");
}

冒泡算法

当我们采用前面的选择排序时,我们仍然要将候选者遍历5遍,才能完成最终的排序,但其 实,本身这些美女出了第一个外,已经很有序了,我们只需要把第一个和第二个交换,然后又和 第三个交换,如此循环,直到和最后一个交换后,整个数组基本就有序了!

在这里插入图片描述

当然,并不是每次都这么幸运,像下面的情况就会更复杂一些,一趟并不能完全解决问题, 我们需要多趟才能解决问题.

在这里插入图片描述

经过上述五步后,得到的结果:

在这里插入图片描述

此时,我们只保障了最后一个数是最大的,并不能保障前面的数一定会有序,所以,我们继续按 照上面五步对剩下的5个数继续进行一次排序,数组就变得有序了. 以上过程就是冒泡排序:通过重复地遍历未排序的数列,一次比较两个元素,如果它们的顺 序错误就把它们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列 已经排序完成。这个算法的名字由来是因为越小的元素会经由交换慢慢得像泡泡一样“”到数 列的顶端,故而得名

代码实现:

#include <iostream>
#include <string>using namespace std;void swap(int* tmp1, int* tmp2)
{int tmp3 = *tmp1;*tmp1 = *tmp2;*tmp2 = tmp3;
}int main()
{int height2[] = { 156,162,161,172,167,169,155 };int height[] = { 155,158,161,163,172,174 };int size = sizeof(height) / sizeof(height[0]);for (int i = 0; i < size-1; i++){bool sorted = true;for (int j = 0; j < size-i-1; j++){if (height[j] > height[j+1]){	sorted = false;swap(&height[j], &height[j + 1]);}}if (sorted == true)	break;}for (int i = 0; i < size; i++){cout << height[i] << " ";}system("pause");return 0;
}

插入排序

在这里插入图片描述

  1. 首先,我们只考虑第一个元素,从第一个元素171开始,该元素可以认为已经被排序;

在这里插入图片描述

  1. 取下一个元素161并记录,并让161所在位置空出来,在已经排序的元素序列中从后向前扫 描;

    在这里插入图片描述

  2. 该元素(171)大于新元素,将该元素移到下一位置;

    在这里插入图片描述

  3. 171前已经没有最大的元素了,则将161插入到空出的位置

    在这里插入图片描述

  4. 取下一个元素163,并让163所在位置空出来,在已经排序的元素序列中从后向前扫描;

    在这里插入图片描述

  5. 该元素(171)大于新元素163,将该元素移到下一位置

    在这里插入图片描述

  6. 继续取171前的元素新元素比较,直到找到已排序的元素小于或者等于新元素的位置;新 元素大于161,则直接插入空位中

    在这里插入图片描述

  7. 重复步骤2~7,直到完成排序

    在这里插入图片描述

插入排序:它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描, 找到相应位置并插入。插入排序在实现上,通常采用in-place排序(即只需用到O(1)的额外空间 的排序),因而在从后向前扫描过程中,需要反复把已排序元素逐步向后挪位,为最新元素提供 插入空间。

具体算法描述如下:

  1. 从第一个元素开始,该元素可以认为已经被排序;

  2. 取出下一个元素,在已经排序的元素序列中从后向前扫描;

  3. 如果该元素(已排序)大于新元素,将该元素移到下一位置; 重复步骤3,直到找到已排序的元素小于或者等于新元素的位置;

  4. 将新元素插入到该位置; 重复步骤2~5

代码实现::

#include <iostream>
#include <string>using namespace std;void InsertSort(int* height, int size) 
{int current = 0;int preIndex = 0;for (int i = 1; i < size; i++){current = height[i];preIndex = i-1;while (preIndex >= 0 && height[preIndex] > current){height[preIndex + 1] = height[preIndex];preIndex--;}height[preIndex + 1] = current;}
}int main()
{int height[] = { 152,163,161,159,172,170,168,151 };int size = (sizeof(height) / sizeof(height[0]));InsertSort(height, size);cout << "The sorting result is" << endl;for (int i = 0; i < size; i++){cout << height[i] << " ";}system("pause");return 0;
}

希尔排序

插入排序虽好,但是某些特殊情况也有很多缺点,比如像下面这种情况

在这里插入图片描述

169前的元素基本不用插入操作就已经有序,元素1和2的排序几乎要移动数组前面的所有 元素!!!于是,有个老帅哥就提出了优化此问题的希尔排序!

希尔排序是希尔(Donald Shell)于1959年提出的一种排序算法。希尔排序也是一种插入排 序,它是简单插入排序经过改进之后的一个更高效的版本,也称为缩小增量排序。它与插入排序 的不同之处在于,它会优先比较距离较远的元素。

希尔排序是把记录按下表的一定增量分组,对每组使用直接插入排序算法排序;随着增量逐 渐减少,每组包含的元素越来越多,当增量减至1时,所有元素被分成一组,实际上等同于执行一 次上面讲过的插入排序,算法便终止。

希尔排序的基本步骤:

选择增量:gap=length/2,缩小增量:gap=gap/2

增量序列:用序列表示增量选择,{n/2,(n/2)/2,…,1}

先将整个待排序的记录序列分割成为若干子序列分别进行直接插入排序,具体算法描述:

选择一个增量序列t1,t2,…,tk,其中ti>tj,tk=1;

按增量序列个数k,对序列进行k趟排序;

每趟排序,根据对应的增量ti,将待排序列分割成若干长度为m的子序列,分别对各子表进 行直接插入排序;

仅增量因子为1时,整个序列作为一个表来处理,表长度即为整个序列的长度。

在这里插入图片描述

#include <iostream>
#include <string>
using namespace std;void InsertSort(int arr[], int len)
{int gap = len / 2;for (; gap > 0; gap = gap / 2) {for (int i = gap; i < len; i++) {int current = arr[i];int j = 0;for (j = i - gap; j >= 0 && arr[j] > current; j -= gap) {arr[j + gap] = arr[j];}arr[j + gap] = current;}}
}int main()
{int height[] = { 152,163,161,159,172,170,168,151 };int size = (sizeof(height) / sizeof(height[0]));InsertSort(height, size);cout << "The sorting result is" << endl;for (int i = 0; i < size; i++){cout << height[i] << " ";}system("pause");return 0;
}

归并排序

当两个组数据已经有序,我们可以通过如下方式(以下简称归并大法)让两组数据快速有序

在这里插入图片描述

我们可以依次从两组中取最前面的那个最小元素依次有序放到新的数组中,然后再把新数组 中有序的数据拷贝到原数组中,快速完成排序
在这里插入图片描述

具体步骤:

对于下面这一组待排序的数组

在这里插入图片描述

先以中间为界,把其均分为A和B两个数组(如果是奇数个,允许两组数相差一个)

在这里插入图片描述

如果A和B两组数据能够有序,则我们可以通过上面的方式让数组快速排好序。 此时,A组有4个成员,B组有5个成员,但两个数组都无序,然后我们可以采用分治法继 续对A组和B组进行均分,以A组为例,又可以均分A1和A2两个组如下:

在这里插入图片描述

均分后,A1组和A2组仍然无序,继续利用分治法细分,以A1组为例,A1又可分成如下 两组

在这里插入图片描述

数组细分到一个元素后,这时候,我们就可以采用归并法借助一个临时数组将数组A1有序化! A2同理!

在这里插入图片描述

依次类推,将A1组和A2组归并成有序的A组,B组同理!

在这里插入图片描述

最后,将A和B组使用归并大法合并,就得到了完整的有序的结果!

在这里插入图片描述

代码实现:

#include <iostream>
#include <string>using namespace std;//void mergeAdd_demo(int arr[], int left, int mid, int right)
//{
//	int temp[64] = { 0 };
//	int i = left;
//	int j = mid;
//	int k = 0;
//
//	while (i < mid && j <= right)
//	{
//		if (arr[i] < arr[j])
//		{
//			temp[k++] = arr[i++];
//		}
//		else
//		{
//			temp[k++] = arr[j++];
//		}
//	}
//	while (i < mid)
//	{
//		temp[k++] = arr[i++];
//	}
//
//	while (j <= right)
//	{
//		temp[k++] = arr[j++];
//	}
//
//	memcpy(arr + left, temp, sizeof(int) * (right - left + 1));
//}void mergeAdd(int arr[], int left, int mid, int right, int* temp)
{//int temp[64] = { 0 };int i = left;int j = mid;int k = left;while (i < mid && j <= right){if (arr[i] < arr[j]){temp[k++] = arr[i++];}else{temp[k++] = arr[j++];}}while (i < mid){temp[k++] = arr[i++];}while (j <= right){temp[k++] = arr[j++];}memcpy(arr + left, temp + left, sizeof(int) * (right - left + 1));
}void mergeSort(int arr[], int left, int right, int* temp)
{int mid = 0;if (left < right){mid = left+(right-left)/2;mergeSort(arr, left, mid, temp);mergeSort(arr, mid + 1, right, temp);mergeAdd(arr, left, mid+1, right, temp);}
}int main()
{int height[] = { 10,11,12,13,2,4,5,8 };int len = sizeof(height) / sizeof(height[0]);int* temp = new int[len];//int mid = len / 2;mergeSort(height, 0, len - 1, temp);//mergeAdd(height, 0, mid, len - 1,temp);for (int i = 0; i < len; i++){cout << height[i] << " ";}system("pause");return 0;
}

快速排序

具体做法为:

  1. 每次选取第一个数为基准数;
  2. 然后使用“乾坤挪移大法”将大于和小于基准的元素分别放置于基准数两边;
  3. 继续分别对基准数两侧未排序的数据使用分治法进行细分处理,直至整个序列有序。

对于下面待排序的数组:

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

代码实现:

#include <iostream>
#include <string>using namespace std;
int partition(int arr[], int low, int high)
{int i = low;int j = high;int base = arr[low];if (low < high){while (i < j){while (i < j && arr[j] >= base){j--;}if (i < j){arr[i++] = arr[j];}while (i < j && arr[i] < base){i++;}if (i < j){arr[j--] = arr[i];}}arr[i] = base;}return i;
}void QuickSort(int* arr, int low, int high)
{if (low < high){int index = partition(arr, low, high);QuickSort(arr, low, index - 1);QuickSort(arr, index + 1, high);}
}int main()
{int arr[] = { 163,161,158,165,171,170,163,159,162 };int len = sizeof(arr) / sizeof(arr[0]);//int index = partition(arr, 0, len - 1);QuickSort(arr, 0, len - 1);cout << "Executing the Quick Sort, result as" << endl;for (int i = 0; i < len; i++){cout << arr[i] << " ";}system("pause");return 0;
}

各大算法对比图

在这里插入图片描述

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • AI预测福彩3D采取888=3策略+和值012路一缩定乾坤测试5月25日预测第1弹
  • 【机器学习】大模型在机器学习中的应用:从深度学习到生成式人工智能的演进
  • 【AI大模型】这可能是最简单的本地大模型工具,无须部署,一键使用
  • Controlnet作者放出新的大招 IC-Light,可以操控图像生成时的光照,对内容主体重新打光生成符合新背景环境光照的图片
  • XH连接器>KH-XH-5A-Z
  • 【全部更新完毕】2024电工杯A题数学建模详细思路代码文章分享
  • 【C++高阶(一)】继承
  • plt多子图设置
  • 如何使用Python中的生成器
  • C:技术面试总结
  • C# 实现腾讯云 IM 常用 REST API 之会话管理
  • Rust:WIndows 环境下交叉编译 Linux 平台程序
  • UIKit之猜图器Demo
  • aws msk加密方式和问控制连接方式
  • Sql语句DQL操作 查询操作单表 多表 子表(嵌套)
  • 《剑指offer》分解让复杂问题更简单
  • 【跃迁之路】【699天】程序员高效学习方法论探索系列(实验阶段456-2019.1.19)...
  • Apache的基本使用
  • ES10 特性的完整指南
  • IIS 10 PHP CGI 设置 PHP_INI_SCAN_DIR
  • JavaScript创建对象的四种方式
  • Js基础知识(一) - 变量
  • MYSQL如何对数据进行自动化升级--以如果某数据表存在并且某字段不存在时则执行更新操作为例...
  • PV统计优化设计
  • Spring思维导图,让Spring不再难懂(mvc篇)
  • 从0搭建SpringBoot的HelloWorld -- Java版本
  • 构造函数(constructor)与原型链(prototype)关系
  • 利用阿里云 OSS 搭建私有 Docker 仓库
  • 手机app有了短信验证码还有没必要有图片验证码?
  • 函数计算新功能-----支持C#函数
  • 曾刷新两项世界纪录,腾讯优图人脸检测算法 DSFD 正式开源 ...
  • ​zookeeper集群配置与启动
  • #define
  • #VERDI# 关于如何查看FSM状态机的方法
  • #设计模式#4.6 Flyweight(享元) 对象结构型模式
  • $(selector).each()和$.each()的区别
  • (2)MFC+openGL单文档框架glFrame
  • (rabbitmq的高级特性)消息可靠性
  • (分享)一个图片添加水印的小demo的页面,可自定义样式
  • (附源码)计算机毕业设计SSM疫情居家隔离服务系统
  • (附源码)流浪动物保护平台的设计与实现 毕业设计 161154
  • (介绍与使用)物联网NodeMCUESP8266(ESP-12F)连接新版onenet mqtt协议实现上传数据(温湿度)和下发指令(控制LED灯)
  • (顺序)容器的好伴侣 --- 容器适配器
  • (五)Python 垃圾回收机制
  • (五十)第 7 章 图(有向图的十字链表存储)
  • *2 echo、printf、mkdir命令的应用
  • .mysql secret在哪_MySQL如何使用索引
  • .NET BackgroundWorker
  • .net core 源码_ASP.NET Core之Identity源码学习
  • .Net 基于MiniExcel的导入功能接口示例
  • .NET/C# 编译期间能确定的相同字符串,在运行期间是相同的实例
  • .NET/C# 使窗口永不获得焦点
  • .net2005怎么读string形的xml,不是xml文件。
  • .net解析传过来的xml_DOM4J解析XML文件
  • .NET开发人员必知的八个网站