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

数据结构实验1

实验题1:求1到n的连续整数和

题目描述

编写一个程序,对于给定的正整数n,求1+2+…十n,采用逐个累加与(n+1)/2(高斯法)两种解法。对于相同的n,给出这两种解法的求和结果和求解时间,并用相关数据进行测试。

运行代码

//实验题1:求1到n的连续整数和
#include<iostream>
#include<time.h>
#include<stdio.h>
#include<math.h>
using namespace std;
#define ll long long 
ll add1(ll n) {ll sum = 0;for (ll i = 1; i <= n; i++) {sum += i;}return sum;
}
void AddTime1(ll n) {clock_t t;ll sum;t = clock();sum = add1(n);t = clock() - t;cout << "方法一:" << endl;printf(" 结果:1 到 %lld 之和:%lld\n", n, sum);printf(" 用时:%lf 秒\n", ((double)t) / CLOCKS_PER_SEC);
}
ll add2(ll n) {return n * (n + 1) / 2;
}
void AddTime2(ll n) {clock_t t;ll sum;t = clock();sum = add2(n);t = clock() - t;cout << "方法二:" << endl;printf(" 结果:1 到 %lld 之和:%lld\n", n, sum);printf(" 用时:%lf 秒\n", ((double)t) / CLOCKS_PER_SEC);
}
int main() {ll n;printf("n(大于 1000000):");cin >> n;if (n < 1000000) return 0;AddTime1(n);AddTime2(n);return 0;
}

代码思路

  1. 头文件和命名空间
    • 包含了必要的输入输出流头文件 <iostream>、时间相关头文件 <time.h>、标准输入输出头文件 <stdio.h> 和数学库头文件 <math.h>
    • 使用 using namespace std 引入标准命名空间。
    • 定义宏 ll 为 long long,方便后续使用长整型数据类型。
  2. 函数定义
    • add1 函数:使用循环遍历从 1 到 n 的整数,逐个累加求和。
    • AddTime1 函数:测量 add1 函数的执行时间,并输出结果和用时。
    • add2 函数:利用数学公式 n*(n+1)/2 直接计算从 1 到 n 的整数之和。
    • AddTime2 函数:测量 add2 函数的执行时间,并输出结果和用时。
  3. main 函数
    • 从用户输入获取整数 n,要求 n 大于 1000000,否则程序退出。
    • 分别调用 AddTime1 和 AddTime2 函数,对两种方法进行测试。
  4. 方法一的原理:循环遍历从 1 到 n 的每个整数,逐个累加到变量 sum中,最终得到从 1到 n 的整数之和。这种方法直观易懂,但当 n 较大时,循环执行次数较多,可能会比较耗时。

  5. 方法二的原理:利用数学公式 1 + 2 + 3 +... + n = n*(n+1)/2 直接计算从 1 到 n 的整数之和。这个公式可以通过数学归纳法证明。这种方法避免了循环遍历,计算效率更高,尤其是对于较大的 n。

通过测量两种方法的执行时间,可以看出当 n 较大时,方法二通常比方法一执行速度更快,因为方法二避免了大量的循环迭代操作,直接利用数学公式进行计算。

实验题2:常见算法时间函数的增长趋势分析

题目描述

运行代码

//实验题2:常见算法时间函数的增长趋势分析
#include <iostream>
#include <cmath>
using namespace std;
double log2(double n) {return log10(n) / log10(2);
}
int factorial(int n) {if (n == 0 || n == 1)return 1;elsereturn n * factorial(n - 1);
}
int main() {cout << "n\tlog2(n)\t√n\tn\tn^2\tn^3\t2^n\tn!" << endl;for (int n = 1; n <= 10; n++) {cout << n << "\t" << log2(n) << "\t" << sqrt(n) << "\t" << n << "\t" << n * n << "\t" << n * n * n << "\t" << pow(2, n) << "\t" << factorial(n) << endl;}return 0;
}

代码思路

一、代码思路

  1. 函数定义
    • log2函数:通过换底公式logₐb = logₑb / logₑa,这里使用以 10 为底的对数函数log10计算出以 2 为底的对数。
    • factorial函数:使用递归的方式计算给定整数n的阶乘。当n为 0 或 1 时,阶乘为 1;否则,n的阶乘等于n乘以n - 1的阶乘。
  2. main函数
    • 首先输出表头,展示不同算法时间函数的名称。
    • 使用循环从 1 到 10 遍历整数n
    • 在循环中,分别计算并输出n、以 2 为底n的对数、n的平方根、nn的平方、n的立方、2 的n次方、n的阶乘的值。

二、原理

  1. log2(n):对数函数的增长非常缓慢。随着n的增大,对数函数的值增长速度远远慢于线性增长。
  2. √n:平方根函数的增长速度比线性增长慢,但比对数函数快。
  3. n:代表线性增长,即随着n的增加,函数值以相同的比例增加。
  4. n^2:二次函数的增长速度比线性增长快得多。当n增大时,二次函数的值增长迅速。
  5. n^3:三次函数的增长速度比二次函数更快。
  6. 2^n:指数函数的增长速度非常快,远远超过其他函数。
  7. n!:阶乘函数的增长速度是所有这些函数中最快的。随着n的增大,阶乘函数的值呈爆炸式增长。

