编程语言
首页 > 编程语言> > 算法基础知识总结

算法基础知识总结

作者:互联网

1.基本概念

1.1 背景

1.2 术语

1.1.1 数据(Data)

分为数值型数据和非数值型数据

1.1.2 数据元素(Data Element)

数据的基本单位,在计算机程序中通常作为一个整体进行考虑和处理,也简称为元素,或称为记录结点顶点

1.1.3 数据项(Data Item)

构成数据元素的不可分割最小单位

1.1.4 数据对象(Data Object)

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

1.1.5 数据结构(Data Structure)

数据元素不是孤立存在的,它们之间存在着某种关系,数据元素相互之间的关系称为结构(Structure)

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

数据结构包括以下三个方面的内容:

  1. 数据元素之间的逻辑关系,也称为逻辑结构

  2. 数据元素及其关系在计算机内存中的表示(又称为映像),称为数据的物理结构或数据的存储结构

  3. 数据的运算和实现,即对数据元素可以施加的操作以及这些操作在相应的存储结构上的实现

1.1.5.1 数据结构的两个层次

1.1.5.1.1 逻辑结构
1.1.5.1.1.1 逻辑结构的种类
划分方法一
  1. 线性结构

有且仅有一个开始和一个终端结点,并且所有结点都最多只有一个直接前趋和一个直接后继

例如:线性表、栈、队列、串

  1. 非线性结构

一个结点可能有多个直接前取和直接后继

例如:树、图

划分方式二—四类基本逻辑结构
  1. 集合结构:结构中的数据元素之间除了同属于一个集合的关系外,无任何其它关系

  2. 线性结构:结构中的数据元素之间存在着一对一的线性关系

  3. 树形结构:结构中的数据元素之间存在着一对多的层次关系

1.1.5.1.2 物理结构(存储结构)
四种基本的存储结构

用一组连续的存储单元依次存储数据元素,数据元素之间的逻辑关系由元素的存储位置来表示

例如:C语言中用数组来实现顺序存储结构

用一组任意的存储单元存储数据元素,数据元素之间的逻辑关系用指针来表示

例如:C语言中用指针来实现链式存储结构

在存储结点信息的同时,还建立附加的索引表

索引表中的每一项称为一个索引项

索引项的一般形式是:(关键字,地址)

关键字是能唯一标识一个结点的那些数据项

若每个结点在索引表中都有一个索引项,则该索引表称为稠密索引(Dense Index)。若一组结点在索引表中只对应一个索引项,则该索引表称之为稀疏索引(Sparse Index)

根据结点的关键字直接计算出该结点的存储地址

1.1.5.1.3 逻辑结构与存储结构的关系

1.1.6 数据类型和抽象数据类型

在使用高级程序设计语言编写程序时,必须对程序中出现的每个变量、常量或表达式明确说明它们所属的数据类型

高级语言中的数据类型明显地或隐含地规定了在程序执行期间变量的所有可能的取值范围,以及在这些数值范围上所允许进行的操作

数据类型的作用:

  1. 约束变量或常量的取值范围

  2. 约束变量或常量的操作

数据类型(Data Type)

定义:数据类型是一组性质相同的值的集合以及定义于这个值集合上的一组操作的总称

数据类型 = 值的集合 + 值集合上的一组操作

抽象数据类型(Abstract Data Type, ADT)

定义:是指一个数学模型以及定义在此数学模型上的一组操作

抽象数据类型的形式定义:

抽象数据类型可用(D, S, P)三元组表示。

其中:D是数据对象;S是D上的关系集;P是对D的基本操作集

一个抽象数据类型的定义格式如下:

ADT 抽象数据类型名{
    数据对象:<数据对象的定义>
    数据关系:<数据关系的定义>
    基本操作:<基本操作的定义>
} ADT 抽象数据类型名

其中:

基本操作定义格式说明:

