八大排序(三)堆排序,计数排序,归并排序

一、堆排序

什么是堆排序:堆排序(Heap Sort)就是对直接选择排序的一种改进。此话怎讲呢?直接选择排序在待排序的n个数中进行n-1次比较选出最大或者最小的,但是在选出最大或者最小的数后,并没有对原来的序列进行改变,这使得下一次选数时还需要对全部数据进行比较,效率大大降低。

堆排序的原理:

  1. 将待排序序列构造成一个大顶堆
  2. 此时,整个序列的最大值就是堆顶的根节点
  3. 将其与末尾元素进行交换,此时末尾就为最大值。
  4. 然后将剩余n-1个元素重新构造成一个堆,这样会得到n个元素的次小值。如此反复执行,便能得到一个有序序列了。

如果读到这里,对堆的一些概念不懂得可以翻阅我的另一篇博客“数据结构——【堆】_#欲速则不达#的博客-CSDN博客”,这里面有更详细的堆概念介绍。

代码实现:

#include<stdio.h>
//交换函数
void Swap(int* p1, int* p2)
{int temp = *p1;*p1 = *p2;*p2 = temp;
}
//向下调整
void down(int*a,int n,int parent)
{//大堆int child = parent * 2 + 1;//大堆while (child <n){if (a[child] < a[child + 1] && n > child + 1){child++;}if (a[child] > a[parent]){Swap(&a[child], &a[parent]);parent = child;child = parent * 2 + 1;}else{break;}}
}int main()
{//排序该数组int arr[] = { 5,9,2,6,0,4,8,1,3,7 };//建大堆for (int i = 4; i >=0; i--){down(arr, 10, i);}//将数组再次插入其中int end = 10 - 1;while (end > 0){Swap(&arr[0], &arr[end]);down(arr, end, 0);end--;}//打印for (int i = 0; i < 10; i++){printf("%d ", arr[i]);}return 0;
}

时间复杂度:

二、计数排序

计数排序思路:

  1. 根据待排序集合中最大元素和最小元素的差值范围,申请额外空间;
  2. 遍历待排序集合,将每一个元素出现的次数记录到元素值对应的额外空间内;
  3. 对额外空间内数据进行计算,得出每一个元素的正确位置;
  4. 将待排序集合每一个元素移动到计算得出的正确位置上。

代码实现:

#include<stdio.h>
#include<string.h>
#include<stdlib.h>void CountSort(int* a, int n)
{int min = a[0];int max = a[0];for (int i = 0; i < n; i++){if (a[i] > max){max = a[i];}if (a[i] < min){min = a[i];}}int range = max - min + 1;int* count = (int*)malloc(sizeof(int) * range);printf("range=%d \n", range);if (count == NULL){perror("malloc fail");exit(-1);}memset(count, 0,sizeof(int) * range);for (int i = 0; i < n; i++){count[a[i] - min]++;}//排序int j = 0;for (int i = 0; i < range; i++){while (count[i]--){a[j++] = i + min;}}
}
int main()
{int arr[] = { 4,8,4,3,2,0,9,1,6,8,3,21,7,4,2,1,6,8 };int len = sizeof(arr) / sizeof(int);CountSort(arr, len);for (int i = 0; i < len; i++){printf("%d ",arr[i] );}return 0;
}

时间复杂度:

平均时间复杂度:Ο(n+k)

空间复杂度:Ο(n+k)

三、归并排序

归并排序思路:

归并排序算法有两个基本的操作,一个是分,也就是把原数组划分成两个子数组的过程。另一个是治,它将两个有序数组合并成一个更大的有序数组。

将待排序的线性表不断地切分成若干个子表,直到每个子表只包含一个元素,这时,可以认为只包含一个元素的子表是有序表。
将子表两两合并,每合并一次,就会产生一个新的且更长的有序表,重复这一步骤,直到最后只剩下一个子表,这个子表就是排好序的线性表。

