九大排序之选择排序和归并排序

1.前言

每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,直到全部待排序的数据元素排完 。

本章重点:

堆排序和选择排序和归并排序

2.选择排序

基本思路

  • left和right记录区间的左端和右端;

  • 不断遍历数组,经过一次遍历选出区间中的最大值和最小值;

  • 然后将最小值换到左端,最大值换到右端;

  • ++left; --right; 当left < right时循环继续。

 注意:交换元素时如果先后交换的下标恰好相同需要做出调整。

代码如下:

void SelectSrot(int *arr, int n){
	assert(arr != NULL);
	
	int begin = 0;
	int end = n-1;
	//begin,end向中间靠拢
	while (begin < end)
	{
		int maxi = begin;
		int mini = begin;
		//一次循环找出一个最大值和一个最小值分别放到begin和end位置
		for (int i = begin; i <= end; i++)
		{
			if (arr[i] < arr[mini])
			{
				mini = i;
			}
			if (arr[i] > arr[maxi])
			{
				maxi = i;
			}
		}
		//因为先将maxi和end交换,所以当后换的mini==end 时原来end的值已经被换走了,转换一下
		if (maxi == begin)
		{
			maxi = mini;
		}
        Swap(&arr[begin], &arr[mini]);	
		Swap(&arr[end], &arr[maxi]);
		begin++;
		end--;
	}
}

 

  • 直接选择排序的特性总结:
    1. 选择排序思路简单好理解,但是对有序序列无反应,复杂度恒为O(N^2)。效率低,实际中很少使用。
    2. 时间复杂度:O(N^2)
    3. 空间复杂度:O(1)
    4. 稳定性:不稳定(有可能两个相等元素的相对顺序会发生变化)
    5. 数据敏感性:不敏感,不管有序无序都要进行多轮次的选择

2.堆排序

在写堆排序之前先写一个节点向上调整和节点向下调整

AdJustDown:

//向下调整,小的在上,大的在下
void AdjustDown(int *arr, int sz, int root)//父亲节点的下标
{
    assert(arr!=nullptr);
    int parent=root;
    int child=2*parent+1;//左节点
    while(child<sz)
    {
        //先判断谁小---找小
        if(child+1<sz&&arr[child]<arr[child+1])
            child++;
        if(arr[child]<arr[parent])
        {
            swap(&arr[child],&arr[parent]);
            parent=child;
            child=2*parent+1;
        }
        else  break;
    }
}

AdJustUp:向上调整

//向上调整---大的在顶部
void  AdJustUp(int *arr,int sz,int root)//这里传来的是孩子节点
{
    assert(arr!=nullptr);
    int child=root;
    int parent=(child-1)/2;
    while(child<sz)
    {
        if(arr[child]<arr[parent])
        {
            swap(&arr[child],&arr[parent]);
            child=parent;
            parent=(child-1)/2;
        }
        else break;
    }
    
}

构建一个堆,一般来说都是从第一个非叶子节点开始构建堆。

void  HeapSort(int* arr,int sz)
{
      assert(arr!=nullptr);
      for(int i=(sz-1-1)/2;i>=0;i--)
       {
           AdJustDown(arr,sz,i);
       }

       //大堆建立完了之后。开始排序
       for(int end=sz-1;end>=0;end--)
    {
        swap(&arr[end],&arr[0]);//最大值调整到了最后一个,最小值调整到了第一个
        AdJustDown(arr,sz,0);//再把最小值进行调整
        
    }    
}

思路总结:

1.首先写一个向上调整或者向下调整函数

2.调整堆:如果是需要升序的话---那么就是大堆---大堆就是说大的在上

                  如果是需要降序的话--那么就是小堆---小堆就是说小的在上

3.利用堆删除的思想来进行排序

  • 记录堆尾下标end;

  • 交换堆顶(0)堆尾(end)元素——将最大值交换到序列尾。

  • 向下调整,但此时的调整范围到end——恢复堆结构选出最大值

  • –end——进行下一轮选择交换。

