【数据结构】排序(3)—堆排序归并排序

                                 

目录

     一. 堆排序

      基本思想  

      代码实现

   向上调整算法

   向下调整算法

      时间和空间复杂度

      稳定性

    二. 归并排序

      基本思想

      代码实现

      时间和空间复杂度

      稳定性



     一. 堆排序

                 堆排序(Heapsort)是指利用堆这种数据结构所设计的一种排序算法。堆积是一个近似            完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)            它的父节点。堆排序可以说是一种利用堆的概念来排序的选择排序

          注意:排升序要建大堆,排降序建小堆  

               大顶堆:每个节点的值都大于或等于其子节点的值

               小顶堆:每个节点的值都小于或等于其子节点的值;

          提示:此次以排升序建大堆为例

           基本思想  

               将待排序的序列构造成一个大根堆。此时,整个序列的最大值就是堆顶的根结点。将它         移走(就是将其与堆数组的末尾元素交换,此时末尾元素就是最大值),然后把剩余的n-1个         序列重新构造成一个堆,就会得到n个元素中的次大值。如此反复执行,便能得到一个有序列。

          算法步骤:          

             ① 创建一个堆 Heap[0……n-1];

             ② 把堆首(最大值)和堆尾互换;

             ③ 把堆的尺寸缩小 1,并调用 shift_down(0),目的是把新的数组顶端数据调整到相应置;

             ④ 重复步骤 2,直到堆的尺寸为 1。

         图示:

    代码实现

         向上调整算法

            思想方法:从第一个结点开始(视为左孩子或右孩子),先找该结点的父结点,在与父节点比较,大的与父结点交换,成为新的父节点;这样依次往下,直到最后一个节点。

         知道孩子结点找父节点:左孩子、 右孩子:parent = (child - 1) / 2 

        图解:

                 

               

void AdjustUp(int* a, int child)
{int parent = (child - 1) / 2; //找父节点while (child > 0){if (a[child] > a[parent]){Swap(&a[child], &a[parent]); //与父结点交换child = parent; //往后走到下一个结点parent = (parent - 1) / 2;}elsebreak;}
}

     向下调整算法

            思想方法:从最后一个元素开始(视为父节点),先找其孩子节点(左孩子或右孩子),与其孩      子结点比较,与大的一方(左孩子或右孩子)交换;依次往上,直到第一个结点。

           知道父节点找孩子:child = parent * 2 + 1

        图解:

          

          

void AdjustDown(int* a, int n, int parent)
{int child = parent * 2 + 1; //找孩子while (child < n){//找左右孩子较小的if (child+1 < n && a[child + 1] > a[child])child++;if (a[child] > a[parent]){Swap(&a[child], &a[parent]); //与父节点交换parent = child;  child = parent * 2 + 1;}elsebreak;}
}

      

  通过向上调整或向下调整算法建堆后,进行堆排序,此程序为向下调整建堆。

   图解:

               

  

void AdjustDown(int* a, int n, int parent)
{int child = parent * 2 + 1;while (child < n){if (child+1 < n && a[child + 1] > a[child])child++;if (a[child] > a[parent]){Swap(&a[child], &a[parent]);parent = child;child = parent * 2 + 1;}elsebreak;}
}//堆排序
void HeapSort(int* a, int n)
{//向下调整建堆for (int i = (n-1-1)/2; i >= 0; i--){AdjustDown(a,n,i);}int end = n - 1;while (end > 0) {Swap(&a[0], &a[end]);AdjustDown(a, end, 0);end--;}
}

   时间和空间复杂度

            时间复杂度:O(nlogn)

            空间复杂度:O(1)

   稳定性

            堆排序:不稳定排序
 

  二. 归并排序

       基本思想

             将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段            间有序。若将两个有序表合并成一个有序表,称为二路归并

      算法步骤:         

      ① 申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列;

      ② 设定两个指针,最初位置分别为两个已经排序序列的起始位置

      ③ 比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置;

      ④ 重复步骤 3 直到某一指针达到序列尾;

      ⑤ 将另一序列剩下的所有元素直接复制到合并序列尾

        图示

       

       代码实现

                   

void _MergeSort(int* a, int* tmp, int left, int right)
{if (left >= right)return;int mid = (left + right) / 2;_MergeSort(a, tmp, left, mid); //递归左边_MergeSort(a, tmp, mid+1, right); //递归右边// 将a数组元素归并到tmp数组,再拷贝回a数组int left1 = left, right1 = mid;int left2 = mid + 1, right2 = right;int index = left;while (left1 <= right1 && left2 <= right2){if (a[left1] <= a[left2])tmp[index++] = a[left1++];elsetmp[index++] = a[left2++];}while(left1 <= right1)   //左>右,将左区间剩余元素拷贝到tmp数组tmp[index++] = a[left1++];while(left2 <= right2)   //左<右,将右区间剩余元素拷贝到tmp数组tmp[index++] = a[left2++];//拷贝回原数组memcpy(a + left, tmp + left, sizeof(int) * (right - left + 1));
}//归并排序
void MergeSort(int* a, int n)
{int* tmp = (int*)malloc(sizeof(int) * n);if (tmp == NULL){perror("malloc fail");return;}_MergeSort(a, tmp, 0, n - 1);free(tmp);
}

       

