算法和数据结构(1)---- 数据结构和算法基本概念

1. 数据和数据结构概念

数据:

是描述客观事物的符号,是计算中可以操作的对象,是能被计算机识别,并输入给计算处理的符号集合,数据不仅包含整型,实型等数值类型,还包括字符以及声音,图像,视频等非值类,数据是计算机能识别,处理的信息的统称

数据元素:

是组成元素的、有一定意义的基本单位,在计算机同通常作为整体处理,也被称为记录,比如在人类中,数据元素就是人,在家禽类中,猪,牛,鸡,鸭等就是数据元素,数据元素数据结构中单个数据的模型,也就说数据结构是由数据元素和数它们之间的关系构成

数据项:

一个数据元素可以由若干个数据项组成,数据项是数据不可分割的最小单位,比如对人这个数据元素来说,可以有眼睛,嘴巴,手,脚这些数据项,也可以有年龄,姓名,性别这些数据项。在数据结构这门课中,将数据项定义为最小单位,但是在正在讨论问题的时候,数据元素才是数据结构中建立数据模型的着眼点,数据项是数据元素的属性

数据对象:

是性质相同的数据元素的集合,是数据的子集

数据结构:

简单理解就是关系,在现实世界中,不同的数据元素之间不是独立的,而是存在特定的关系,我们将这些关系称为结构,数据结构是什么:

数据结构:是相互之间存在一种或者多种特定关系的数据元素的集合

数据结构是一种集合,包含了特定的数据元素,数据元素之间存在特定的关系,在计算机中,数据元素不是孤立的,杂乱无序的,而是存在内在联系的数据集合,数据元素之间存在一种或者多种特定的关系,也就是数据的组织形式

2. 数据结构分类

逻辑结构

是指数据对象中数据元素之间的相互关系,逻辑结构可以分为以下几种:

集合结构:集合中的数据元素除了属于一个集合外,它们之间没有其他关系

线性结构:线性结构中的数据元素是一对一的关系

树形结构:树形结构中的数据元素之间存在一种一对多的关系

图形结构:图形结构的数据元素是多对多的关系

用示意图表示数据的逻辑结构时,要注意两点:将每个数据元素看成一个节点,用圆圈表示,元素之间的逻辑关系用节点之间的连线表示,如果这个关系是有方向的,那么用带箭头的连线表示

物理结构(存储结构)

物理结构也称为存储结构,物理结构是指数据的逻辑结构在计算机中的存储形式,

数据是数据元素的集合,根据物理结构的定义,实际上就是如何把数据元素存储到计算机的存储器中,数据元素的存储结构形式有两种,顺序存储和链式存储:

顺序存储结构:

把数据元素放在地址连续的存储单元里,其数据间的逻辑关系和物理关系是一致的,数组就是这样的顺序存储结构

链式存储结构:

是把数据元素放在任意的存储单元里,这组存储空间可以是连续的,也可以是不连续的,数据间的存储关系不能反映其逻辑关系,因此需要一个指针存放数据元素的地址,这样就可以通过地址可以找到相关数据元素的位置

抽象数据类型(ADT)

Abstract Data Type  抽象数据类型,体现了程序设计中问题分解,抽象和信息隐藏的特性,抽象数据类型可以用下面标准格式:

ADT 抽象数据类型名
Data
数据元素之间逻辑关系的定义
Operation
操作1
   初始条件
   操作结果描述

操作2
    .....

操作n
    ......

endADT    

3. 算法中的基本概念

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

算法具有五个基本特性:输入,输出,有穷性,确定性和可行性

  • 输入输出:算法具有零个或者多个输入,一个或者多个输出,绝大多数的算法是需要输入的,算法至少有一个或者多个输出,否则就没有实现算法的必要
  • 有穷性:算法在执行有限的步骤后,自动结束而不会出现无限循环,并且每个步骤在可接受的时间内完成,死循环的代码就不满足算法有穷性的特点
  • 确定性:算法的每一个步骤具有确定的含义,不会出现二义性
  • 可行性:算法的每一步都必须是可行的,也就是说,每一步都能执行有限的次数内完成

算法的时间复杂度

在进行算法分析时,语句的总执行次数 T(n) 是关于问题规模 n 的函数,进而分析 T(n) 随 n 的变化,并确定 T(n) 的数量级,算法的时间复杂度,也就是算法的时间度量,记作 T(n) = O(f(n))。它表示随着问题规模 n 的增大,算法执行时间的增长率和 f(n) 的增长率相同,称作算法的渐近时间复杂度,简称为时间复杂度,其中的 f(n) 是问题规模 n 的某个函数

这样用大写的 来体现算法复杂度的计法,我们称之为 大 O 记法,一般来说,随着 n 的规模增大, T(n) 增长最慢的算法是最优算法

表示法表示了一个函数的上限值,具体来说,如果 g(n) 是 f(n) 的一个上限值,那么对于常数c,我们总可以找到一个 n,当 n >= n0 时,f(n) <= cg(n) 。