堆排序(Heapsort)是指利用堆积树(堆)这种数据结构所设计的一种排序算法,它是选择排序的一种。它是通过堆来进行选择数据。需要注意的是排升序要建大堆,排降序建小堆

  • 堆排序的特性总结:

    堆排序使用堆来选数,效率就高了很多。
  • 时间复杂度:O(N*logN)
  • 空间复杂度:O(1)
  • 稳定性:不稳定,由于使用了堆结构,无法保证稳定性数据
  • 敏感性:不敏感,不管有序无序都要重新建堆排序

3.归并排序

归并排序就是找到一个基准值,大的在基准值的右,小的在基准值的左边。

然后开始递归-------当只有一个元素时就不需要了,然后返回上一层,再次进行排序即可。

具体步骤如下:

  1. 正式排序前需要创建与待排数组相同大小的数组tmp。

  2. 首先计算出中间位置的下标,将序列一分为二。

  3. 如果子区间元素个数大于1则向下递归先使左右子区间有序

  4. 然后将左右子区间归并到tmp数组

  5. 最后将数据考回原数组。

代码如下:

void _MergeSort(int *arr, int left, int right, int *tmp)
{
	//注意递归的结束条件
	if (left >= right)
	{
		return;
	}
	//计算出中间位置的下标
	int mid = left + (right - left) / 2;
	//划分左右区间
	int begin1 = left, end1 = mid;
	int begin2 = mid + 1, end2 = right;
	//先使左右两区间有序
	_MergeSort(arr, begin1, end1, tmp);
	_MergeSort(arr, begin2, end2, tmp);
	//将左右两区间归并到tmp数组
	//注意排序的区间不从0开始
	int i = left;
	while (begin1 <= end1 && begin2 <= end2)
	{
		if (arr[begin1] < arr[begin2])
		{
			tmp[i++] = arr[begin1++];
		}
		else
		{
			tmp[i++] = arr[begin2++];
		}
	}
	while (begin1 <= end1)
	{
		tmp[i++] = arr[begin1++];
	}
	while (begin2 <= end2)
	{
		tmp[i++] = arr[begin2++];
	}
	//将排好的数据从tmp数组考回arr
	for (int j = left; j <= right; j++)//注意这里一定是从left-right而不是从0-sz-1
    //因为当递归进去之后,就不一定是0-sz-1了。也有可能是只有两个数:例 下标2-3
	{
		arr[j] = tmp[j];
	}
}

void MergeSort(int *arr, int sz){
	//递归排序过程中需使用额外空间
	int *tmp = (int*)malloc(sizeof(int) * sz);
	if (tmp == NULL)
	{
		perror("MergeSort");
		exit(1);
	}
	_MergeSort(arr, 0, sz - 1, tmp);

	//排序结束后记得释放额外空间
	free(tmp);
	tmp = NULL;
}

 将数组一分为二,先使数组的左右区间有序,再将左右区间归并成一个有序数组。对比快速排序,归并排序与二叉树的后序遍历思想更为相似。

归并排序解决磁盘问题:

归并排序的特点:

1. 归并排序兼具高效、稳定、数据不敏感的特点;缺点在于需要O(N)的空间。常用于外排序问题。
2. 时间复杂度:O(N*logN)
3. 空间复杂度:O(N)
4. 稳定性:稳定
5. 数据敏感性:不敏感---即使是数据已经有序,也要进行排列(可以称这种排列为伪排列)。

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

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

相关文章

Opencv库的安装与vs项目配置(vs成功配置opencv库)

目录 一、下载安装opencv 1、下载 2、减压安装 3、环境变量配置 二、vs项目配置opencv 1、创建vs项目 2、配置opencv库 3、测试 其中&#xff1a;二、2、配置opencv库是最复杂的&#xff0c;有空需要搞清楚vs中配置不同地方的区别。 以下所有测试是opencv官方4.6.0 w…