代码实现: 

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
void _MergeSort(int* a, int* tmp, int begin, int end)
{if (begin >= end){return;}int mid = (begin + end) / 2;//分为左右两块//左_MergeSort(a, tmp, begin, mid);//右_MergeSort(a, tmp, mid+1, end);int begin1 = begin;int begin2 = mid+1;int end1 = mid;int end2 = end;int index = begin;while (begin1 <= end1 && begin2 <= end2){if (a[begin1] < a[begin2]){tmp[index++] = a[begin1++];}else{tmp[index++] = a[begin2++];}}while (begin1 <= end1){tmp[index++] = a[begin1++];}while (begin2 <= end2){tmp[index++] = a[begin2++];}memcpy(a + begin, tmp + begin, sizeof(int) * (end - begin + 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);
}/// ///
//归并排序非递归void MergeSortNonR(int* a, int n)
{int* tmp = (int*)malloc(sizeof(int) * n);if (tmp == NULL){perror("malloc fail");return;}int gap = 1;while (gap < n){for (int i = 0; i < n; i += 2 * gap){int begin1 = i, end1 = i + gap - 1;int begin2 = i + gap, end2 = i + 2 * gap - 1;// [begin1,end1] [begin2,end2] 归并if (begin2 >= n){break;}// 如果第二组的右边界越界,修正一下if (end2 >= n){end2 = n - 1;}int index = i;while (begin1 <= end1 && begin2 <= end2){if (a[begin1] < a[begin2]){tmp[index++] = a[begin1++];}else{tmp[index++] = a[begin2++];}}while (begin1 <= end1){tmp[index++] = a[begin1++];}while (begin2 <= end2){tmp[index++] = a[begin2++];}// 拷贝回原数组memcpy(a + i, tmp + i, (end2-i+1) * sizeof(int));}gap *= 2;}free(tmp);
}void Print(int* arr, int n)
{for (int i = 0; i < n; i++){printf("%d ", arr[i]);}printf("\n");
}
int main()
{int arr[] = { 2,5,7,9,1,0,3,4,6,8,10};int len = sizeof(arr) / sizeof(int);MergeSortNonR(arr, len);Print(arr, len);return 0;
}

时间复杂度:

归并排序方法就是把一组n个数的序列,折半分为两个序列,然后再将这两个序列再分,一直分下去,直到分为n个长度为1的序列。然后两两按大小归并。如此反复,直到最后形成包含n个数的一个数组。

归并排序总时间 = 分解时间 + 子序列排好序时间 + 合并时间

无论每个序列有多少数都是折中分解,所以分解时间是个常数,可以忽略不计,则:

归并排序总时间 = 子序列排好序时间 + 合并时间

假设处理的数据规模大小为 n,运行时间设为:T(n),则T(n) = n,当 n = 1时,T(1) = 1

由于在合并时,两个子序列已经排好序,所以在合并的时候只需要 if 判断即可,所以n个数比较,合并的时间复杂度为 n。

将 n 个数的序列,分为两个 n/2 的序列,则:T(n) = 2T(n/2) + n
将 n/2 个数的序列,分为四个 n/4 的序列,则:T(n) = 4T(n/4) + 2n
将 n/4 个数的序列,分为八个 n/8 的序列,则:T(n) = 8T(n/8) + 3n

将 n/2k 个数的序列,分为2k个 n/2k 的序列,则:T(n) = 2kT(n/2k) + kn
当 T(n/2k) = T(1)时, 即n/2k = 1(此时也是把n分解到只有1个数据的时候),转换为以2为底n的对数:k = log2n,把k带入到T(n)中,得:T(n) = n + nlog2n。

使用大O表示法,去掉常数项 n,省略底数 2,则归并排序的时间复杂度为:O(nlogn)

四、八大排序的复杂度和稳定性

稳定排序有:插入排序、冒泡排序、归并排序
不稳定排序:希尔排序、快速排序、选择排序、堆排序
口诀,不稳定的排序:快(快排)些(希尔)选(选择)一堆(堆排)

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

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

相关文章

Python无废话-办公自动化Excel修改数据

如何修改Excel 符合条件的数据&#xff1f;用Python 几行代码搞定。 需求&#xff1a;将销售明细表的产品名称为PG手机、HW手机、HW电脑的零售价格分别修改为4500、5500、7500&#xff0c;并保存Excel文件。如下图 Python 修改Excel 数据&#xff0c;常见步骤&#xff1a; 1&…

docker 基本操作

目录 一、docker 概述 二、容器 2.1容器的特性 2.2namespace的六项隔离 三、docker与虚拟机的区别 四、Docker核心概念 五、docker 基本操作命令 镜像操作 1、搜索镜像 2、获取镜像 3、查看镜像信息 ​编辑 4、查看下载的镜像文件信息 5、查看下载到本地的所有镜…

搭建智能桥梁,Amazon CodeWhisperer助您轻松编程

零&#xff1a;前言 随着时间的推移&#xff0c;人工智能技术以惊人的速度向前发展&#xff0c;正掀起着全新的编程范式革命。不仅仅局限于代码生成&#xff0c;智能编程助手等创新应用也进一步提升了开发效率和代码质量&#xff0c;极大地推动着软件开发领域的快速繁荣。 当前…

SpringCloud(一)Eureka、Nacos、Feign、Gateway

文章目录 概述微服务技术对比 Eureka服务远程调用服务提供者和消费者Eureka注册中心搭建注册中心服务注册服务发现Ribbon负载均衡负载均衡策略饥饿加载 NacosNacos与Eureka对比Nacos服务注册Nacos服务分集群存储NacosRule负载均衡服务实例权重设置环境隔离 Nacos配置管理配置热…

用于自然语言处理的 Python:理解文本数据

一、说明 Python是一种功能强大的编程语言&#xff0c;在自然语言处理&#xff08;NLP&#xff09;领域获得了极大的普及。凭借其丰富的库集&#xff0c;Python 为处理和分析文本数据提供了一个全面的生态系统。在本文中&#xff0c;我们将介绍 Python for NLP 的一些基础知识&…

2023 彩虹全新 SUP 模板,卡卡云模板修复版

2023 彩虹全新 SUP 模板&#xff0c;卡卡云模板&#xff0c;首页美化&#xff0c;登陆页美化&#xff0c;修复了 PC 端购物车页面显示不正常的问题。 使用教程 将这俩个数据库文件导入数据库&#xff1b; 其他的直接导入网站根目录覆盖就好&#xff1b; 若首页显示不正常&a…

计算机网络学习易错点(持续更新~~~)

目录 概述 1.internet和Internet的区别 2.面向连接和无连接 3.不同的T 4.传输速率和传播速率 5.传播时延和传输时延&#xff08;发送时延&#xff09; 6.语法&#xff0c;语义和同步 一.物理层 1.传输媒体与物理层 2.同步通信和异步通信 3.位同步&#xff08;比特同…

nginx多文件组织

背景&#xff1a; nginx的话&#xff0c;有时候&#xff0c;想部署多个配置&#xff0c;比如&#xff1a;使用不同的端口配置不同的web工程。 比如&#xff1a;8081部署&#xff1a;项目1的web页面。 8082部署&#xff1a;项目2的web页面。 1)nginx.conf worker_processes…

Google vs IBM vs Microsoft: 哪个在线数据分析师证书最好

Google vs IBM vs Microsoft: 哪个在线数据分析师证书最好&#xff1f; 对目前市场上前三个数据分析师证书进行审查和比较|Madison Hunter 似乎每个重要的公司都推出了自己版本的同一事物&#xff1a;专业数据分析师认证&#xff0c;旨在使您成为雇主的下一个热门商品。 随着…

7.JavaScript-vue

1 JavaScript html完成了架子&#xff0c;css做了美化&#xff0c;但是网页是死的&#xff0c;我们需要给他注入灵魂&#xff0c;所以接下来我们需要学习JavaScript&#xff0c;这门语言会让我们的页面能够和用户进行交互。 1.1 介绍 通过代码/js效果演示提供资料进行效果演…

嵌入式Linux应用开发-基础知识-第十九章驱动程序基石⑤

嵌入式Linux应用开发-基础知识-第十九章驱动程序基石⑤ 第十九章 驱动程序基石⑤19.9 mmap19.9.1 内存映射现象与数据结构19.9.2 ARM架构内存映射简介19.9.2.1 一级页表映射过程19.9.2.2 二级页表映射过程 19.9.3 怎么给APP新建一块内存映射19.9.3.1 mmap调用过程19.9.3.2 cach…

华为云云耀云服务器L实例评测|部署在线轻量级备忘录 memos

华为云云耀云服务器L实例评测&#xff5c;部署在线轻量级备忘录 memos 一、云耀云服务器L实例介绍1.1 云服务器介绍1.2 产品优势1.3 应用场景1.4 支持镜像 二、云耀云服务器L实例配置2.1 重置密码2.2 服务器连接2.3 安全组配置 三、部署 memos3.1 memos介绍3.2 Docker 环境搭建…

C语言数组

C 语言支持数组数据结构&#xff0c;它可以存储一个固定大小的相同类型元素的顺序集合。数组是用来存储一系列数据&#xff0c;但它往往被认为是一系列相同类型的变量。 数组的声明并不是声明一个个单独的变量&#xff0c;比如 runoob0、runoob1、...、runoob99&#xff0c;而…

Scala第十章

Scala第十章 章节目标 1.数组 2.元组 3.列表 4.集 5.映射 6.迭代器 7.函数式编程 8.案例&#xff1a;学生成绩单 scala总目录 文档资料下载

Jmeter分布式压力测试

目录 1、场景 2、原理 3、注意事项 4、slave配置 5、master配置 6、脚本执行 1、场景 在做性能测试时&#xff0c;单台机器进行压测可能达不到预期结果。主要原因是单台机器压到一定程度会出现瓶颈。也有可能单机网卡跟不上造成结果偏差较大。 例如4C8G的window server机…

防火墙基础之H3C防火墙分支与分支之间双向地址转换

分支与分支之间双向地址转换 原理概述&#xff1a; 防火墙&#xff08;英语&#xff1a;Firewall&#xff09;技术是通过有机结合各类用于安全管理​与筛选的软件和硬件​设备&#xff0c;帮助计算机网络于其内、外网之间构建一道相对隔绝的保护屏障&#xff0c;以保护用户资…

029-从零搭建微服务-消息队列(一)

写在最前 如果这个项目让你有所收获&#xff0c;记得 Star 关注哦&#xff0c;这对我是非常不错的鼓励与支持。 源码地址&#xff08;后端&#xff09;&#xff1a;mingyue: &#x1f389; 基于 Spring Boot、Spring Cloud & Alibaba 的分布式微服务架构基础服务中心 源…

ARP和DDOS攻击防御介绍

ARP攻击如何产生的&#xff1f; ARP如何进行有效的防御&#xff1f; ARP地址解析协议 已知对方ip地址&#xff0c;求得对方mac地址 交换机会自动学习&#xff1a; 当pc1想访问外网&#xff0c;会向外发一个广播包&#xff0c;交换机会收到一个广播包 ARP地址表&#xff1a; …

嵌入式Linux应用开发-基础知识-第十九章驱动程序基石②

嵌入式Linux应用开发-基础知识-第十九章驱动程序基石② 第十九章 驱动程序基石②19.3 异步通知19.3.1 适用场景19.3.2 使用流程19.3.3 驱动编程19.3.4 应用编程19.3.5 现场编程19.3.6 上机编程19.3.7 异步通知机制内核代码详解 19.4 阻塞与非阻塞19.4.1 应用编程19.4.2 驱动编程…

简历项目优化关键方法论-START

START方法论是非常著名的面试法则&#xff0c;经常被面试官使用的工具 Situation:情况、事情、项目需求是在什么情况下发生Task:任务&#xff0c;你负责的做的是什么Action:动作&#xff0c;针对这样的情况分析&#xff0c;你采用了什么行动方式Result:结果&#xff0c;在这样…