从零开始_学_数据结构(一)——算法的基本概念

简介:

从零开始__数据结构(——算法

 

算法的定义:

解决问题的方法。

对于同一个问题,一个好的算法比一个差的算法,效率更高,更节约资源。

 

For Computer:算法是解决特定问题的求解步骤的描述,在计算机中,表示指令的有限序列,每条指令表示一个或者多个操作。

简单来说,算法就是输入代码,告诉计算机,你应该怎么解决这个问题

 

 

算法的特性:

(1)输入和输出。

       光算出结果但不输出结果,跟没算没区别;要计算,总得有数据,不然没法计算。

(2)有穷性:

       能出结果,并且在接受时间之内出结果。如果时间太长,这个算法往往就没什么意义了。

(3)确定性:

       同样的数据,同一个算法,出同样的结果。

(4)可行性;

       如果一个算法太复杂,都没办法变成代码给计算机,那肯定不行。

 

 

一个好的算法的要求:

(1)正确。

对于计算的数据,能得到预期的结果。

①首先得做到程序没问题,能运行;

②其次得对于计算的数据,能得到符合要求的结果;

③更好的算法,对于非法数据,能得出满足要求的结果(比如说提示有问题);

④对于专门用于为难人的数据,也能有满足要求的输出结果;

至少要做到第②步

 

(2)可读性

代码和算法,起码让人能读懂,不然写代码的人都不明白自己写的代码,如果代码出问题,那么也没办法鉴别出来。

 

(3)健壮性

面对不符合要求(非法)的数据,能够适当的处理。

例如,我们正常处理的一组数据里,只有正数,比如说我们使用unsigned int类型。那么假如有负数输入,如果没有代码去鉴别这些,那么就容易出现出乎意料的结果。

 

(4)速度快,用内存小

假如计算一组1GB大小的数据,同样的处理器

①假如一个算法用1分钟,另一个算法用1小时,显然前者更好;

②假如一个算法用10MB内存,另一个算法用1GB内存,显然前者更好。

在实际中,有时候会出现对于较少的数据来说,某一种算法更好,对于较多的数据来说,另一种算法更好。因此,选择哪种算法,要根据实际情况而决定。

 

 

 

算法效率的度量方法:

(1)事后统计:

简单直接,运行一遍就知道。

他到底用1秒还是100秒,用10MB内存还是500MB内存,一目了然。

缺点:假如需要1天甚至10天难道也要这么做?肯定是不靠谱的。因此,一般是不会使用这种方法的。

 

(2)事前分析估算方法:

这个方法,简单来说,就是:

①预估数据量(比如100万个数据)

②根据算法计算其运行次数(比如说3行代码,一般是运算3次的。但若涉及到循环,那么就是循环代码的行数*循环次数)

③机器执行代码的速度(计算求和与在一串字符串中插入一个字符,其执行速度自然是有区别的。而且,机器配置不同,运行同样指令其时间也是有区别的)

 

由于③是不可控的,因此一般不考虑。

而①是我们要为之服务的对象,因此是需要考虑,但无法选择的;

只有②,是我们最需要关心的内容。

 

以循环为例:

int total;

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

{

       cin>>data[i];

       data[i]*=2;

       data[i]+=5;

       total += data[i];

}

       cout<< total;

//假如cin是读取某个文件的int类型的数据(实际上不能这么写)

首先,循环范围内有4条指令。因此,当data数组里有n个元素时,这个代码将执行4*n + 2,4*n是循环,1是int total,另一个1是cout<<total。

如果我们使用另外一个方法:

int total;

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

{

       cin>>data[i];

       total+=data[i];

}
total=total*2+5*n;

cout<<total;

//注意,这里的cin只是用来意会,实际应用ifstream类变量来读取文件

与上面相比,这个算法需要执行的次数是:2*n+3次。

 

假如n=100万时,第一个算法需要执行的次数是400万+2次,第二个算法执行的次数是200万+3次,节约了几乎50%的时间。

 

这样的话,哪个算法好,通过简单的预估执行代码的次数,一目了然。

 

当然了,实际中,会因为代码不同,不同的代码的效率略有差异,但是显然执行次数更少的代码,更剩时间,效率也更高。

 

除了以上两种以外,还有双重for循环(即外层是一个for循环,执行n次;然后在外层的for循环内部还有一个for循环,执行m次,如代码);

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

       for(int j=0; j<m; j++)

              total=total+m+n;

这样一段代码,其执行次数将为m*n次(假如m=n的话,可以认为其运行次数为n的乘方)。

 

总结一下:

不同的算法(假设代码行数为m),针对不同的数据量(n),将执行不同的次数:

有的次数为n,有的次数为m,有的为m*n,有的为n*n,也有其他的。

一般来说,需要特别设计算法的,数据量都比较大(比如说几万甚至更多),代码行数相对就偏少(也许只有几行或者几十行)。

因此,m次最好,n次其次,m*n次再次,n*n次最次。

四个字:避免乘方

 

如下表:

数据量n

算法A执行代码(n2)次

记作f(A)=

算法B执行代码(3n)次

f(B)=

1

1

3

2

4

6

3

9

9

10

100

30

100

一万

三百

10000

一亿

三万

 

假如需要特别的算法,一般来说,原因是数据量都很大(几百MB,几GB,几十几百GB,甚至TB级别),只有一个好的算法,才能做到高效率的完成任务。

因此,需要尽量避免那种执行的代码次数,为数据量的乘方甚至n次方这样的情况。

 

以下概念有印象就行,反正知道怎么用最重要,单纯背概念毫无意义。

概念:函数的渐进增长

如上表,当n<3时,f(A)>f(B);

当n=3时,f(A)=f(B);

当n>3时,f(A)>f(B);

假如对于给定的函数,存在一个整数N,使得对于所有n>N的情况,f(A)总是大于f(B),那么我们就说,f(a)的渐进增长快于f(B)

 

假如两个函数,都存在幂的情况(比如说n的2次方或者3次方)。

那么主要关心其最高阶的部分(因为假如n=10,其2次方的值,仅仅只有3次方的十分之一,n越大,差距越大。即使一个是n的平方+一万,另一个是n的3次方,只需要n=100时,前者的效率便能轻松高于后者)。

 

因此:避免使用需要执行nm次幂次代码的算法。

 

除此之外,一个算法的需要执行代码的次数还有对数的情况、或者是指数的情况。

个人意见是,这里有个概念就可以,暂时不需要深究,毕竟这里学的是数据结构。

 

 

 

算法需要考虑最坏的情况:

例如我们设计一个算法,然后通过这个算法去试图去寻找一个文件里的数据。

那么①这个数据可能存在于文件的开始,也可能存在于数据的结尾;

②如果这个算法是逐个字节寻找,那么假如在开始,就会立刻找到,但若假如在结尾,那么可能需要找很久很久。而这个 最坏的情况(需要很多时间),是需要我们考虑的。

③特别是当这个文件很大很大时(遍历整个文件需要很多时间),那么考虑如何解决这个问题,是很重要的(因此可能需要优化算法)。比如说,假如这个数据存在的开始地址,是0xXXXX0这样,我们就可以考虑一次读取十六个字节,然后先对比第一个,符合后在继续对比,这样的话,就相对节约了很多时间。

④除了优化算法外,我们还应该考虑平均时间。例如,当算法无法优化时,那么最好的情况下,这个算法需要多久,最差的情况下,这个算法需要多久,二者平均起来,往往就是普通的情况下,需要的时间。

 

而这个 平均时间,是这个算法的期望运行时间,是需要我们关注的。

 

 

 

算法的存储空间:

当使用算法时,除了需要花时间外,可能还需要使用一定的存储空间。

例如:

①使用一个10个元素的int数组来存储计算的内容,由于一个int是4字节,因此需要使用40字节来存储这些内容;

②可能还要创建一个临时的变量(堆或者栈)用于存储算法中创建的临时对象,而在提高效率方面,创建的临时对象是有一定意义的;

③有时候,对于算法,要求其最多只能使用多少空间,算法在运行过程中,不能超出这个界限。

 

因此,对于存储空间的使用,也是有必要考虑的。

 

 

 第二章:树

http://blog.csdn.net/qq20004604/article/details/50869632

目录
相关文章
|
16天前
|
存储 机器学习/深度学习 算法
C 408—《数据结构》算法题基础篇—链表(下)
408考研——《数据结构》算法题基础篇之链表(下)。
79 29
|
16天前
|
存储 算法 C语言
C 408—《数据结构》算法题基础篇—链表(上)
408考研——《数据结构》算法题基础篇之链表(上)。
72 25
|
16天前
|
存储 人工智能 算法
C 408—《数据结构》算法题基础篇—数组(通俗易懂)
408考研——《数据结构》算法题基础篇之数组。(408算法题的入门)
58 23
|
1月前
|
存储 算法 测试技术
【C++数据结构——树】二叉树的遍历算法(头歌教学实验平台习题) 【合集】
本任务旨在实现二叉树的遍历,包括先序、中序、后序和层次遍历。首先介绍了二叉树的基本概念与结构定义,并通过C++代码示例展示了如何定义二叉树节点及构建二叉树。接着详细讲解了四种遍历方法的递归实现逻辑,以及层次遍历中队列的应用。最后提供了测试用例和预期输出,确保代码正确性。通过这些内容,帮助读者理解并掌握二叉树遍历的核心思想与实现技巧。
51 2
|
2月前
|
存储 运维 监控
探索局域网电脑监控软件:Python算法与数据结构的巧妙结合
在数字化时代,局域网电脑监控软件成为企业管理和IT运维的重要工具,确保数据安全和网络稳定。本文探讨其背后的关键技术——Python中的算法与数据结构,如字典用于高效存储设备信息,以及数据收集、异常检测和聚合算法提升监控效率。通过Python代码示例,展示了如何实现基本监控功能,帮助读者理解其工作原理并激发技术兴趣。
70 20
|
3月前
|
算法 数据处理 C语言
C语言中的位运算技巧,涵盖基本概念、应用场景、实用技巧及示例代码,并讨论了位运算的性能优势及其与其他数据结构和算法的结合
本文深入解析了C语言中的位运算技巧,涵盖基本概念、应用场景、实用技巧及示例代码,并讨论了位运算的性能优势及其与其他数据结构和算法的结合,旨在帮助读者掌握这一高效的数据处理方法。
91 1
|
3月前
|
并行计算 算法 测试技术
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面,旨在通过综合策略提升程序性能,满足实际需求。
99 1
|
3月前
|
数据采集 存储 算法
Python 中的数据结构和算法优化策略
Python中的数据结构和算法如何进行优化?
|
1天前
|
传感器 算法
基于GA遗传算法的多机无源定位系统GDOP优化matlab仿真
本项目基于遗传算法(GA)优化多机无源定位系统的GDOP,使用MATLAB2022A进行仿真。通过遗传算法的选择、交叉和变异操作,迭代优化传感器配置,最小化GDOP值,提高定位精度。仿真输出包括GDOP优化结果、遗传算法收敛曲线及三维空间坐标点分布图。核心程序实现了染色体编码、适应度评估、遗传操作等关键步骤,最终展示优化后的传感器布局及其性能。
|
1天前
|
机器学习/深度学习 算法 安全
基于深度学习的路面裂缝检测算法matlab仿真
本项目基于YOLOv2算法实现高效的路面裂缝检测,使用Matlab 2022a开发。完整程序运行效果无水印,核心代码配有详细中文注释及操作视频。通过深度学习技术,将目标检测转化为回归问题,直接预测裂缝位置和类别,大幅提升检测效率与准确性。适用于实时检测任务,确保道路安全维护。 简介涵盖了算法理论、数据集准备、网络训练及检测过程,采用Darknet-19卷积神经网络结构,结合随机梯度下降算法进行训练。