分析和设计算法

目录

前言 

循环不变式

n位二进制整数相加问题

RAM模型

使用RAM模型分析

代码的最坏情况和平均情况分析

插入排序最坏情况分析

插入排序平均情况分析

设计算法

分治法

总结


前言 

        循环迭代,分析算法和设计算法作为算法中的三个重要的角色,下面从一些程序示例入手,介绍如何使用有效的方法来设计和分析算法。

循环不变式

代码:

int f(int n) {
    int res = 1;
    for(int i = 1; i <= n; i++) {
        res = res * i;
    }
    return res;
}

这是求n!的函数, res是每次迭代的(i-1)!的结果,可以看到每趟迭代下来,它的形式都是res,没有变更过,我们称之为循环不变式

循环不变式有初始化,保持和终止三要素。

初始化:循环的第一次迭代,它为真。代码中如果res = 0; 则第一次迭代的结果res = 0;

结果为假,初始化错误。

保持:如果本次迭代结果为真,则下一次的结果也为真。本次res = i!, 下一次res = res * (i+1) = i! * (i + 1) = (i+1)!. 可以理解为迭代保持了。

终止:迭代终止的条件, i > n时,迭代终止。数学归纳法中只有初始化和保持的证明,但是没有终止这一步。当i叠加到n+1时,上一次迭代结果时res = res*i = i! = n!已经是正确结果了,所以迭代条件终止时,结果正确。

n位二进制整数相加问题

初始化:A[MAXSIZE] = {0}, B[MAXSIZE] = {0}, C[MAXSIZE] = {0}.

保持:C[i+1] = (A[i] + B[i] + C[i])/2; C[i] = (A[i] + B[i] + C[i])%2.

终止条件:A[i]和B[i]中全部为零,迭代终止.

代码:

void num_to_binary(int num, int B[MAXSIZE]) {
    for (int i = 0; num > 0; i++)
    {
        B[i] = num % 2;
        num = num / 2;
        printf("%d", B[i]);
    }
    printf("\n");
    
}

void binary_add(int A[MAXSIZE], int B[MAXSIZE], int C[MAXSIZE + 1]) {
    int i;
    for (i = 0; B[i] || A[i] ; i++)
    {
        C[i+1] = (A[i] + B[i] + C[i]) / 2;
        C[i] = (A[i] + B[i] + C[i]) % 2;
        printf("%d", C[i]);
    }
    printf("%d\n", C[i]);
}

输出结果:

RAM模型

在分析算法时,我们经常提到时间复杂度和空间复杂度。这些都是基于代码中的指令是一条一条地在CPU中执行的,不存在并行操作。这种前提可以理解位RAM模型。

使用RAM模型分析

代码

代价

次数

int res = 1;

C1

1

for(int i = 1; i <= n; i++)

C2

n

res = res * i;

C3

n

return res;

C4

1

上述代码的运行时间位Tn=c1+c2*n+c3*n+c4.

T(n)为n的线性函数,所以可以说改代码的时间复杂度为O(n).

代码的最坏情况和平均情况分析

  for(int i = 0; i < 10; i++) {
        while (p->next)
        {
            lnode *q = p->next;
            if(q->data > data[i]) {
                lnode *node = (lnode *) malloc(sizeof(lnode));
                node->data = data[i];
                node->next = q;
                p->next = node;
                break;
            }
            p = p->next;
        }
        p = list;
}
}
插入排序最坏情况分析

10个元素参与插入排序,最坏情况下,每趟插入的位置都是表尾:

第一趟  比较1次

第二趟  比较2次

。。。

第n趟  比较n次

T(n) = (1+2+3+…+n) + c = (n+1)*n/2 + cn.(c为插入一个结点的时间复杂度)。

插入排序平均情况分析

平均比较次数:

第一趟 比较(1+1)/2

第二趟 比较(1+2)/2

。。。

第n趟 比较(1+n)/2

T(n) = n*n/4 + cn.

在n足够大的时候,可以认为插入排序的最坏情况和平均情况的时间复杂度均为O(n*n).

设计算法

分治法

分治三个步骤:

分解:分解原问题为子问题,这些子问题为原问题的较小规模的问题。

解决:递归地解决这些子问题,如果规模小到一定程度,则直接得出答案。

合并:合并上述解决地子问题地解,得出最终解。

前提:该集合S经过归并排序之后的序列再进行如下算法运算。

分解:集合S的n个问题分解成两个规模n/2的问题。

解决:递归的解决和分解这些子问题,直到规模为2时,两个数相加与x比较,如果相等则存在,否则返回不存在。

合并:合并两个子问题,两个子问题中不存在和等于x的情况,所以需要判断是否存在跨集合相加和等于x的情况。

代码:

