C数据结构与算法——常见排序算法时间复杂度比较 应用

实验任务

(1) 掌握常见比较排序算法的实现;
(2) 掌握常用比较排序算法的性能及其适用场合。

实验内容

(1) 平均时间复杂度O(n2)和O(nlog2n)的算法至少各选两种实现;
(2) 待排序的无重复关键字存放在一维整型数组中,数量为60000个;
(3) 对于不同的排序算法,分成两轮进行性能对比:
     第1轮对比:关键字初始为升序状态;
     第2轮对比:关键字初始为乱序状态;

实验源码

// 由于临近期末,所以插入排序和快速排序不加以验证(读者自行验证)#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <profileapi.h>#define LENGTH(arr) (sizeof(arr)/sizeof((arr)[0])) // 计算数组长度void PrintCompare(int arr[], int length); // 打印排序结果
void knuthShuffle(int arr[], int length); // 洗牌算法
void swapInt(int *card_1, int *card_2); // 交换函数
double BubbleSortTimes(int arr[], int length); // 冒泡排序测时
double SelectSortTimes(int arr[], int length); // 选择排序测时
double HeapSortTimes(int arr[], int length); // 堆排序测时
void adjustHeap(int arr[], int i, int length); // 堆排序核心部分(大小堆顶)
double MergeSortTimes(int arr[], int length); // 归并排序测时
void mergeSort(int arr[], int left, int right, int temp[]); // 归分
void merge(int arr[], int left, int mid, int right, int temp[]); // 分治int main() {srand(time(NULL)); // 初始化随机种子printf("======= 排序算法对比 (将 60000 个无重复有序/乱序数据按升序排序)=======\n");printf("\n");printf("------------------- 第01轮比较 初始有序序列排序性能 --------------------\n");int arr[60000];// 有序数组for (int i = 0; i < LENGTH(arr); i++) { // 一副有序牌arr[i] = i + 1;}PrintCompare(arr, LENGTH(arr));printf("\n");printf("------------------- 第02轮比较 初始乱序序列排序性能 --------------------\n");// 无序数组knuthShuffle(arr, LENGTH(arr)); // 洗牌打乱顺序PrintCompare(arr, LENGTH(arr));printf("\n= 测试环境:i7-9750HF @ 4.12Ghz | 16GB RAM | Win 11 X64 | Clion 2022.1 =");getchar();
}void PrintCompare(int arr[], int length) {int tempArr[length];printf("\n ---- 排序算法 ----- - 排序耗时 - ---- 随机展示5个排序后的连续数据 -----\n");printf("【时间复杂度  O(n^2)】\n");for (int i = 0; i < length; i++) {tempArr[i] = arr[i];}printf("  冒泡排序\t\t%7.2lf ms", BubbleSortTimes(tempArr, length));int randIndex = rand() % length; // 0 - (length-1)int printNum = 5;for (int i = 0; i < printNum; i++) {if (tempArr[randIndex] >= (length - printNum)) {i = 0;} else {printf("%7d", tempArr[randIndex++]);}}printf("\n");for (int i = 0; i < length; i++) {tempArr[i] = arr[i];}printf("  直接选择排序\t\t%7.2lf ms", SelectSortTimes(tempArr, length));randIndex = rand() % length; // 0 - (length-1)printNum = 5;for (int i = 0; i < printNum; i++) {if (tempArr[randIndex] >= (length - printNum)) {i = 0;} else {printf("%7d", tempArr[randIndex++]);}}printf("\n");printf("【时间复杂度O(nlogn)】\n");for (int i = 0; i < length; i++) {tempArr[i] = arr[i];}printf("  堆排序\t\t%7.2lf ms", HeapSortTimes(tempArr, length));randIndex = rand() % length; // 0 - (length-1)printNum = 5;for (int i = 0; i < printNum; i++) {if (tempArr[randIndex] >= (length - printNum)) {i = 0;} else {printf("%7d", tempArr[randIndex++]);}}printf("\n");for (int i = 0; i < length; i++) {tempArr[i] = arr[i];}printf("  归并排序\t\t%7.2lf ms", MergeSortTimes(tempArr, length));randIndex = rand() % length; // 0 - (length-1)printNum = 5;for (int i = 0; i < printNum; i++) {if (tempArr[randIndex] >= (length - printNum)) {i = 0;} else {printf("%7d", tempArr[randIndex++]);}}printf("\n");
}void knuthShuffle(int arr[], int length) {for (int i = length - 1; i > 1; i--) {swapInt(&arr[i], &arr[rand() % (i + 1)]);}
}void swapInt(int *card_1, int *card_2) {int tCard;tCard = *card_1;*card_1 = *card_2;*card_2 = tCard;
}double BubbleSortTimes(int arr[], int length) {union _LARGE_INTEGER time_start; // 开始时间union _LARGE_INTEGER time_over; // 结束时间LARGE_INTEGER f; // 计时器频率QueryPerformanceFrequency(&f);double dqFreq = (double) f.QuadPart; // 计时器频率QueryPerformanceCounter(&time_start); // 计时开始int temp;for (int i = 0; i < length - 1; i++) { // 外层循环:轮次int index = -1;for (int j = 0; j < length - 1 - i; j++) { // 内层循环:比较并交换位置(找出每轮最大数)if (arr[j] > arr[j + 1]) {temp = arr[j + 1];arr[j + 1] = arr[j];arr[j] = temp;index++;}}if (index == -1) {break; // 为提高排序效率,如果在每轮排序中未发生一次位置交换则代表已经是需要的顺序(直接跳出排序)}}QueryPerformanceCounter(&time_over); // 计时结束// 乘以1000000把单位由秒化为微秒,精度为1000 000/(cpu主频)微秒double run_time = 1000000.0 * (time_over.QuadPart - time_start.QuadPart) / dqFreq;return run_time / 1000.0;
}double SelectSortTimes(int arr[], int length) {struct timespec start;struct timespec end;// 开始时间clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &start);for (int i = 0; i < length - 1; i++) {int minIndex = i; // 最小数的下标int min = arr[i]; // 最小数的值for (int j = i + 1; j < length; j++) { // 选出本轮最小值,放到当前位置if (min > arr[j]) { // 升序排序min = arr[j];minIndex = j;}}// 将最小值,放在arr[i] (即交换)if (minIndex != i) { // 如果当前位置的数就是最小值,那么不需要进行交换arr[minIndex] = arr[i];arr[i] = min;}}// 结束时间clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &end);// 总耗时// 转化为 ms 为单位(但是精度可以直接到 ns 级别)double start_ms = start.tv_sec * 1000.0 + start.tv_nsec / 1000000.0;double end_ms = end.tv_sec * 1000.0 + end.tv_nsec / 1000000.0;return end_ms - start_ms;
}double HeapSortTimes(int arr[], int length) {union _LARGE_INTEGER time_start; // 开始时间union _LARGE_INTEGER time_over; // 结束时间LARGE_INTEGER f; // 计时器频率QueryPerformanceFrequency(&f);double dqFreq = (double) f.QuadPart; // 计时器频率QueryPerformanceCounter(&time_start); // 计时开始int temp;// 将无序序列构建成一个堆,根据升序降序需求选择大顶堆或小顶堆for (int i = length / 2 - 1; i >= 0; i--) {adjustHeap(arr, i, length);}for (int i = length - 1; i > 0; i--) {// 将堆顶元素与末尾元素交换,将最大元素"沉"到数组末端temp = arr[i];arr[i] = arr[0];arr[0] = temp;// 重新调整结构,使其满足堆定义,然后继续交换堆顶元素与当前末尾元素,反复执行调整+交换步骤,直到整个序列有序adjustHeap(arr, 0, i); // 从最顶端 下标0 开始重新调整为堆}QueryPerformanceCounter(&time_over); // 计时结束// 乘以1000000把单位由秒化为微秒,精度为1000 000/(cpu主频)微秒double run_time = 1000000.0 * (time_over.QuadPart - time_start.QuadPart) / dqFreq;return run_time / 1000.0;
}void adjustHeap(int arr[], int i, int length) {// 取出当前元素的值,保存为临时变量int temp = arr[i];// k=i*2+1:k是i结点的左子结点for (int k = i * 2 + 1; k < length; k = k * 2 + 1) {// 在保证有右子结点的前提下,比较左子结点和右子结点的值的大小if (k + 1 < length && arr[k] < arr[k + 1]) {k++; // 如果右子结点大于左子结点,则把 左子结点 赋值为 右子结点}// 如果子结点大于父结点if (arr[k] > temp) {arr[i] = arr[k]; // 把当前子结点的值赋值给父结点i = k; // 把当前子结点作为新的父结点,继续向下循环比较是否还有子结点} else {break; // 直到以 i 父结点的树无子结点未比较为止}}//当for 循环结束后,我们已经将以i 为父结点的树的最大值,放在了 最顶(局部)arr[i] = temp; // 将temp值放到调整后的被交换的位置(子结点)
}double MergeSortTimes(int arr[], int length) {union _LARGE_INTEGER time_start; // 开始时间union _LARGE_INTEGER time_over; // 结束时间LARGE_INTEGER f; // 计时器频率QueryPerformanceFrequency(&f);double dqFreq = (double) f.QuadPart; // 计时器频率QueryPerformanceCounter(&time_start); // 计时开始int tempArr[length];mergeSort(arr, 0, length - 1, tempArr);QueryPerformanceCounter(&time_over); // 计时结束// 乘以1000000把单位由秒化为微秒,精度为1000 000/(cpu主频)微秒double run_time = 1000000.0 * (time_over.QuadPart - time_start.QuadPart) / dqFreq;return run_time / 1000.0;
}void mergeSort(int arr[], int left, int right, int temp[]) {if (left < right) {int mid = (left + right) / 2;// 左边分 递归分法mergeSort(arr, left, mid, temp);// 右边分 递归分法mergeSort(arr, mid + 1, right, temp);// 合并法merge(arr, left, mid, right, temp);}
}void merge(int arr[], int left, int mid, int right, int temp[]) {int i = left; // 初始化 i, 左边有序序列的初始索引int j = mid + 1; // 初始化 j, 右边有序序列的初始索引int t = 0; // 指向 temp 数组的当前索引while (i <= mid && j <= right) { // 只要左边或者右边的索引超过if (arr[i] <= arr[j]) { // 左右索引元素开始比较,如果左边小于等// 于右边索引元素值,将小的元素赋值到temp数组中temp[t++] = arr[i++]; // 索引向后 ++ 移动} else {temp[t++] = arr[j++];}}// 如果左边有剩余while (i <= mid) {temp[t++] = arr[i++];}// 如果右边有剩余while (j <= right) {temp[t++] = arr[j++];}t = 0;int tempLeft = left;while (tempLeft <= right) {arr[tempLeft++] = temp[t++];}
}

实验结果

在这里插入图片描述

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

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

相关文章

springboot使用configtree读取树形文件目录中的配置

文章目录 一、介绍二、演示环境三、项目演示1. 配置文件2. 导入配置3. 检测配置属性 四、应用场景五、源码解析1. ConfigTreeConfigDataLocationResolver2. ConfigTreeConfigDataLoader 六、总结 一、介绍 相信绝大多数使用springboot开发项目的朋友们在添加配置时&#xff0c…

同步_异步请求和Ajax并利用axios框架简化

目录 同步和异步 原生的Ajax 创建XMLHttpRequest对象 常用方法 常用属性 axios框架 同步和异步 同步请求&#xff1a;发送请求后&#xff0c;会做出回应&#xff0c;回应的内容会覆盖浏览器中的内容&#xff0c;这样会打断其他正常的操作&#xff0c;显得不太友好&#…

汉诺塔:传说中的智慧游戏

文章目录 前言规则概述数学原理核心Java代码实现结语 前言 汉诺塔&#xff08;Hanoi Tower&#xff09;&#xff0c;又称汉诺塔游戏&#xff0c;是源自印度古老传说的经典智力游戏。这个谜题的起源被认为与印度的寺庙有关&#xff0c;是由僧侣们传承的智慧游戏。汉诺塔塔座包含…

点击base64编码过的图片在另一个页面显示

开始的代码是这样的&#xff0c;新开一个窗口显示经过base64编码后的图片&#xff0c;但是url太长了显示失败。 openImage(imgSrc) {window.open(imgSrc, _blank); }, 解决方法&#xff1a;这段代码接收一个Base64编码的图像数据&#xff0c;把它转换为一个Blob对象。 Blob&…

LabVIEW使用边缘检测技术实现彩色图像隐写术

LabVIEW使用边缘检测技术实现彩色图像隐写术 隐写术是隐藏信息的做法&#xff0c;以隐瞒通信的存在而闻名。该技术涉及在适当的载体&#xff08;如图像&#xff0c;音频或视频&#xff09;中插入秘密消息。在这些载体中&#xff0c;数字图像因其在互联网上的广泛使用而受到青睐…

1+X Web前端开发职业技能等级证书建设方案

一 、系统概述 1X Web前端开发技术是计算机类专业重要的核心课程&#xff0c;课程所包含的教学内容多&#xff0c;实践性强&#xff0c;并且相关技术更新快。传统的课堂讲授模式以教师为中心&#xff0c;学生被动式接收&#xff0c;难以调动学生学习的积极性和主动性。混合式教…

5.0 Spring Boot核心

1. Spring Boot注解 注解名称 注解说明 SpringBootApplication 用于标注Spring Boot应用为启动类&#xff0c;是一个组合注解&#xff0c;主要组合了SpringBootConfiguration、EnableAutoConfiguration和ComponentScan注解 SpringBootConfiguration 继承自Configuration&a…

【apifox】如何写一份合格的 API 文档?

要想弄清楚如何开始写出一份合格的 API 文档&#xff0c;我们需要首先了解什么是 API&#xff0c;它的使用场景有哪些&#xff0c;应该具备什么样的能力。 什么是 API&#xff1f; 想象一下&#xff0c;当小 A 购入了一台新的电脑后&#xff0c;希望将显示画面投射至一块色准…

【Quarkus技术系列】「云原生架构体系」在云原生时代下的Java“拯救者”是Quarkus,那云原生是什么呢?

云原生时代下的Java"拯救者" 在云原生时代&#xff0c;其实Java程序是有很大的劣势的&#xff0c;以最流行的spring boot/spring cloud微服务框架为例&#xff0c;启动一个已经优化好&#xff0c;很多bean需要lazy load的application至少需要3-4秒时间&#xff0c;内…

构建之法 - 软件工程实践教学:每天都向前推进一点点

作者&#xff1a;福州⼤学 汪璟玢⽼师 汪老师&#xff1a;每次都向前推进一点点&#xff0c;哪怕只有一点点&#xff0c;也好过什么都不做。 ​邹老师&#xff1a;对&#xff0c;几个学期下来&#xff0c;就已经超过那些“空想”的团队很远了。坚持下去&#xff01; 汪老师&…

vue或uniapp使用pdf.js预览

一、先下载稳定版的pdf.js&#xff0c;可以去官网下载 官网下载地址 或 pdf.js包下载(已配置好&#xff0c;无需修改) 二、下载好的pdf.js文件放在public下静态文件里&#xff0c; uniapp是放在 static下静态文件里 三、使用方式 1. vue项目 注意路径 :src"static/pd…

数据结构——时间复杂度和空间复杂度

1.算法效率 2.时间复杂度 3.空间复杂度 4. 常见时间复杂度以及复杂度oj练习 1.算法效率 1.1 如何衡量一个算法的好坏 如何衡量一个算法的好坏呢&#xff1f;比如对于以下斐波那契数的计算 long long Fib(int N) { if(N < 3) return 1; return Fib(N-1) Fib(N-2); }我们看到…

母婴即时零售行业数据可视化分析

对新晋父母来说&#xff0c;很多母婴用品如同一位贴心的助手&#xff0c;为他们的宝宝提供温暖和呵护。从婴儿床垫到可爱的拼图玩具&#xff0c;每一件用品都是为宝宝的成长和发展量身定制。对于繁忙的父母们而言&#xff0c;这些用品不仅帮助照顾孩子&#xff0c;更是为他们减…

【MySQL】数据库基础

文章目录 1. 数据库基础1.1 什么是数据库1.2 在Linux上见见数据库 2. 主流数据库3. 服务器、数据库、表三者之间的关系4. MySQL结构5. SQL语句分类6. 存储引擎 1. 数据库基础 1.1 什么是数据库 数据库是按照数据结构来组织、存储和管理数据的仓库&#xff0c;是一个长期存储在…

旧版本docker未及时更新,导致更新/etc/docker/daemon.json配置文件出现docker重启失败

一、背景 安装完docker和containerd之后&#xff0c;尝试重启docker的时候&#xff0c;报错如下&#xff1a; systemctl restart dockerJob for docker.service failed because the control process exited with error code. See “systemctl status docker.service” and “…

Django-配置邮箱功能(一):使用django自带的发送邮件功能

一、获取邮箱授权码 以QQ邮箱为例子&#xff1a; 1、进入到设置&#xff0c;找到账户 2、开启POP3等服务&#xff0c;点击管理服务 3、进入管理服务&#xff0c;生成授权码 4、按照要求发送短信就可以了 5、将授权码复制保存&#xff0c;离开界面就看不到了 二、django项目中…

【CTF-MISC】这是一张单纯的图片

题目链接&#xff1a;https://ctf.bugku.com/challenges/detail/id/2.html 下载图片&#xff0c;使用010 Editor打开&#xff1a; 在文件末尾可以看到疑似HTML实体的内容&#xff0c;将其解码即可得到答案。

day3 TCP/UDP基础模型、多点通信、TCP开发服务器模型

1.多线程中的newfd&#xff0c;能否修改成全局&#xff0c;不行&#xff0c;为什么&#xff1f; 不能。线程之间共享附属进程的所有资源&#xff0c;newfd是全局变量&#xff0c;作用域是全局&#xff0c;一经更改所有线程中的newfd都会变化。 2.多线程中分支线程的newfd能否…

Spring Boot+Redis 实现一个简单的限流器示例

Spring BootRedis 实现一个简单的限流器&#xff0c;限制 文章目录 Spring BootRedis 实现一个简单的限流器&#xff0c;限制0.前言1.基础介绍2.步骤2.1. 引入依赖2.2. 配置文件2.3. 核心源码优化后再优化一下加入布隆过滤器 4.总结5.参考文档6. Redis从入门到精通系列文章 0.前…

每天一道leetcode:1129. 颜色交替的最短路径(图论中等广度优先遍历)

今日份题目&#xff1a; 给定一个整数 n&#xff0c;即有向图中的节点数&#xff0c;其中节点标记为 0 到 n - 1。图中的每条边为红色或者蓝色&#xff0c;并且可能存在自环或平行边。 给定两个数组 redEdges 和 blueEdges&#xff0c;其中&#xff1a; redEdges[i] [ai, bi…