通过输出这些不同函数在不同n值下的结果,可以直观地观察到它们的增长趋势差异,对于分析算法的时间复杂度非常有帮助。例如,在选择算法时,如果一个算法的时间复杂度是指数级的(如2^nn!),那么对于较大的输入规模,该算法可能会非常耗时,而如果算法的时间复杂度是线性的(如n)或对数级的(如log2(n)),则通常会更加高效。

实验题3:求数的个数

题目描述

编写一个程序,求1~n的素数个数。给出两种解法,对于相同的n,给出这两种解法的结果和求解时间,并用相关数据进行测试。

运行代码

//实验题3:求素数的个数
#include <iostream>
#include <ctime>
using namespace std;
bool isPrime1(int n) {// 方法 1:传统方法判断素数,时间复杂度 O(n)if (n < 2) return false;for (int i = 2; i < n; i++) {if (n % i == 0) return false;}return true;
}
int prime1(int n) {int count = 0;for (int i = 2; i <= n; i++) {if (isPrime1(i)) count++;}return count;
}
bool isPrime2(int n) {// 方法 2:改进方法判断素数,时间复杂度 O(√n)if (n < 2) return false;if (n == 2 || n == 3) return true;if (n % 2 == 0 || n % 3 == 0) return false;for (int i = 5; i * i <= n; i += 6) {if (n % i == 0 || n % (i + 2) == 0) return false;}return true;
}
int prime2(int n) {int count = 0;for (int i = 2; i <= n; i++) {if (isPrime2(i)) count++;}return count;
}
void PrimeTime1(int n) {clock_t start = clock();int count = prime1(n);clock_t end = clock();double time_taken = double(end - start) / CLOCKS_PER_SEC;cout << "方法 1:1 到 " << n << " 的素数个数为 " << count << ",用时 " << time_taken << " 秒。" << endl;
}
void PrimeTime2(int n) {clock_t start = clock();int count = prime2(n);clock_t end = clock();double time_taken = double(end - start) / CLOCKS_PER_SEC;cout << "方法 2:1 到 " << n << " 的素数个数为 " << count << ",用时 " << time_taken << " 秒。" << endl;
}
int main() {int n;cout << "输入 n(n>100000):";cin >> n;PrimeTime1(n);PrimeTime2(n);return 0;
}

代码思路

一、代码思路

  1. 函数定义
    • isPrime1函数:采用传统方法判断一个整数是否为素数。从 2 开始到该数减 1 进行遍历,如果存在能整除该数的数,则不是素数,否则是素数。时间复杂度为。
    • prime1函数:利用isPrime1函数,遍历从 2 到n的所有整数,统计其中素数的个数。
    • isPrime2函数:改进的方法判断素数。先处理特殊情况小于 2 的数、2 和 3。然后根据素数的性质,只需要判断到该数的平方根即可,并且只需要考虑 6 的倍数两侧的数(即ii + 2),因为所有大于等于 5 的素数一定可以表示为 6k ± 1 的形式。时间复杂度为。
    • prime2函数:与prime1类似,使用isPrime2函数遍历从 2 到n的整数,统计素数个数。
    • PrimeTime1函数:测量prime1函数的执行时间,并输出素数个数和用时。
    • PrimeTime2函数:测量prime2函数的执行时间,并输出素数个数和用时。
  2. main函数
    • 提示用户输入一个大于 100000 的整数n
    • 分别调用PrimeTime1PrimeTime2函数,对两种方法进行测试并输出结果。

二、原理

  1. 素数的定义:素数是指一个大于 1 的自然数,除了 1 和它自身外,不能被其他自然数整除。

  2. 两种判断素数方法的原理:

    • 方法 1:传统方法通过遍历所有小于该数的整数来判断是否有能整除它的数。这种方法虽然直观,但效率较低,因为需要进行大量的除法运算。
    • 方法 2:改进的方法利用了素数的分布规律。首先处理特殊情况,然后只需要判断到该数的平方根,并且只考虑特定形式的数,减少了不必要的判断,提高了效率。
  3. 统计素数个数的原理:通过遍历一定范围内的整数,对每个整数使用判断素数的函数进行判断,如果是素数则计数器加一。

  4. 测量执行时间的原理:使用clock_t类型记录程序开始和结束的时间,通过计算时间差并除以CLOCKS_PER_SEC得到程序的执行时间,以秒为单位。

通过比较两种方法,可以看出在处理较大范围的素数个数计算时,改进后的方法(方法 2)具有更高的效率,因为其时间复杂度更低。

实验题4:求连续整数阶乘的和

题目描述

编写一个程序,对于给定的正整数n,求1!+2!+3!+…+n!。给出一种时间复杂度为O(n)的解法。

运行代码

