当前位置: 首页 > news >正文

【数据结构初阶】--排序(二)--直接选择排序,堆排序

🔥个人主页:@草莓熊Lotso

🎬作者简介:C++研发方向学习者

📖个人专栏: 《C语言》 《数据结构与算法》《C语言刷题集》《Leetcode刷题指南》

⭐️人生格言:生活是默默的坚持,毅力是永久的享受。

前言:在前面的学习中,我们实现了顺序表和链表,栈和队列以及二叉树。通过这些知识的学习和实现我们的代码能力也有了一定的提升。那么我们从这篇博客就继续接着上一篇博客实现完的排序往后写。还是和之前一样,我们先分部分来讲解。


目录

一.直接选择排序

代码实现: 

时间复杂度: 

二.堆排序

代码实现:

时间复杂度: 

三.直接选择排序和堆排序的性能对比

代码演示:


一.直接选择排序

  1. 在元素集合 array[i]--array[n-1] 中选择关键码最大(小)的数据元素
  2. 若它不是这组元素中的最后⼀个(第⼀个)元素,则将它与这组元素中的最后一个(第一个)元素交换
  3. 在剩余的 array[i]--array[n-2](array[i+1]--array[n-1]) 集合中,重复上述步骤,直到集合剩余 1 个元素

--在实现选择排序之前,我们还需要先实现一共交换的函数

void swap(int* a, int* b)
{int tmp = *a;*a = *b;*b = tmp;
}

--我们如果只选最小或最大值的话那时间复杂度肯定就是O(n),我们可以优化一下,让它们同时选择最大和最小的 

代码实现: 

