C++-----算法分析

devtools/2024/12/26 1:51:21/

C++算法分析基础

算法分析主要评估算法的性能,这在优化程序效率时至关重要。关键指标之一是时间复杂度,它衡量随着输入规模增长,算法执行时间的变化趋势。

排序算法分析与时间复杂度

排序算法用于将一组无序的数据元素按特定顺序排列。常见的排序算法有冒泡排序、插入排序、选择排序、归并排序和快速排序等,它们各有不同的时间复杂度:

  • 冒泡排序:通过多次比较相邻元素并交换,把最大(或最小)的元素逐步“冒泡”到数组末尾。它的时间复杂度是 O ( n 2 ) O(n^2) O(n2),因为对于有 n n n 个元素的数组,需要进行大约 n 2 n^2 n2 次比较操作。
  • 插入排序:将一个数据插入到已经排好序的数组中的适当位置。在最坏情况下,每次插入都要移动数组中的大部分元素,时间复杂度同样是 O ( n 2 ) O(n^2) O(n2);但在最好情况下(数组已经有序),时间复杂度为 O ( n ) O(n) O(n)
    在这里插入图片描述

递归的终止

递归函数在自身内部调用自身,但必须有终止条件,否则会陷入无限递归。例如,计算阶乘的递归函数:

int factorial(int n) {if (n == 0 || n == 1) {  // 终止条件return 1;}return n * factorial(n - 1);
}

n 为 0 或 1 时,函数直接返回 1,不再进行递归调用,从而防止程序栈溢出。

标准的算法复杂度类别

常见的算法复杂度类别有:

  • 常数时间复杂度 O ( 1 ) O(1) O(1)算法执行时间不随输入规模增长而变化,例如访问数组中的单个元素:int num = arr[0];
  • 对数时间复杂度 O ( log ⁡ n ) O(\log n) O(logn):典型的如二分查找,每次将搜索区间减半,随着输入规模 n n n 增大,执行时间增长缓慢。
  • 线性时间复杂度 O ( n ) O(n) O(n):遍历一次数组的操作,如计算数组元素之和:int sum = 0; for(int num : arr) sum += num;
  • 线性对数时间复杂度 O ( n log ⁡ n ) O(n\log n) O(nlogn):高效排序算法如归并排序、快速排序的平均时间复杂度为此类。
  • 平方时间复杂度 O ( n 2 ) O(n^2) O(n2):像冒泡排序、插入排序的最坏情况复杂度。
  • 指数时间复杂度 O ( 2 n ) O(2^n) O(2n):递归求解斐波那契数列的朴素算法就属于这类,效率极低。

快速排序算法

快速排序采用分治策略,是一种高效的排序算法,平均时间复杂度为 O ( n log ⁡ n ) O(n\log n) O(nlogn)

#include <iostream>
#include <vector>// 划分函数,选择一个基准元素,将数组分为两部分
int partition(std::vector<int>& arr, int low, int high) {int pivot = arr[high];int i = low - 1;for (int j = low; j < high; ++j) {if (arr[j] <= pivot) {++i;std::swap(arr[i], arr[j]);}}std::swap(arr[i + 1], arr[high]);return i + 1;
}// 快速排序主体函数
void quickSort(std::vector<int>& arr, int low, int high) {if (low < high) {int pi = partition(arr, low, high);quickSort(arr, low, pi - 1);quickSort(arr, pi + 1, high);}
}
int main() {std::vector<int> numbers = {10, 7, 8, 9, 1, 5};quickSort(numbers, 0, numbers.size() - 1);for (int num : numbers) {std::cout << num << " ";}return 0;
}
  • 原理partition 函数选定一个基准元素(这里选数组末尾元素),把数组分成两部分,左边部分元素小于等于基准,右边部分大于基准。然后递归地对左右两部分进行排序。
  • 时间复杂度:在平均情况下,每次划分能把数组大致分成两半,递归深度为 O ( log ⁡ n ) O(\log n) O(logn),每层划分操作需要 O ( n ) O(n) O(n) 时间,所以平均时间复杂度是 O ( n log ⁡ n ) O(n\log n) O(nlogn);但在最坏情况下(例如数组已经有序,每次选的基准都是最值),时间复杂度会退化到 O ( n 2 ) O(n^2) O(n2)

数学归纳法

数学归纳法用于证明与自然数有关的命题。步骤一般分为两步:

  1. 基础步骤:证明当 n = n 0 n = n_0 n=n0(通常 n 0 = 0 n_0 = 0 n0=0 n 0 = 1 n_0 = 1 n0=1) 时命题成立。
  2. 归纳步骤:假设当 n = k n = k n=k 时命题成立,证明当 n = k + 1 n=k + 1 n=k+1 时命题也成立。

以证明等差数列求和公式 S n = n ( a 1 + a n ) 2 S_n=\frac{n(a_1 + a_n)}{2} Sn=2n(a1+an) 为例:

  • 基础步骤:当 n = 1 n = 1 n=1 时, S 1 = a 1 = 1 × ( a 1 + a 1 ) 2 S_1=a_1=\frac{1\times(a_1 + a_1)}{2} S1=a1=21×(a1+a1),公式成立。
  • 归纳步骤:假设 S k = k ( a 1 + a k ) 2 S_k=\frac{k(a_1 + a_k)}{2} Sk=2k(a1+ak) 成立,那么 S k + 1 = S k + a k + 1 = k ( a 1 + a k ) 2 + a k + 1 = ( k + 1 ) ( a 1 + a k + 1 ) 2 S_{k+1}=S_k + a_{k + 1}=\frac{k(a_1 + a_k)}{2}+a_{k + 1}=\frac{(k + 1)(a_1 + a_{k+1})}{2} Sk+1=Sk+ak+1=2k(a1+ak)+ak+1=2(k+1)(a1+ak+1),证毕。数学归纳法常用来证明算法的正确性,例如递归算法在不同输入规模下的有效性。
  • 下面以证明等差数列求和公式 S n = n ( a 1 + a n ) 2 S_n=\frac{n(a_1 + a_n)}{2} Sn=2n(a1+an) 为例,展示一个用 C++ 编写的体现数学归纳法思路的代码实例:
#include <iostream>// 计算等差数列的和
int arithmeticSeriesSum(int n, int a1, int an) {return (n * (a1 + an)) / 2;
}int main() {// 基础情况验证int n1 = 1;int a1 = 1;int an1 = 1;int sum1 = arithmeticSeriesSum(n1, a1, an1);if (sum1 == (n1 * (a1 + an1)) / 2) {std::cout << "基础情况(n = 1)成立" << std::endl;} else {std::cout << "基础情况(n = 1)不成立" << std::endl;}// 归纳步骤验证int k = 5;int a1_k = 1;int an_k = k;int sum_k = arithmeticSeriesSum(k, a1_k, an_k);int k_plus_1 = k + 1;int a1_k_plus_1 = 1;int an_k_plus_1 = k + 1;int sum_k_plus_1 = arithmeticSeriesSum(k_plus_1, a1_k_plus_1, an_k_plus_1);if (sum_k + (a1_k_plus_1 + an_k_plus_1) == sum_k_plus_1) {std::cout << "归纳步骤成立" << std::endl;} else {std::cout << "归纳步骤不成立" << std::endl;}return 0;
}

在这段代码中:

  • arithmeticSeriesSum 函数用于根据公式计算等差数列的和。
  • main 函数里,先验证基础情况,也就是当 n = 1 时,公式是否成立。随后,通过手动设定一个值 k 来模拟归纳步骤,假设 n = k 时公式成立,检验当 n = k + 1 时公式是否依然成立。实际应用中,数学归纳法常用于证明算法正确性,像递归算法的正确性证明,往往也遵循先证基础情况,再证归纳步骤的流程。
  • 在这里插入图片描述

http://www.ppmy.cn/devtools/145411.html

相关文章

系统压力测试助手——stress-ng

1、背景 在系统性能测试和压力测试中&#xff0c;stress-ng 是一个非常强大的工具&#xff0c;广泛应用于对 Linux 系统进行各种硬件和软件方面的负载测试。它能够模拟多种极端负载情况&#xff0c;帮助开发人员和运维人员检查系统在高负载下的表现&#xff0c;以便发现潜在的…

vue前端编译报错解决方法

如果控制台报错&#xff1a;&#xff08;其他报错信息往下滑&#xff0c;下面的解决方法可以解决大部分的报错&#xff0c;不只是这一种&#xff09; ERROR Error loading vue.config.js: ERROR TypeError: defineConfig is not a function TypeError: defineConfig is not a f…

HDLBits训练5

时间&#xff1a;2024.12.24 Count15 代码 module top_module (input clk,input reset, // Synchronous active-high resetoutput [3:0] q);always(posedge clk)beginif(reset) q<4b0;else if(q4b1111)q<4b0000;else q<q4b0001;end endmodulemodule top_module…

重温设计模式--单例模式

文章目录 单例模式&#xff08;Singleton Pattern&#xff09;概述单例模式的实现方式及代码示例1. 饿汉式单例&#xff08;在程序启动时就创建实例&#xff09;2. 懒汉式单例&#xff08;在第一次使用时才创建实例&#xff09; 单例模式的注意事项应用场景 C代码懒汉模式-经典…

Nginx整合Lua脚本

Nginx-Lua Nginx整合Lua脚本 Lua环境搭建 下载地址 linux环境下 yum install lua安装后验证 lua -vLua脚本执行 lua xxx.luaNginx整合Lua nginx需要添加lua模块 嵌入内容 示例如下 修改nginx.conf如下 location /lua {default_type text/plain;content_by_lua ngx.sa…

如何使用C/C++语言编写GPIB协议控制程序呢?

使用C/C语言编写GPIB&#xff08;General Purpose Interface Bus&#xff0c;通用接口总线&#xff09;协议控制程序通常涉及与GPIB硬件接口的交互。以下是一个使用C/C编写GPIB控制程序的基本步骤和示例代码&#xff0c;但请注意&#xff0c;具体的实现细节可能会因你使用的GPI…

java反射详讲

好的&#xff01;以下是关于 Java 反射的详细讲解&#xff08;约5000字左右&#xff09;。内容包括基础概念、反射的优缺点、基本用法&#xff0c;以及典型案例。 Java 反射详解 反射是 Java 中的一项强大机制&#xff0c;允许程序在运行时动态获取类的相关信息&#xff0c;并…

vue3入门教程:reactive函数

基本用法 引入 reactive 首先&#xff0c;你需要从 vue 包中引入 reactive 函数&#xff1a; import { reactive } from vue;创建一个响应式对象 使用 reactive 函数来创建一个响应式对象&#xff1a; const state reactive({count: 0,name: Vue 3 });在这个例子中&#xff0c…