数据结构初阶--排序1

news2024/9/21 13:52:16

目录

  • 前言
  • 冒泡排序
    • 思路
    • 代码实现
  • 选择排序
    • 思路
    • 代码实现
  • 插入排序
    • 思路
    • 代码实现
  • 希尔排序
    • 思路
    • 代码实现
  • 堆排序
    • 思路
      • 向上调整建堆
      • 向下调整建堆
    • 代码实现

前言

排序在我们的日常生活中无处不在,比如对若干个学生的期末成绩,可以依据姓氏,学号,某科成绩,总成绩等进行排名,富豪榜的排名,游戏中的战力排名,甚至是在日常生活中的扑克牌,我们也会依据其数字大小等对其进行排序,所以我们在学习编程的过程中,排序一定是十分重要并且对于我们十分有帮助的东西,所以本篇文章,将对几大重要排序算法–冒泡排序,插入排序,希尔排序,选择排序,堆排序,快速排序,归并排序进行讲解。

冒泡排序

冒泡排序,几乎是所有编程初学者接触到的第一种排序算法,虽然由于其时间复杂度过大没有什么实际的应用价值,但其还是有很强的教学意义的。

思路

冒泡排序的基本思路就是相邻的两个元素两两比较,不断地将较大/小的值往后放,一趟下来最后一个元素就是最大/小值,然后再重复此过程即可。

代码实现

冒泡排序的代码实现如下

void BubbleSort(int arr[], int n)
{
	for (int i = 0; i < n; i++)
	{
		for (int j = 1; j < n - i; j++)
		{
			if (arr[j - 1] > arr[j])
			{
				int temp = arr[j - 1];
				arr[j - 1] = arr[j];
				arr[j] = temp;
			}
		}
	}
}

冒泡排序的时间复杂度是O(N^2),可见消耗是十分大的。

选择排序

选择排序和冒泡排序的思想是类似的。

思路

选择排序和冒泡排序唯一的不同就是,冒泡排序是比较相邻的元素,而选择排序是将一个元素和它后面所有的元素进行比较.也没有什么难度。

代码实现

选择排序的代码实现如下

void SelectSort(int arr[], int n)
{
	for (int i = 0; i < 9; i++)
	{
		for (int j = i + 1; j < 10; j++)
		{
			if (arr[i] > arr[j])
			{
				int temp = arr[i];
				arr[i] = arr[j];
				arr[j] = temp;
			}
		}
	}
}

选择排序的时间复杂度是O(N^2),时间消耗和冒泡一样,也是十分巨大的。

插入排序

插入排序的思想就和我们平时打扑克牌时理牌的思路差不多

思路

我们平时在打扑克牌时,我们一般是摸一张整理一张,这样可以保证我每次放进一张牌之前的牌都是有序的,然后将我们要插入的牌从后往前(之所以不从前往后,是因为我们插入牌,相当于插入数据的时候,需要将后面的所有数据依次往后挪动,为这个数据(牌)留出一个位置)依次进行比较,放入合适的位置。

代码实现

插入排序的代码实现如下

void InsertSort(int arr[], int n)
{
	for (int i = 0; i < n - 1; i++)
	{
		// 2 3 4 3
		int end = i;
		int temp = arr[end + 1];
		while (end >= 0)
		{
			if (arr[end] > temp)
			{
				arr[end + 1] = arr[end];
				end--;
			}
			else
			{
				break;
			}
		}
		arr[end + 1] = temp;
	}

}

插入排序的算法也是O(N^2),但是它有别于前两个算法,因为数据越接近有序,它的时间效率就越高,不像前两个排序一样就算有序仍然要进行比较。而且它还能作为接下来要讲的一个很强的排序–希尔排序的辅助实现。

希尔排序

希尔排序是对直接插入排序的优化。

思路