//实验题4:求连续整数阶乘的和
#include <iostream>
using namespace std;
long long Sum(int n) {long long sum = 0;long long fact = 1;for (int i = 1; i <= n; i++) {fact *= i;sum += fact;}return sum;
}
int main() {int n;cout << "输入正整数 n(3-20):";cin >> n;if (n < 3 || n>20)return 0;long long result = Sum(n);cout << "1! + 2! + 3! +... + " << n << "! 的结果为:" << result << endl;return 0;
}                

代码思路

一、代码思路

  1. Sum函数:
    • 循环结束后,返回sum,即从 1 到n的连续整数阶乘之和。
    • 通过循环从 1 到n遍历整数。在每次循环中,先将fact乘以当前的整数i,得到当前整数的阶乘,然后将这个阶乘累加到sum中。
    • 初始化变量fact为 1,用于存储当前整数的阶乘。
    • 初始化变量sum为 0,用于存储连续整数阶乘的和。
  2. main函数:
    • 提示用户输入一个正整数n,要求在 3 到 20 之间。
    • 如果输入的n不在这个范围内,程序直接返回 0 退出。
    • 调用Sum函数计算从 1 到n的连续整数阶乘之和,并将结果存储在result中。
    • 输出结果,显示从 1 到n的连续整数阶乘之和的具体值。

二、原理

  1. 阶乘的定义:一个正整数的阶乘是所有小于及等于该数的正整数的乘积。例如,5 的阶乘是 5! = 5×4×3×2×1 = 120。

  2. 计算连续整数阶乘之和的原理:

    • 通过循环依次计算每个整数的阶乘,并将其累加到总和中。
    • 首先,初始化阶乘为 1,因为 1 的阶乘是 1。然后,从 2 开始,每次将当前整数乘以当前的阶乘得到新的阶乘,并将新的阶乘累加到总和中。
    • 这样,通过循环可以依次得到 2!、3!、4!…… 直到n!,并将它们累加到总和中,最终得到从 1! 到n!的连续整数阶乘之和。

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • [创业之路-146] :如何理解:复杂的事情简单化,简单的事情标准化,标准的事情流程化,流程的事情数字化,数字化的事情自动化,自动化的事情智能化
  • CentOS 8FTP服务器
  • 第T11周:优化器对比实验
  • 架构设计:负责网络、定时、坐下、站起、重连等,支持多类游戏的无锁房间
  • 通过python提取PDF文件指定页的图片
  • k8s笔记——kubebuilder实战
  • wifiip地址可以随便改吗?wifi的ip地址怎么改变
  • 【计算机网络 - 基础问题】每日 3 题(二)
  • linux: nvidia-smi用法详解
  • 二.Unity中使用虚拟摇杆来控制角色移动
  • Unity 第一人称游戏的武器被其他物体覆盖解决方案
  • 供应RM500UCNAB-D10-SNADA模块
  • leetcode 108.将有序数组转换为二叉搜索树
  • word文档无损原样转pdf在windows平台使用python调用win32com使用pip安装pywin32
  • 嵌入式epoll面试题面试题及参考答案
  • centos安装java运行环境jdk+tomcat
  • conda常用的命令
  • create-react-app做的留言板
  • ES学习笔记(10)--ES6中的函数和数组补漏
  • JAVA多线程机制解析-volatilesynchronized
  • JS变量作用域
  • Shell编程
  • springboot_database项目介绍
  • 更好理解的面向对象的Javascript 1 —— 动态类型和多态
  • 目录与文件属性:编写ls
  • 详解移动APP与web APP的区别
  • 学习ES6 变量的解构赋值
  • 要让cordova项目适配iphoneX + ios11.4,总共要几步?三步
  • ​探讨元宇宙和VR虚拟现实之间的区别​
  • ‌U盘闪一下就没了?‌如何有效恢复数据
  • #{}和${}的区别是什么 -- java面试
  • (1)常见O(n^2)排序算法解析
  • (55)MOS管专题--->(10)MOS管的封装
  • (C11) 泛型表达式
  • (动手学习深度学习)第13章 计算机视觉---图像增广与微调
  • (机器学习-深度学习快速入门)第一章第一节:Python环境和数据分析
  • (每日一问)计算机网络:浏览器输入一个地址到跳出网页这个过程中发生了哪些事情?(废话少说版)
  • (南京观海微电子)——COF介绍
  • (欧拉)openEuler系统添加网卡文件配置流程、(欧拉)openEuler系统手动配置ipv6地址流程、(欧拉)openEuler系统网络管理说明
  • (五)Python 垃圾回收机制
  • (转载)Linux网络编程入门
  • .Mobi域名介绍
  • .net core webapi 部署iis_一键部署VS插件:让.NET开发者更幸福
  • .NET Framework .NET Core与 .NET 的区别
  • .NET Framework杂记
  • .NET 中的轻量级线程安全
  • .NET国产化改造探索(三)、银河麒麟安装.NET 8环境
  • .NET学习全景图
  • ??myeclipse+tomcat
  • @31省区市高考时间表来了,祝考试成功
  • [28期] lamp兄弟连28期学员手册,请大家务必看一下
  • [ACM] hdu 1201 18岁生日
  • [BJDCTF2020]EzPHP1
  • [C/C++入门][ifelse]20、闰年判断
  • [CISCN 2023 初赛]go_session