时间和空间复杂度

         时间复杂度:O(nlogn)

         空间复杂度:O(n)   归并排序时需要和待排序记录个数相等的存储空间

稳定性

      归并排序:稳定排序

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

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

相关文章

蓝桥等考Python组别十四级002

第一部分&#xff1a;选择题 1、Python L14 &#xff08;15分&#xff09; 运行下面程序&#xff0c;输出的结果是&#xff08; &#xff09;。 d {A: 11, B: 12, C: 13, D: 14} print(d[B]) 11121314 正确答案&#xff1a;B 2、Python L14 &#xff08;15分&#x…

JMeter性能测试

性能测试前言 老师开局一句话&#xff1a;性能测试和你会不会JMeter一点关系没有…… 作者坚持技多不压身的原则&#xff0c;还是多学一点JMeter吧&#xff0c;看老师到底要怎么讲下去&#xff0c;什么并发量、吞吐量啥的…… 性能测试的核心思想&#xff1a;在于创造大量并发去…

(32)测距仪(声纳、激光雷达、深度摄影机)

文章目录 前言 32.1 单向测距仪 32.2 全向性近距离测距仪 32.3 基于视觉的传感器 前言 旋翼飞机/固定翼/无人车支持多种不同的测距仪&#xff0c;包括激光雷达&#xff08;使用激光或红外线光束进行距离测量&#xff09;、360 度激光雷达&#xff08;可探测多个方向的障碍…

【C++】:类和对象(2)

朋友们、伙计们&#xff0c;我们又见面了&#xff0c;本期来给大家解读一下有关Linux的基础知识点&#xff0c;如果看完之后对你有一定的启发&#xff0c;那么请留下你的三连&#xff0c;祝大家心想事成&#xff01; C 语 言 专 栏&#xff1a;C语言&#xff1a;从入门到精通 数…

透明度和透明贴图制作玻璃水杯

1、什么是透明度 模型透明度是指一个物体或模型在呈现时的透明程度。它决定了物体在渲染时&#xff0c;是否显示其后面的物体或背景。 在图形渲染中&#xff0c;透明度通常以0到1之间的值表示。值为0表示完全透明&#xff0c;即物体不可见&#xff0c;背景或其他物体完全穿透…

Python之元组

Python之元组 元组tuple 一个有序的元素组成的集合使用小括号 ( ) 表示元组是不可变对象 tuple(), (), type(()) # 空元组 ((), (), tuple)(1,), (1) # 元组中只有1必须加逗号&#xff0c;否则就是1了 # ((1,), 1)x 1, 2 # 以逗号分隔的内容会形成元组&#xff0c;封装元组x…

JVM-满老师

JVM 前言程序计数器&#xff0c;栈&#xff0c;虚拟机栈&#xff1a;本地方法栈&#xff1a;堆&#xff0c;方法区&#xff1a;堆内存溢出方法区运行时常量池 垃圾回收垃圾回收算法分代回收 前言 JVM 可以理解的代码就叫做字节码&#xff08;即扩展名为 .class 的文件&#xff…

目标检测算法改进系列之Backbone替换为RIFormer

RIFormer简介 Token Mixer是ViT骨干非常重要的组成成分&#xff0c;它用于对不同空域位置信息进行自适应聚合&#xff0c;但常规的自注意力往往存在高计算复杂度与高延迟问题。而直接移除Token Mixer又会导致不完备的结构先验&#xff0c;进而导致严重的性能下降。 原文地址&…

【JavaEE】JUC(Java.util.concurrent)常见类

文章目录 前言ReentrantLock原子类线程池信号量CountDownLatch相关面试题 前言 经过前面文章的学习我们大致了解了如何实现多线程编程和解决多线程编程中遇到的线程不安全问题&#xff0c;java.util.concurrent 是我们多线程编程的一个常用包&#xff0c;那么今天我将为大家分…

基于安卓android微信小程序的校园维修平台

项目介绍 随着社会的发展&#xff0c;社会的方方面面都在利用信息化时代的优势。互联网的优势和普及使得各种系统的开发成为必需。 本文以实际运用为开发背景&#xff0c;运用软件工程原理和开发方法&#xff0c;它主要是采用java语言技术和mysql数据库来完成对系统的设计。整…

gitgitHub

在git中复制CtrlInsert、粘贴CtrlShif 一、用户名和邮箱的配置 查看用户名 &#xff1a;git config user.name 查看密码&#xff1a; git config user.password 查看邮箱&#xff1a;git config user.email 查看配置信息&#xff1a; $ git config --list 修改用户名 git co…

Python 无废话-基础知识面向对象编程详解

类定义 如何理解万物皆对象&#xff1f; 生活中一些事物&#xff0c;动物&#xff08;可爱的小狗、调皮的小猫&#xff09;、交通工具&#xff08;比亚迪U8汽车、飞机&#xff09;、人&#xff08;学生、教师&#xff09;…… 这些对象都有着独特或共性的属性和方法来描述其…