#include "stdio.h"
#define OK 1
#define ERROR 0
#define MAXSIZE 10
int FLAG = 0;
int is_x(int a1[MAXSIZE], int x, int low, int mid, int high);
void jude_add_x(int a[MAXSIZE], int x, int low, int high);

void main() {
    int b[10] = {-1,2,3,5,9,27,29,38,49,74};
    int x = 8;
    jude_add_x(b, x, 0, 9);
    printf("The result is %d", FLAG);
}

int is_x(int a1[MAXSIZE], int x, int low, int mid, int high) {
    
    int i = low, j = mid+1, k = low;
    while (i <= mid || j <= high)
    {
        if(a1[i] + a1[j] == x) 
        {
            return OK;
        }else if(a1[i] + a1[j] < x) {
            if(i < mid) i++;
            else if( j <= high) j++;
            else return ERROR;
        }else {
            return ERROR;
        }
    } 
    return ERROR;
}

void jude_add_x(int a[MAXSIZE], int x, int low, int high) {

    if(low == high) {
        return;
    }
    int mid = (low + high) / 2;
    jude_add_x(a, x, low, mid);
    jude_add_x(a, x, mid + 1, high);
    if(low != high && is_x(a, x, low, mid, high)) FLAG = 1;
}

 输出结果:

时间复杂度:O(lgn*n) 

空间复杂度:   O(1)

总结

本文主要讲解如何分析和设计算法。分析算法从分析时间复杂度入手,讲述了最坏情况和平均情况下的分析。设计算法以一个程序入手,讲述了分治法的三个步骤怎么分析。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【深度 Q 学习-01】 Q学习概念和python实现

文章目录 一、说明二、深度 Q 学习概念三、python实现四、结论 关键词&#xff1a;Deep Q-Networks 一、说明 在强化学习 &#xff08;RL&#xff09; 中&#xff0c;Q 学习是一种基础算法&#xff0c;它通过学习策略来最大化累积奖励&#xff0c;从而帮助智能体导航其环境。它…

2024年618网购节各大电商超级红包二维码集合

一年一度的电商618网购节又要来了&#xff0c;下面收集了淘宝/京东/拼多多的618红包二维码&#xff0c;手机扫描或识别即可每天领红包&#xff0c;可参考好物分享中的商品下单&#xff1a; 淘宝618超级红包&#xff1a;即日起至2024.6.10&#xff0c;每天可领一次 京东618无门…

P9 【力扣+知识点】【算法】【二分查找】C++版

【704】二分查找&#xff08;模板题&#xff09;看到复杂度logN&#xff0c;得想到二分 给定一个 n 个元素有序的&#xff08;升序&#xff09;整型数组 nums 和一个目标值 target &#xff0c;写一个函数搜索 nums 中的 target&#xff0c;如果目标值存在返回下标&#xff0…

RUST 和 GO 如何管理它们的内存

100编程书屋_孔夫子旧书网 Go 中的内存管理 Go 中的内存不会在缓存键被驱逐时立即释放。 相反&#xff0c;垃圾收集器会经常运行以发现任何没有引用的内存并释放它。 换句话说&#xff0c;内存会一直挂起&#xff0c;直到垃圾收集器可以评估它是否真正不再使用&#xff0c;而…

SpringCloud:Nacos配置管理

程序员老茶 &#x1f648;作者简介&#xff1a;练习时长两年半的Java up主 &#x1f649;个人主页&#xff1a;程序员老茶 &#x1f64a; P   S : 点赞是免费的&#xff0c;却可以让写博客的作者开心好久好久&#x1f60e; &#x1f4da;系列专栏&#xff1a;Java全栈&#…

01--nginx基础

前言&#xff1a; 本文用来整理一下nginx的用法&#xff0c;应该是本人中间件专栏的第一篇文章&#xff0c;这里开始概念和实操将会同样重要&#xff0c;面试时基本概念的理解非常重要&#xff0c;深有体会&#xff0c;不会再让概念成为压死骆驼的稻草。 1、nginx简介 Nginx…

vue连接mqtt实现收发消息组件超级详细

基本概念&#xff1a; MQTT&#xff08;Message Queuing Telemetry Transport&#xff09;是一种基于发布/订阅模式的轻量级消息传输协议&#xff0c;专为低带宽、高延迟或不稳定的网络环境设计。以下是MQTT实现收发消息的基本原理&#xff1a; 客户端-服务器模型&#xff1a…

【数据结构】-- 栈

栈 引入&#xff1a; 一种特殊的线性表&#xff0c;其只允许在固定的一端进行插入和删除元素操作。 进行数据插入和删除操作的一端 称为栈顶&#xff0c;另一端称为栈底。栈中的元素遵循先进后出的原则&#xff0c;先入栈的元素总是先后出栈。 压栈&#xff1a;栈的插入操作叫…

HCIP-Datacom-ARST自选题库__OSPF多选【62道题】

