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

一、堆排序

什么是堆排序:堆排序(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.mzph.cn/news/93091.shtml

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

相关文章

【牛客网-面试必刷TOP101】二分查找题目

目录 二维数组中的查找_牛客题霸_牛客网 (nowcoder.com) 寻找峰值_牛客题霸_牛客网 (nowcoder.com) 数组中的逆序对_牛客题霸_牛客网 (nowcoder.com) 旋转数组的最小数字_牛客题霸_牛客网 (nowcoder.com) 二维数组中的查找_牛客题霸_牛客网 (nowcoder.com) 题意&#xff1a…

毕业设计选题uniapp+springboot新闻资讯小程序源码 开题 lw 调试

&#x1f495;&#x1f495;作者&#xff1a;计算机源码社 &#x1f495;&#x1f495;个人简介&#xff1a;本人七年开发经验&#xff0c;擅长Java、Python、PHP、.NET、微信小程序、爬虫、大数据等&#xff0c;大家有这一块的问题可以一起交流&#xff01; &#x1f495;&…

Redis 列表类型(List)和命令(数据类型 三)

基本概念 Redis 列表是一种非常实用和多功能的数据结构&#xff0c;适用于各种场景&#xff0c;如消息队列、实时数据流、任务队列、排行榜、历史记录等。 列表底层是压缩列表&#xff08;数据量小、元素简单时&#xff09;和双向循环链表&#xff08;数据量较大、元素复杂时&…

基于 QT 实现一个 Ikun 专属桌面宠物

Step0、实现思路 想到的思路有两种&#xff1a; 1、使用 QT 的状态机模式&#xff0c;参考官网文档&#xff0c;这个模式的解耦最佳 2、使用原生 Wigets&#xff0c;将窗口设置为透明无框&#xff0c;循环播放桌面宠物的状态 本文采用第二种思路&#xff0c;实现一个极简版…

低功耗引擎Cliptrix为什么可以成为IOT的高效能工具

在万物互联的时代&#xff0c;现代人已普遍接受电视、音箱等电器设备具备智能化能力&#xff0c;也是在这个趋势下&#xff0c;我们身边越来越多的iOT设备联网和交互成为刚需。 但iot设备也面临到一些非常显著的痛点&#xff0c;例如iot设备的内存、处理器等核心元件无法与手机…

拉链法和开放寻址法 c++实现

拉链法&#xff08;以下为代码&#xff09; #include<iostream> #include<cstring>using namespace std; const int N100003; int h[N],e[N],ne[N]; int n,idx;void insert(int x){int k(x%NN)%N;e[idx]x;ne[idx]h[k];h[k]idx; }bool find(int x){int k(x%NN)%N;f…

Java之多线程的综合练习二

练习六&#xff1a;多线程统计并求最大值 需求&#xff1a; 在上一题基础上继续完成如下需求&#xff1a; 每次抽的过程中&#xff0c;不打印&#xff0c;抽完时一次性打印(随机) 在此次抽奖过程中&#xff0c;抽奖箱1总共产生了6个奖项。 分别为&#xff1a;10,20,100,50…

Chrome扩展V2到V3的变化

Chrome扩展manifest V3变化、升级迁移指南_chrome_ZK645945-华为云开发者联盟 (csdn.net) 1.background //V2 "background": "background.js"//V3 "background": {"service_worker": "background.js"} 2.executeScript …

[Java·算法·困难]LeetCode124.二叉树中的最大路径和

每天一题&#xff0c;防止痴呆 题目示例分析思路1题解1 &#x1f449;️ 力扣原文 题目 二叉树中的 路径 被定义为一条节点序列&#xff0c;序列中每对相邻节点之间都存在一条边。同一个节点在一条路径序列中 至多出现一次 。该路径 至少包含一个 节点&#xff0c;且不一定经…

对pyside6中的textedit进行自定义,实现按回车可以触发事件。

以下方法不算最优解。因为这个ui文件很容易重新编译&#xff0c;使写在ui.py里面的代码被删掉。 所以更好的方法应该是在主代码当中单独定义控件。并且使用布局添加控件到界面中。 以下内容纯为旧版实现&#xff0c;仅供参考&#xff1a; 我的实现方法是&#xff0c;先用qt de…

拒绝水文!八大排序(三)【适合初学者】快速排序

文章目录 快速排序递归实现霍尔法优化 挖坑法前后指针法 快速排序非递归 大家好&#xff0c;我是纪宁&#xff0c;这篇文章将向大家介绍非常有名气的一款排序&#xff1a;快速排序 回忆到我们刚开始学习C语言的时候。经常会使用到一个库函数&#xff1a; qsort函数 &#xff0…

运维困局下确保系统稳定的可行性

业务高速发展背后的困局 随着业务的快速发展&#xff0c;运维体系也逐步的完善起来。业务的稳定性和服务质量也在监控、可用性等体系的相互环抱下健康地成长。所有的问题、故障及影响稳定性的因素都在可控、可收敛的范围内&#xff0c;一切都向着好的方向发展。 这一切的背后…

【JavaEE】JavaScript

JavaScript 文章目录 JavaScript组成书写方式行内式内嵌式外部式&#xff08;推荐写法&#xff09; 输入输出变量创建动态类型基本数据类型数字类型特殊数字值 String转义字符求长度字符串拼接布尔类型undefined未定义数据类型null 运算符条件语句if语句三元表达式switch 循环语…

Nginx查找耗时的接口

Nginx查找耗时的接口 # grep 是筛选的域名 awk中的$5是判断的状态码 sort中的15是指的upstream_response_time 当然也可以统计request_time的时间cat access.log | grep zhhll.icu | awk $5 200{print $0} | sort -k 15 -n -r | head -10 https://zhhll.icu/2021/linux/实…

百元价位开放式耳机哪款好、百元耳机性价比最高的开放式耳机推荐

现如今越来越多的人选择开放式耳机&#xff0c;因为开放式耳机具有多重优点&#xff0c;首先是舒适性。由于它们不需要插入耳道&#xff0c;长时间佩戴也不会产生不适感。其次&#xff0c;开放式耳机在保持与外界的连接上表现出色&#xff0c;使得户外活动更加安全。另外&#…

Unity Game FrameWork—模块使用—资源热更新

工程选项配置​ json文件解析不要用默认的unity解析方式&#xff0c;unity解析有问题&#xff0c;使用StarForce.LitJsonHelper​ ​ 资源模式改为热更新模式​ ​ 配置文件配置​ BuiltinDataComponent自定义组件引用率了Buildinfo.txt配置文件&#xff0c;该文件配置了热更…

幽默逻辑树

基本逻辑树 以下是一个幽默的逻辑树结构示例&#xff1a; 开始 ├─ 拿出一杯咖啡 ├─ 喝一口咖啡 │ └─ 是否烫嘴&#xff1f; │ ├─ 是 │ │ ├─ 吐出咖啡 │ │ └─ 等待凉一点再喝 │ └─ 否 │ └─ 继续喝咖啡 ├─ …

实时人脸检测:基于卷积神经网络CNN和OpenCV的摄像头应用

一、前言 人脸检测是计算机视觉中的重要任务之一,广泛应用于人脸识别、人脸表情分析、人脸跟踪等领域。在实时视频流中进行人脸检测可以帮助我们快速准确地识别和定位图像中的人脸。本文将介绍如何使用 OpenCV 库来实现通过本地摄像头获取实时视频流,并利用预训练的深度学习…

【GAN对抗性损失函数】以CycleGAN和PIX2PIX算法的对抗性损失的代码为例进行讲解

一、代码 class GANLoss(nn.Module):"""Define different GAN objectives.The GANLoss class abstracts away the need to create the target label tensorthat has the same size as the input."""def __init__(self, gan_mode, target_real_l…

BASH shell脚本篇2——条件命令

这篇文章介绍下BASH shell中的条件相关的命令&#xff0c;包括&#xff1a;if, case, while, until, for, break, continue。之前有介绍过shell的其它基本命令&#xff0c;请参考&#xff1a;BASH shell脚本篇1——基本命令 1. If语句 if语句用于在顺序执行语句的流程中执行条…