希尔排序法又称缩小增量法。希尔排序法的基本思想是:先选定一个整数,把待排序文件中所有记录分成n/gap个
组,所有距离为gap的记录分在同一组内,并对每一组内的记录进行排序。然后,取重复上述分组和排序的工作。当到达gap=1时,所有记录在统一组内排好序。
当gap>1时叫做预排序,目的是使数组接近有序,因为假设我们考虑一个最坏的情况,数组最开始是降序排列的,我们要将其升序排列,相当于位于第一个位置的最大的数要放到最后的位置去,如果我们用插入排序的思想去排,那么要比较长度次才能将这个数放到最后去,这样消耗是十分大的,但是我们可以增大比较的数据之间的间隔,以此来减小比较的次数,
这样假设有10个数据,如图

  1. 我们要将9放到正确的位置(即0的位置),如果使用插入排序的思想,需要比较9次才能成功。但如果我们用希尔排序的思想,间隔gap(假设为3)进行比较,这样比较2次就能到达正确的位置,如果数据量很大,这样操作能大大节省时间。

    然后我们再往后,从8开始往后依次间隔为3比较,即图中的8,5,2。然后再是7,4,1这一组,这样就完成了一次预排序了。当然我们也可以将这三次分组比较进行合并,即9和6比完了就轮到8和5比,然后就到7和4比,然后就又轮到第一组,以此类推
  2. 在进行完一次预排序后,我们逐步的缩小gap的值,我们不难发现规律,当gap越小时,其预排序后越接近有序
  3. gap减小为1时,就是直接插入排序,至此排序就完成了。

代码实现

希尔排序的代码实现如下

void ShellSort(int arr[], int n)
{
  int gap = n;
  while (gap > 1)
  {
  	gap = gap / 3 + 1;
  	for (int i = 0; i < n - gap; i++)
  	{
  		int end = i;
  		int temp = arr[end + gap];
  		while (end >= 0)
  		{
  			if (arr[end] > temp)
  			{
  				arr[end + gap] = arr[end];
  				end -= gap;
  			}
  			else
  			{
  				break;
  			}
  		}
  		arr[end + gap] = temp;
  	}
  }
}

希尔排序的时间复杂度不好计算,因为gap的取值方法很多,导致很难去计算,因此在好些书中给出的希尔排序的时间复杂度都不固定。

堆排序

学习堆排序前我们要首先了解什么是堆。

堆其实就是一种二叉树,堆满足以下两种性质:
**1. 堆中某个节点的值总是不大于或不小于其父节点的值;

  1. 堆总是一棵完全二叉树。**

思路

要实现堆排序,我们首先要实现一个堆,然后才能进行后续操作,而堆虽然是一个完全二叉树,但在本质上,还是以数组的形式存储的.这里我们要用两种算法–向上调整建堆和向下调整建堆

向上调整建堆

向上调整建堆在插入数据以前必须要保证之前的数组满足是一个大堆或者小堆,向上调整建堆,顾名思义,就是要将插入到尾部的数据在其祖先这条线路上进行迭代调整,如图圈出来的部分就是我们要调整的部分。

我们不难发现这是一个小堆,那么此时我们就要将插入的3放到正确的位置上去,我们经过如图的操作即可实现,最终3会到根节点的位置。

向下调整建堆

向下调整建堆,其实就是调整根节点的位置,但在这之前要保证其左右子树都是大堆或者小堆

然后我们要比较父亲和左右孩子的大小,如果是小堆,我们就要选出左右孩子种较小的那个,比如图中的10,我们就要和5进行对调,如果和9进行对调,9变成父节点比5大,就不满足小堆了。所以正确的方法是如图所示的路径。

在学习完这两种算法后我们就要来尝试实现堆排序了。

1。首先我们通过向上/向下调整算法建立一个小堆(大堆也行,这里用小堆举例)。建立的思路就是依次往数组里放入数据,最开始只有一个数据的时候我们可以看做是一个堆,以此类推,我们就能满足每次插入数据之前都是一个堆
2.在创建完堆后,我们后续操作出来的数组是升序还是降序就取决于这是一个大堆还是小堆,我们第一步这说的是建立小堆,那么我们最终得到的数组也只能是降序,反之则是升序,这是为什么呢?
我们建立了小堆,最小的数就在根节点的位置,但由于其物理上是数组,如果我们直接在根节点把这个最小的数取出来,后面的所有数据父子关系就全乱了。所以正确的思路是把其根节点与最后一个数据交换,保证其堆的结构大致不变(即左右子树还是堆),接着我们根据这个特性首先想到向下调整算法继续选出次小的数,再和倒数第二个数交换,这样以此类推,我们就会发现数组就成为降序排列了。

代码实现

堆排序的代码实现如下