对于大小为 n 的数据,我们通常用函数 f(n) 来表示它的算法性能,很多情况下,我们可以完全可以确定具体的 f 的值,我们关注的算法处理的数据量变成无穷大时,算法性能将趋近一个什么样的值,一个算法的增长率非常重要,表示的是输入数据量变成无穷大时,它可以用来描述的算法效率到底有多高,表示法正是一种表示算法增长规律的方法。

  • 常数项用 O(1) 表示,分析一个算法的运行时间,无论处理多大的数据量,它至少等消耗一段固定的时间,那么就可以用常数项表述固定的时间,对于某些常数 c,正确的表述形式为:O(c) = O(1)
  • 常量因子往往被忽略,某个算法有三个运行任务 T(n) = n ,运行时间结果表示为 O(3n),根据规则可以简化为 O(n)
  • 加法运算取最大值,分析一个算法的运行时间,如何一个任何在另一个任务之后顺序执行,可以运用此规则,T1(n) = n 和 T2(n) = n2 ,运行结果表示为 O(n) + O(n2) ,根据规则可以简化为 O(n2)
  • 乘法运算的结果不需要改变,但往往可用更加紧凑的方式表示,如果一个任务引起了另一个任务的,迭代运行,可以运用此规则,T1(n) = n 和 T2(n) = n,那么运算结果表示为 O(n2)。

假设某个算法的运行时间 T(n) = 3n2 + 10n + n,用 O 表示法,函数可以简化为 O(T(n)) = n2,实际验证的也可以发现,当 n = 100 时,3n2已经占用了 96% 左右的运行时间,也就是说 n2 是对执行次数影响最大的项,用于表示此算法的时间复杂度

在前面的例子中,用T(n) 表示算法的运行时间,时间复杂度 O(n) 并没有具体表示实际算法运行需要多少时间,换句话说,一个增长率低的算法并不意味着消耗更少的运行时间,算法的时间复杂度更多的是表示算法的增长规律

O(n) 表示 T(n) 的复杂度只是说明算法运行时间和因素 n 成正比,在特定 n 的取值下,T(n) 能够达到上限值

常见复杂计算发生的复杂度:

复杂度举例
O(1)从一个数据集获取第一个元素(固定执行长度)
O(lg n)将一个数据集分为两半,然后将分开的一半再分为两半,依次类推
O(n)遍历一个数据集(循环遍历)
O(n lgn)将一个数据集分开为两半,然后再将分开每一半再分开为两半,依次类推,再此过程中同时遍历每一半数据
O(n2)遍历一个数据集的同时遍历另一个数量级相同的数据集(循环嵌套)
O(2^n)为一个数据集生成所有可能的子集(非固定长度)
O(n!)为一个数据集生成所有的排列组合(固定长度)

算法的时间复杂度分为常数阶,线性阶,对数阶和平方阶

常见的算法复杂度耗费时间从小到大依次是:

 对算法的分析,一种方法是计算所有情况的平均值,这种时间复杂度的计算方法称为平均时间复杂度,另一种方法是计算最坏情况下的时间复杂度,这种方法称为最坏时间复杂度,一般在没有特殊说明的情况下,都是指最坏的时间复杂度

算法的空间复杂度

算法的空间复杂度的计算公式是 S(n) = O(f(n)) ,其中 n 表示数据的规模,或者说数据的数量

在写代码时,可以采用空间换取时间的方法,比如判断某一年是不是闰年,可以写一个算法判断,也可以使用查表的方式实现

常见算法的设计方法

从广义上来讲,很多算法解决思路是相同的的,因此,为了方便,通常使用算法使用的方法和思路对其进行分类:

随机法:

随机法依赖随机数的统计特征,快速排序应用的就是随机法

快速排序的思路:设想要对一堆作废的支票排序,首先将无序的一堆分为两部分,其中一堆里所使用的支票号码都小于等于这个中间值,另一堆里都大于这个中间值。一旦有了这样的两堆支票后,就再以同样的方式对这两堆支票重复刚才的划分过程,直到每一堆里都只有一张支票为止,这时所有的支票都已经排好序列了。

为了获得较高的性能,快速排序依赖于每一次如何划分支票,我们需要让划分的两堆支票数量基本相同,为了实现这一步,理想的方法是在划分支票之前找到号码的中间值,但是为了确定这个中间值需要遍历所有的支票,作为替代的方法,随机选择一个支票号码作为划分的依据,快速排序的平均性能很不错,因为随机数的正态分布使得划分的结果是相对公平的

分治法:

分治法包含三个步骤:分解,求解和合并,分解阶段,将数据分解为更小更容易管理的部分,求解阶段,对每个分解出的部分进行处理,合并阶段,将每部分的处理结果进行合并,归并排序就是分治法的体现

排序一堆作废的支票,首先将无序的一堆分为两半,下一步将两堆支票各自分为两半,一直持续到直到每一堆中都只有一张支票为止,一旦堆中都只有一张支票时,就将其两两合并,保证每一个合并后的新堆都是有序的。

动态规划:

动态规划和分治法类似,都是将较大的问题分解为子问题,最后再将结果合并,在分治法中,每一个子问题都是独立的,我们以递归的方式解决每一个子问题,然后再将结果和其他子问题的结果合并。

动态规划中,子问题之间不是独立的,换句话说,子问题之间可能存在关联。

贪心法:

贪心法在求解问题时总能够做出在当前的最佳选择,换句话说,不是从整体最优上考虑,而仅仅是在某种意义上局部的最优解,一个贪心法的例子是霍夫曼编码,这个一个数据压缩算法。

近似法:

近似法并不计算出最优解,相反,它总是计算出足够好的解,通常利用近似法解决那些计算成本很高又因为其本身十分有价值而不愿放弃的问题,推销员问题是一个通常用近似法解决的问题

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值