参数表:赋值参数只为操作提供输入值。引用参数以&打头,除可提供输入值外,还将返回操作结果

初始条件:描述操作执行之前数据结构和参数应满足的条件,若不满足,则操作失败,并返回相应出错信息。若初始条件为空,则省略之

操作结果:说明操作正常完成之后,数据结构的变化状况和应返回的结果。

e.g. Circle

ADT Circle{
    数据对象:D = {r,x,y|r,x,y均为实数}
    数据关系:S = {<r,x,y>|r是半径,<x,y>是圆心坐标}
    基本操作:
    Circle(&C,r,x,y)
        操作结果:构造一个圆
    double Area(C)
        初始条件:圆已存在
        操作结果:计算面积
    double Circumference(C)
        初始条件:圆已存在
        操作结果:计算周长
    ......
} ADT Circle

e.g. 复数

ADT Complex{
    数据对象:D = {r1, r2|r1,r2都是实数}
    数据关系:S = {<r1, r2>|r1是实部,r2是虚部}
    基本操作:
    assign(&C,v1,v2)
        初始条件:空的复数C已存在
        操作结果:构造复数C,r1,r2分别被赋以参数v1,v2的值
    destory(&C)
        初始条件:复数C已存在
        操作结果:复数C被销毁
    GetReal(C, &realPart)
        初始条件:复数C已存在
        操作结果:用realPart返回复数C的实部值
    GetImag(C, &ImagPart)
        初始条件:复数已存在
        操作结果:用ImagPart返回复数C的虚部值
    Add(c1, c2, &sum)
        初始条件:c1, c2是复数
        操作结果:sum返回两个复数c1, c2的和
    ......
} ADT Complex

1.3 总结

2.抽象数据类型的表示与实现

抽象数据类型可以通过固有的数据类型(如整型、实型、字符型等)来表示和实现

例如:抽象数据类型“复数”的实现

typedef struct{
    float realpart; // 实部
    float imagpart; // 虚部
}Complex // 定义复数抽象类型

Complex assign(Complex* A, float real, float imag); // 赋值
Complex add(Complex* c, Complex A, Complex B); // A + B
Complex minus(Complex* c, Complex A, Complex B); // A - B
Complex multiply(Complex* c, Complex A, Complex B); // A * B
Complex divide(Complex* c, Complex A, Complex B); // A / B
Complex assign(Complex* A, float real, float imag){
    A->realpart = real; // 实部赋值
    A->imagpart = imag; // 虚部赋值
    return A;
}

Complex add(Complex* c, Complex A, Complex B){
    c->realpart = A.realpart + B.realpart; // 实部相加
    c->imagpart = A.imagpart + B.imagpart; // 虚部相加
    return c;
}

Complex minus(Complex* c, Complex A, Complex B){
    c->realpart = A.realpart - B.realpart; // 实部相减
    c->imagpart = A.imagpart - B.imagpart; // 虚部相减
    return c;
}

Complex multiply(Complex* c, Complex A, Complex B){
    c->realpart = A.realpart * B.realpart - A.imagpart * B.imagpart;
    c->imagpart = A.imagpart * B.realpart + A.realpart * B.imagpart;
    return c;
}

Complex divide(Complex* c, Complex A, Complex B){
    c->realpart = (A.realpart * B.realpart + A.imagpart * B.imagpart) / (B.realpart * B.realpart + B.imagpart * B.imagpart);
    c->imagpart = (A.imagpart * B.realpart - A.realpart * B.imagpart) / (B.realpart * B.realpart + B.imagpart * B.imagpart);
    return c;
}

3.算法和算法分析

算法的定义:对特定问题求解方法和步骤的一种描述,它是指令有限序列。其中每个指令表示一个或多个操作。简言之,算法就是解决问题的方法和步骤

算法的描述:

算法与程序

程序 = 数据结构 +算法

数据结构通过算法实现操作