1.如图所示&#xff0c;路由器所有的接口开启OSPF&#xff0c;图中标识的IP地址为设备的LoopbackO接口的IP地址&#xff0c;R1、R2、R3的LoopbackO通告在区域1&#xff0c;R4的Loopback0通告在区域0&#xff0c;R5的LoopbackO通告在区域2&#xff0c;下列哪些IP地址之间可以相互…

Docker CIG使用

Docker CIG是什么 CIG为&#xff1a;CAdvisor监控收集、InfluxDB存储数据、Granfana图表展示 这个组合是一个常见的监控 Docker 容器的解决方案,它包括以下三个组件: cAdvisor (Container Advisor): cAdvisor 是一个开源的容器资源监控和性能分析工具。它能够收集有关正在运行的…

【Linux系统】进程间通信

本篇博客整理了进程间通信的方式管道、 system V IPC的原理&#xff0c;结合大量的系统调用接口&#xff0c;和代码示例&#xff0c;旨在让读者透过进程间通信去体会操作系统的设计思想和管理手段。 目录 一、进程间通信 二、管道 1.匿名管道 1.1-通信原理 1.2-系统调用 …

【VTKExamples::Utilities】第十五期 ShepardMethod

很高兴在雪易的CSDN遇见你 VTK技术爱好者 QQ:870202403 公众号:VTK忠粉 前言 本文分享VTK样例ShepardMethod,并解析接口vtkShepardMethod,希望对各位小伙伴有所帮助! 感谢各位小伙伴的点赞+关注,小易会继续努力分享,一起进步! 你的点赞就是我的动力(^U^)ノ…

HTML+CSS 圆形菜单

效果演示 实现了一个圆形菜单的效果,点击菜单按钮后,菜单项会从菜单按钮中心点向外展开,并且菜单项上有文字链接。可以将这段代码的效果称为“圆形菜单展开效果”。 Code <!DOCTYPE html> <html lang="en"><head><meta charset="UTF-8…

实战15:bert 命名实体识别、地址解析、人名电话地址抽取系统-完整代码数据

直接看项目视频演示: bert 命名实体识别、关系抽取、人物抽取、地址解析、人名电话地址提取系统-完整代码数据_哔哩哔哩_bilibili 项目演示: 代码: import re from transformers import BertTokenizer, BertForTokenClassification, pipeline import os import torch im…

(IDEA修改Java版本)java: 警告: 源发行版 X 需要目标发行版 X

搜索关键词&#xff1a;一致、发行 错误信息 其他错误&#xff1a; java: 错误: 不支持发行版本 6 java: -source 1.5 中不支持 lambda 表达式 (请使用 -source 8 或更高版本以启用 lambda 表达式) 思路 有两个地方要检查&#xff0c;JDK版本保持一致即可。 比如统一用JDK8或…

[排序算法]4. 图解堆排序及其代码实现

先来看看什么是堆? 堆是一种图的树形结构&#xff0c;被用于实现“优先队列”&#xff08;priority queues&#xff09; 注:优先队列是一种数据结构&#xff0c;可以自由添加数据&#xff0c;但取出数据时要从最小值开始按顺序取出。 在堆的树形结构中&#xff0c…

linux安装mysql后,配置mysql,并连接navicat软件

Xshell连接登陆服务器 输入全局命令 mysql -u root -p 回车后&#xff0c;输入密码&#xff0c;不显示输入的密码 注意mysql服务状态&#xff0c;是否运行等 修改配置文件my.cnf&#xff0c;这里没找到就找my.ini&#xff0c;指定有一个是对的 find / -name my.cnf 接下…

书籍学习|基于SprinBoot+vue的书籍学习平台(源码+数据库+文档)

书籍学习平台 目录 基于SprinBootvue的书籍学习平台 一、前言 二、系统设计 三、系统功能设计 1平台功能模块 2后台功能模块 5.2.1管理员功能模块 5.2.2用户功能模块 5.2.3作者功能模块 四、数据库设计 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 …

mysql数据导入navicat中,报错提示1067

MySQL导入问题&#xff1a; 报错1067 - Invalid default value for 字段名 由于数据库版本升级&#xff0c;老数据库的数据文件导出以后&#xff0c;在新版本的数据库上执行会报错 这种问题多是由于默认值不兼容引起的&#xff0c;我们可以通过修改sql_mode来解决这个问题 由…

Steamdeck使用Windows系统游玩雪地奔驰时闪退问题解决方法

我非常喜欢雪地奔驰这款游戏&#xff0c;买sd的一部分也是为了它。可在我打开这个游戏时&#xff0c;游戏发生闪退问题。查阅了网络各个途径&#xff0c;基本没有解决方法。因此我自己分析终于解决该问题。以下是我解决问题的思路&#xff0c;仅供记录参考&#xff1a; 游戏在崩…