void AdjustUp(int arr[],int child)
{
   int parent = (child - 1) / 2;
   while (child > 0)
   {
   	if (arr[parent] < arr[child])
   	{
   		Swap(&arr[parent], &arr[child]);
   		child = parent;
   		parent = (child - 1) / 2;
   	}
   	else
   	{
   		break;
   	}
   }
}
void AdjustDown(int arr[], int n,int parent)
{
   int child = parent * 2 + 1;
   while (child < n)
   {
   	if (child + 1 < n && arr[child + 1] > arr[child])
   	{
   		child = child + 1;
   	}
   	if (arr[parent] < arr[child])
   	{
   		Swap(&arr[parent], &arr[child]);
   		parent = child;
   		child = parent * 2 + 1;
   	}
   	else
   	{
   		break;
   	}
   }
}
void HeapSort(int arr[], int n)
{
   //向上调整建堆
   for(int i=1;i<n;i++)
   	AdjustUp(arr,i);
   //升序--建大堆
   //降序--建小堆
   int end = n - 1;
   while (end > 0)
   {
   	Swap(&arr[0], &arr[end]);
   	AdjustDown(arr, end, 0);
   	end--;
   }

}

本篇内容到这里就结束了,如有出入,欢迎指正。

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

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

相关文章

交易成本模型与Python技术共同促进高频交易的发展走向

高频交易是一种在金融市场中越来越受到关注的交易方式&#xff0c;其具有快速、高效、低风险的特点&#xff0c;可以为投资者带来丰厚的利润。然而&#xff0c;在高频交易中&#xff0c;交易成本往往占据了很大的比例&#xff0c;可以说是一个非常重要的因素。因此&#xff0c;…

辅助驾驶功能开发-功能规范篇(22)-1-L2级辅助驾驶方案功能规范

1. 系统概览 System Overview 1.1 系统架构 各模块描述如下: ADSADS控制器,包括5R1V感知融合算法模块、level0-level2相关功能、控制决策模块、响应执行模块。EPBi制动执行机构,包括主制动和冗余制动,可实现行车和驻车控制。EPS转向执行机构,TJP包含冗余转向,L-TJP不包含…

DynaSLAM代码详解(3) — MaskNet.cc加载Mask R-CNN网络部分

目录 3.1 Mask R-CNN运行 3.2 SegmentDynObject::SegmentDynObject() 3.3 SegmentDynObject::GetSegmentation() 3.1 Mask R-CNN运行 在Examples/RGB-D/rgbd_tum.cc文件开始运行Mask R-CNN网络&#xff0c;首先进入MaskNet->GetSegmentation函数。 // Segment out the i…

使用Dockerfile创建nginx+php镜像,采用分层

什么是Dockerfile Dockerfile是一种能被Docker程序解释的脚本&#xff0c;它是由一条条的命令所组成&#xff0c;每条命令对应Linux下面的一条命令&#xff0c;Docker程序将这些Dockerfile命令翻译成真正的Linux命令 Dockerfile命令 Dockerfile通常会包含如下命令&#xff1a…

【AGC】认证服务HarmonyOS(api9)实现手机号码认证登录

【问题背景】 近期AGC上线了HarmonyOS(api9)平台的SDK&#xff0c;这样api9的设备也能使用认证服务进行快速认证登录了。下面为大家带来如何使用auth SDK&#xff08;api9&#xff09;实现手机号码认证登录。 【开通服务】 1.登录AppGallery Connect&#xff0c;点击“我的项…

lc202306

785. 判断二分图 对于单个连通图&#xff1a;一个dfs判断图中所有节点符合二分。 遍历节点列表>遍历所有连通图。 133. clone graph 994. rotting oranges 力扣 维护一个time表&#xff0c;表示所有orange rot的最快时间。对每一个 t0 就 rot 的 orange dfs&#xff0c;遇…

无法从gcr.io获取distroless镜像问题

当我们能够访问外网&#xff0c;且能够ping通gcr.io网站后&#xff0c;依旧无法拉取distroless镜像时&#xff0c;可以通过以下网站作为中转获取。 rootacoinfo-Vostro-3667:/home/xxx/xx# docker pull gcr.io/distroless/base-debian11 Using default tag: latest Error resp…

快速制作优惠券信息展示小程序教程

要想拥有一个拥有优惠券功能的小程序商城&#xff0c;首先我们需要搭建一个小程序。以乔拓云第三方平台为例&#xff0c;我们可以通过以下步骤来完成。 首先&#xff0c;登录乔拓云平台&#xff0c;进入【乔拓云】后台管理页面。乔拓云功能强大&#xff0c;不仅可以搭建小程序…

运维开发面试题第五期(华电天益)

1、一个目录(没有子目录)有很多文件&#xff0c;想最快速度查看到最近更新的文件你有几种方式实现?请写出一种或几种 ls -lrt 目录 R 逆序 l 长格式 t 按更新时间排序2、使用 tar 命令打包/etc 目录下的所有文件(包括子文件夹) tar -cvf 打包路径加名字 /etc/ 仅打包…