差分的数学定义——由泰勒展开式推导

差分是数值分析中的概念&#xff0c;用于近似连续函数的导数。差分可以通过多种方式定义&#xff0c;一阶差分常见的有前向差分、后向差分和中心差分&#xff0c;二阶差分常用的是中心差分法。 一阶差分 1. 前向差分 (Forward Difference) 对于一个函数 f ( x ) f(x) f(x)&…

机器学习数据标准化与归一化:提升模型精度的关键

&#x1f4d8;数据标准化与归一化&#xff1a;提升模型精度的关键 机器学习中的数据处理环节至关重要&#xff0c;其中&#xff0c;数据标准化与归一化是提高模型性能的关键步骤之一。数据的特征尺度往往不一致&#xff0c;直接影响模型的训练效果&#xff0c;因此对数据进行处…

大数据开发基础实训室设备

大数据实验实训一体机 大数据实验教学一体机是一种专为大数据教育设计的软硬件融合产品&#xff0c;其基于华为机架服务器进行了调优设计&#xff0c;从而提供了卓越的性能和稳定性。这一产品将企业级虚拟化管理系统与实验实训教学信息化平台内置于一体&#xff0c;通过软硬件…

【超详细】TCP协议

TCP(Transmission Control Protocol 传输控制协议) 传输层协议有连接可靠传输面向字节流 为什么TCP是传输控制协议呢&#xff1f; 我们以前所看到的write接口&#xff0c;都是把用户级缓冲区的数据拷贝到发送缓冲区中&#xff0c;然后数据就由TCP自主决定了&#xff0c;所以…

番茄工作法计时器:高效时间管理利器

《番茄工作法计时器&#xff1a;高效时间管理利器》 在快节奏的现代生活中&#xff0c;高效管理时间成为每个人的迫切需求。今天&#xff0c;我们为你推荐一款强大的番茄工作法计时器。 这款计时器设计简洁&#xff0c;操作便捷&#xff0c;仅有两个按钮 —— 工作 25 分钟和休…

【未公开0day】RaidenMAILD CVE-2024-32399 路径穿越漏洞【附poc下载】

免责声明&#xff1a;本文仅用于技术学习和讨论。请勿使用本文所提供的内容及相关技术从事非法活动&#xff0c;若利用本文提供的内容或工具造成任何直接或间接的后果及损失&#xff0c;均由使用者本人负责&#xff0c;所产生的一切不良后果均与文章作者及本账号无关。 fofa语…

【C++】创建TCP服务端

实现了一个基本的 TCP 服务器&#xff0c;可以接受多个客户端连接&#xff0c;然后持续接收客户端发送的信息&#xff0c; 最后将接收到的信息再发送回客户端 。 源码 头文件&#xff08;TCPServerTest.h&#xff09; #include <iostream> #include <winsock2.h&g…

Idea序列图插件-SequenceDiagram Core

&#x1f496;简介 SequenceDiagram Core 是一个 IntelliJ IDEA 插件&#xff0c;它允许开发者直接在 IDE中创建和编辑序列图&#xff08;Sequence Diagrams&#xff09;。序列图是 UML&#xff08;统一建模语言&#xff09;中的一种图表类型&#xff0c;用于描述对象之间如何…

【Java 22 | 10】 深入解析Java 22 :Vector API 增强特性

Java 22 对 Vector API 进行了重要增强&#xff0c;旨在提供更高效的矢量操作能力&#xff0c;以支持性能关键的应用程序。Vector API 允许开发者利用硬件的 SIMD&#xff08;单指令多数据&#xff09;特性&#xff0c;从而在处理数组和集合等数据时显著提高性能。 1. 基础介绍…

谷歌-BERT-第一步:模型下载