算法根据数据结构设计程序

算法特性

一个算法必须具备以下五个重要特性:

算法设计的要求

一个好的算法首先要具备正确性,然后是健壮性,可读性,在几个方面都满足的情况下,主要考虑算法的效率,通过算法的效率高低来评判不同算法的优劣程度

算法效率以下两个方面来考虑:

  1. 时间效率:指的是算法所耗费的时间

  2. 空间效率:指的是算法执行过程中所耗费的存储空间

注意:时间效率和空间效率往往不可兼得

算法时间效率的度量

算法时间效率可以用依据该算法编制的程序在计算机上执行所消耗的时间来度量

两种度量方法:

注意:每条语句的执行次数又称为语句频度

每条语句执行依次所需的时间,一般是随机器而异的。取决于机器的指令性能、速度以及编译的代码质量。是由机器本身软硬件环境决定的,它与算法无关

所以我们可以假设执行每条语句所需的时间均为单位时间。此时对算法的运行时间的讨论就可转化为讨论该算法中所有语句的执行次数,即频度之和

这就可以独立于不同机器的软硬件环境来分析算法的时间性能了

O:Order 数量级

一般情况下,不必计算所有操作的执行次数,而只考虑算法中基本操作执行的次数,它是问题规模n个某个函数,用T(n)表示

基本语句:

问题规模n:n越大算法的执行时间越长

定理1.1

若f(n) = \(a_{m}n^{m}\)+\(a_{m-1}n^{m-1}\)+...+\(a_1n\)+\(a_0\)是m次多项式,则T(n) = O(\(n^{m}\))

忽略所有低次幂项和最高次幂系数,体现出增长率的含义

分析算法时间复杂度的基本方法

  1. 找出语句频度最大的那条语句作为基本语句

  2. 计算基本语句的频度得到问题规模n的某个函数f(n)

  3. 取其数量级用符号"O"表示

注意:时间复杂度是由嵌套最深层语句的频度决定的

练习:

算法时间复杂度

请注意:有的情况下,算法中基本操作重复执行的次数还随问题的输入数据集不同而不同

[例] 顺序查找,在数组中查找值等于e的元素,返回其所在位置

for(i = 0; i < n; i++)
    if(a[i] == e) return i + 1;
return 0;

最好情况:1次;最坏情况:n;平均时间复杂度为:O(n)

对于复杂的算法,可以将它分成几个容易估算的部分,然后利用大O加法法则和乘法法则,计算算法的时间复杂度

  1. 加法法则:T(n) = \({T_1}\)(n) + \(T_2\)(n) = O(f(n)) + O(g(n)) = O(max(f(n),g(n)))

  2. 乘法法则:T(n) = \({T_1}\)(n) × \(T_2\)(n) = O(f(n)) × O(g(n)) = O(f(n)×g(n))

算法时间效率的比较

复杂度:O(1) < O(logn) < O(n) < O(nlogn) < O(\(n^{2}\)) < O(\(n^{3}\)) < ······ < O(\(n^{k}\)) < O(\(2^{n}\)) < O(n!)

渐进空间复杂度

空间复杂度:算法所需存储空间的度量,记作:S(n) = O(f(n)),其中n为问题的规模(或大小)

算法要占据的空间

例如:将一维数组a中的n个数逆序存放到原数组中

// 算法1
for(int i = 0; i < n / 2; i++){
    // t为辅助空间
    t = a[i];
    a[i] = a[n-i-1];
    a[n-i-1] = t;

    // S(n) = O(1) 原地工作
}

// 算法2
for(int i = 0; i < n; i++){
    b[i] = a[n-i-1];
}
for(int i = 0; i < n; i++){
    a[i] = b[i];
}

// S(n) = O(n)

4.总结

标签:总结,imagpart,基础知识,算法,Complex,操作,realpart,数据
来源: https://www.cnblogs.com/skipspur163/p/15913421.html