//选择排序
//1)直接选择排序
void SelectSort(int* arr, int n)
{int begin = 0;int end = n - 1;while (begin < end){int mini = begin;int maxi = end;//这里从end开始的话后面的i就不再能从begin+1开始了for (int i = begin; i <= end; i++){if (arr[i] < arr[mini]){mini = i;}if (arr[i] > arr[maxi]){maxi = i;}}if (begin == maxi){maxi = mini;}swap(&arr[begin], &arr[mini]);swap(&arr[end], &arr[maxi]);++begin;--end;}
}

图示如下:

test.c: 

#include"Sort.h"void PrintArr(int* arr, int n)
{for (int i = 0; i < n; i++){printf("%d ", arr[i]);}printf("\n");
}void test1()
{int a[] = { 5, 3, 9, 6, 2, 4, 7, 1, 8 };int size = sizeof(a) / sizeof(a[0]);printf("排序前:");PrintArr(a, size);//直接选择排序SelectSort(a, size);printf("排序后:");PrintArr(a, size);
}int main()
{test1();return 0;
}

--测试完成,打印没有问题,升序排列正确,退出码为0

时间复杂度: 

  • O(n^2)

--这个时间复杂度没啥可讲的了,很好算出来,直接选择排序在实际运用中比较少 


二.堆排序

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

--堆排序在之前二叉树(三)的博客中讲的很详细,这里就不过多介绍了,给大家看一下它的代码和时间复杂度吧,在实现之前我们需要用到向下调整算法和交换函数,交换在上面实现过了,这里先把向下调整算法的代码给大家

向下调整算法(建大堆版):

//向下调整算法--O(logn)
void AdjustDown(int* arr, int parent, int n)
{int child = 2 * parent + 1;while (child < n){if (child + 1 < n && arr[child] < arr[child + 1]){child++;}if (arr[child] > arr[parent]){swap(&arr[child], &arr[parent]);parent = child;child = 2 * parent + 1;}else {break;}}
}

代码实现:

void HeapSort(int* arr, int n)
{//向下调整建堆,升序建大堆for (int i = (n - 1 - 1) / 2; i >= 0; i--){AdjustDown(arr, i, n);}int end = n - 1;while (end > 0){swap(&arr[0], &arr[end]);AdjustDown(arr, 0, end);end--;}
}

test.c:

#include"Sort.h"void PrintArr(int* arr, int n)
{for (int i = 0; i < n; i++){printf("%d ", arr[i]);}printf("\n");
}void test1()
{int a[] = { 5, 3, 9, 6, 2, 4, 7, 1, 8 };int size = sizeof(a) / sizeof(a[0]);printf("排序前:");PrintArr(a, size);//直接插入排序//InsertSort(a, size);//希尔排序//ShellSort(a, size);//直接选择排序//SelectSort(a, size);//堆排序HeapSort(a, size);printf("排序后:");PrintArr(a, size);
}int main()
{test1();return 0;
}

--测试完成,打印没有问题,升序排序正确,退出码为0 

时间复杂度: 

  • O(n*logn)

 --这个在之前二叉树(四)这篇博客中具体分析过,大家可以自己去看看


三.直接选择排序和堆排序的性能对比

--我们还是通过测试来对比一下这两种排序的性能,大家也可以看看和之前实现过的排序的对比

代码演示:

#include"Sort.h"void PrintArr(int* arr, int n)
{for (int i = 0; i < n; i++){printf("%d ", arr[i]);}printf("\n");
}void test1()
{int a[] = { 5, 3, 9, 6, 2, 4, 7, 1, 8 };int size = sizeof(a) / sizeof(a[0]);printf("排序前:");PrintArr(a, size);//直接插入排序//InsertSort(a, size);//希尔排序//ShellSort(a, size);//直接选择排序//SelectSort(a, size);//堆排序HeapSort(a, size);printf("排序后:");PrintArr(a, size);
}// 测试排序的性能对⽐
void TestOP()
{srand(time(0));const int N = 100000;int* a1 = (int*)malloc(sizeof(int) * N);int* a2 = (int*)malloc(sizeof(int) * N);int* a3 = (int*)malloc(sizeof(int) * N);int* a4 = (int*)malloc(sizeof(int) * N);for (int i = 0; i < N; ++i){a1[i] = rand();a2[i] = a1[i];a3[i] = a1[i];a4[i] = a1[i];}int begin1 = clock();InsertSort(a1, N);int end1 = clock();int begin2 = clock();ShellSort(a2, N);int end2 = clock();int begin3 = clock();SelectSort(a3, N);int end3 = clock();int begin4 = clock();HeapSort(a4, N);int end4 = clock();printf("InsertSort:%d\n", end1 - begin1);printf("ShellSort:%d\n", end2 - begin2);printf("SelectSort:%d\n", end3 - begin3);printf("HeapSort:%d\n", end4 - begin4);free(a1);free(a2);free(a3);free(a4);
}int main()
{TestOP();//test1();return 0;
}

--测试完成,我们可以看出堆排序要比直接选择排序快很多


往期回顾: 

【数据结构初阶】--二叉树(四)

【数据结构初阶】--二叉树(五)

【数据结构初阶】--二叉树(六)

【数据结构初阶】--排序(一):直接插入排序,希尔排序

结语:本篇博客就到此结束了,主要实现了一下两种选择排序,一个直接选择排序,一个堆排序。我们通过对比可知堆排序优于直接选择排序。这里声明一下,博主这里展示的都是Sort.c文件和test.c文件,其中.h文件由于比较简单这里就不展示了,大家可以直接看图片。如果文章对你有帮助的话,欢迎评论,点赞,收藏加关注,感谢大家的支持。

http://www.lryc.cn/news/608091.html

相关文章:

  • AI Agent开发学习系列 - LangGraph(10): 带有循环的Looping Graph(练习解答)
  • JavaScript特殊集合WeakMap 的使用及场景介绍
  • 【昇腾推理PaddleOCR】生产级部署方式
  • 什么是AWS Region和AWS Availability Zones
  • php完整处理word中表单数据的方法
  • Word怎样转换为PDF
  • 使用AWS免费EC2自建RustDesk远程桌面连接服务
  • 【iOS】3GShare仿写
  • 市政污水厂变频器联网改造方案-profibus转ethernet ip网关(通俗版)
  • 疏老师-python训练营-Day33 MLP神经网络的训练
  • 详解Python标准库之命令行界面库
  • 【05】OpenCV C#——OpenCvSharp 图像基本操作---转灰度图、边缘提取、兴趣区域ROI,图像叠加
  • MyBatisPlus之CRUD接口(IService与BaseMapper)
  • 西门子 G120 变频器全解析:从认知到参数设置
  • 技巧|SwanLab记录ROC曲线攻略
  • LINUX82 shell脚本变量分类;系统变量;变量赋值;四则运算;shell
  • 系统性学习数据结构-第一讲-算法复杂度
  • MySQL 内置函数
  • ADB 查看 CPU 信息、查看内存信息、查看硬盘信息
  • 排序算法大全:从插入到快速排序
  • k8s使用 RBAC 鉴权
  • 论文阅读笔记:Dataset Condensation with Gradient Matching
  • [C++竞赛]数论
  • 深入 Go 底层原理(十三):interface 的内部表示与动态派发
  • [硬件电路-113]:模拟电路 - 信号处理电路 - 二极管的应用 - 精密整流电路与波形
  • sqli-labs:Less-18关卡详细解析
  • Json Jsoncpp
  • hyper-v实战系列:第一代虚拟机转第二代步骤
  • 深入理解 Docker 容器网络:为什么用 host 网络模式能解决连通性问题?
  • yolo 、Pytorch (5)IOU