1 需求 需求1&#xff1a;基于transformers库实现自动从Hugging Face下载模型 需求2&#xff1a;基于huggingface-hub库实现自动从Hugging Face下载模型 需求3&#xff1a;手动从Hugging Face下载模型 2 接口 3.1 需求1 示例一&#xff1a;下载到默认目录 from transform…

微带传输线 - 本征模 - Alpha 衰减常数与S21插损_CST软件案例

关于Beta之前的文章解释了很多&#xff0c;这期说说Alpha。α 是衰减常数&#xff08;attenuation constant&#xff09;&#xff0c;表示波损耗&#xff0c;和S21插损相关&#xff0c;但这几个量很多人还是搞不清楚。 首先&#xff0c;S21和插损Insertion Loss严格上讲是不一…

Spring Boot与JavaWeb协同:在线考试系统的实现“

1系统概述 1.1 研究背景 随着计算机技术的发展以及计算机网络的逐渐普及&#xff0c;互联网成为人们查找信息的重要场所&#xff0c;二十一世纪是信息的时代&#xff0c;所以信息的管理显得特别重要。因此&#xff0c;使用计算机来管理基于JavaWeb技术的在线考试系统设计与实现…

请求参数中字符串的+变成了空格

前端请求 后端接收到的结果 在URL中&#xff0c;某些字符&#xff08;包括空格、、&、? 等&#xff09;需要被编码。具体而言&#xff0c;在URL中&#xff0c;空格通常被编码为 或 %20。因此&#xff0c;如果你在请求参数中使用 &#xff0c;它会被解释为一个空格。 如果…

【C++贪心】2086. 喂食仓鼠的最小食物桶数|1622

本文涉及知识点 C贪心 LeetCode2086. 喂食仓鼠的最小食物桶数 给你一个下标从 0 开始的字符串 hamsters &#xff0c;其中 hamsters[i] 要么是&#xff1a; ‘H’ 表示有一个仓鼠在下标 i &#xff0c;或者’.’ 表示下标 i 是空的。 你将要在空的位置上添加一定数量的食物桶…

QUIC(Quick UDP Internet Connections)与 RTMP(Real Time Messaging Protocol)

QUIC&#xff08;Quick UDP Internet Connections&#xff09;和 RTMP&#xff08;Real Time Messaging Protocol&#xff09;是两种不同的网络传输协议&#xff0c;它们在一些方面有不同的特点和应用场景。 QUIC 协议 特点 基于 UDP&#xff1a;QUIC 建立在 UDP 之上&#xff…

unity静态批处理

unity静态批处理 静态批处理要求和兼容性渲染管线兼容性 使用静态批处理在构建时进行静态批处理在构建时执行静态批处理的步骤&#xff1a; 在运行时进行静态批处理性能影响 静态批处理 静态批处理是一种绘制调用批处理方法&#xff0c;它将不移动的网格组合在一起&#xff0c…

合并与变形

目录 合并 准备数据 append关键字 concat关键字 merge关键字 join关键字 变形 df.T行列转置 透视表 合并 很多情况下需要将多个df合并为一个新的df df1.append(df2) 纵向合并数据集 pd.concat([df1, df2, ...]) 横向或纵向合并数据集&#xff0c;df1和df2可以没有任何…

企业微信开放平台注册流程

目录 网址 注册步骤 准备工作 填写信息 微信认证 填写发票 支付费用 完成注册 网址 微信开放平台&#xff1a; https://open.weixin.qq.com/ 注册步骤 准备工作 企业版&#xff1a; 没有注册过微信其他平台&#xff08;如&#xff1a;微信小程序&#xff0c;微信公众…

澳鹏干货 | 大语言模型的上下文窗口 (Context Windows)

大语言模型&#xff08;LLMs&#xff09;极大地提升了人工智能在理解和生成文本方面的能力。其中一个影响其效用的重要方面是“上下文窗口”&#xff08;Context Windows&#xff09;—— 这个概念直接影响着模型接收和生成语言的有效性。 本期澳鹏干货将深入探讨上下文窗口对…