[gtp]购物车案例参考

react hooks,购物车案例. 在列表上点击或者-更新数量,调用接口更新单个价格. 点击table的checkbox勾选后,计算总价? 对于React Hooks和购物车案例&#xff0c;您可以使用useState来管理列表中商品的数量和总价。当点击"“或”-"按钮时&#xff0c;可以更新相应商品…

网络营销的定义、实现方式、关键要素和应用案例

网络营销是通过互联网及相关技术手段来实现企业品牌推广、产品销售、客户维护等目标的营销方式。近年来&#xff0c;随着互联网技术的飞速发展&#xff0c;网络营销已成为企业推广、销售和宣传的重要手段。本文将从网络营销的定义、实现方式、关键要素和应用案例等方面&#xf…

【ECharts系列】ECharts 图表渲染问题解决方案

1 问题描述 echats 渲染&#xff0c;第一次的时候只出现Y轴数值&#xff0c;不出现X轴数值&#xff0c;切换下页面&#xff0c;X轴数值就能出现。 2 原因分析 如果在使用ECharts渲染时&#xff0c;X轴数值只在切换页面后才出现&#xff0c;可能是因为ECharts在初始化时没有正确…

Mac上提取应用APP的LOGO

1、找到想提取LOGO的应用&#xff0c;右键「显示包内容」 2、 双击【Contents】文件夹&#xff0c;再双击【Resources】文件夹 3、双击图标打开&#xff0c;选择最清晰的一帧&#xff0c;右键【导出为】 4、选择保存位置&#xff0c;格式注意选择常见格式&#xff0c;如png

【Ajax】Express 服务端框架

因为Ajax需要向服务端发送请求。Express框架比较简单&#xff0c;内容使用起来比较少&#xff0c;借助一个基本功能就可以了。 Express 基于 Node.js 平台&#xff0c;快速、开放、极简的 Web 开发框架 所以需要安装一下node.js 检查命名&#xff1a;node -v 安装 打开项目最外…

多线程面试题详解

总体概览 线程的基础知识 线程和进程的区别&#xff1f; 并行和并发有什么区别&#xff1f; 创建线程的方式有哪些&#xff1f; runable和callable有什么区别 run()和start()有什么区别 线程包括了那些状态&#xff1f;这些状态之间如何变化 新建T1,T2,T3三个线程&#xff0c;如…

C#内存不够解决方法

今天在使用C#程序的时候&#xff0c;出现了下图的问题&#xff1a; 注意下图中我用红框标出的位置&#xff0c;实际是一个三维数组。 但是出现这个问题和三维数组没有关系。 他是提示内存不足。 百度了一下&#xff0c;C#在生成的过程中如果是生成对应的32位系统&#xff0c…

VMware15.5版本虚拟机安装Linux Centos 7系统详细步骤

1.首先准备好Centos7.6安装文件&#xff0c;安装文件可百度搜索或在阿里镜像站中下载。 阿里巴巴开源镜像站-OPSX镜像站-阿里云开发者社区 2.新建虚拟机. 1选择自定义&#xff0c;点下一步。 2硬件兼容性选择15.x&#xff0c;&#xff0c;点下一步。 3选择稍后安装操作系统&…

自定义seg_decoder组件并创建Nios系统(一)

前面进行了数码管的显示 对Avalon总线协议进行了大概的学习 那么就可以 将数码管译码器模块封装成符合Avalon-MM接口的组件创建一个基于Nios Ⅱ处理器的系统 将数码管译码器组件添加至该系统中 通过用户应用程序控制数码管显示字符0~F 本文同数码管显示一样并不是完整项目&a…

JavaWeb_瑞吉外卖_项目优化Day12-前后端分离

JavaWeb_瑞吉外卖_项目优化Day12-前后端分离 前后端分离开发介绍开发流程前端技术栈 YapiSwagger介绍使用方式常用注解 项目部署部署架构部署环境说明部署前端项目部署后端项目 来源 前后端分离开发 介绍 开发流程 前端技术栈 开发工具 Visual Studio Codehbuilder 技术框架 …

【全栈开发指南】VUE前端路由设计及配置

我们在使用Vue.js时&#xff0c;创建单页面应用一定会用到路由&#xff0c;Vue Router 是 Vue.js 官方的路由管理器&#xff0c;我们在开发框架中过程中&#xff0c;需要结合Vue Router路由管理器提供的功能&#xff0c;设计和实现系统中菜单的配置。 一、实现原理 一级菜单r…