第一章——概论

概论

掌握常用的基本数据结构的ADT(Abstract Data Type)及其应用
学会合理地组织数据, 有效地表示数据, 有效地处理数据
掌握算法的设计分析技术
提高程序设计的质量
1946年美国第一台电子计算机问世,那时候它用来计算弹道轨迹,也就是用来进行数值计算。早期的计算机一直都是用来进行数值计算的,比如数学中的求解方程组,计算微积分等。
随着时代的进步与发展,单纯的数值计算不能再满足人们的要求,计算机也发展到可以进行非数值计算,比如找出几个数中的最大数,排序,查找,分类等等。
1968 年克努思教授开创了数据结构的最初体系,他所著的《计算机程序设计艺术》第一卷《基本算法》是第一本较系统地阐述数据的逻辑结构和存储结构及其操作的著作。 70 年代初,数据结构作为一门独立的课程开始进入大学课堂。
无结构阶段。
40~60 年代,计算机的应用主要针对科学计算,程序设计技术以机器语言 / 汇编语言为主,程序处理的数据是纯粹的数值,数据之间的关系主要是数学公式或数学模型。
结构化阶段
60~80 年代,计算机开始广泛应用于非数值处理领域,数据表示成为程序设计的重要问题。图灵奖获得者沃思给出了一个著名的公式:
程序=数据结构 + 算法

面向对象阶段

对象=数据结构+算法
程序=对象+对象+。。。。
面向对象技术(首先是面向对象程序设计)始于 80 年代初,是目前最流行的程序设计技术。

用计算机求解问题一般包含两个步骤:
⑴ 抽象出问题的模型;
⑵ 求该模型的解。
对于数值问题抽象出的模型通常是数学方程,例如
图形的面积与周长等
预报人口增长情况的模型
更多的非数值问题是难以用数学方程来描述的。


数据结构的基本概念

数据(Data):是对客观事物的符号表示,在计算机科学中是指能输入到计算机并被计算机程序处理的符号的总称。
数据一般可分为数值数据、文本数据、图形图像数据和音响数据等。
数据元素(Data Element):是数据的基本单位,也可以称为结点,在计算机程序中通常作为一个整体进行考虑。
数据元素一般由若干数据项(Data Item)组成,数据项是构成数据元素最小的、不可分割的单位。
数据处理(Data Process):对数据进行检索、插入、删除、合并、拆分、排序、统计、计算、转换、输入、输出等的操作过程。
数据结构(Data Structure):
相互之间存在一定关系的数据的集合。
是数据及其元素之间相互关系的表示。
逻辑结构:数据元素之间一般存在某种特定的关系,这种关系称为数据的逻辑结构。
物理结构(存储结构):数据结构在计算机内存中的表示形式。包括数据元素的表示和其关系的表示。

逻辑结构

线性结构(linear structure)
树型结构(tree structure)
图结构(graph structure)
集合(set)
计算机的主存储器的特性
1,其存储空间提供了一种具有非负整数地址编码的,相邻单元的集合,其基本的存储单元是字节
2,计算机的指令具有按地址随机访问存储空间内任意单元的能力,访问不同地址所需的访问时间基本相同
数据存储结构又称物理结构,是数据及其逻辑结构在计算机中的表示
存储结构的分类: 1. 顺序结构 2. 链式结构
顺序(sequential)的方法
用一块无空隙的存储区域存储数据称为顺序存储
顺序存储把一组结点存储在按地址相邻的顺序存储单元里,结点间的逻辑后继关系用存储单元的自然顺序关系来表达
顺序存储结构称为紧凑存储结构,其紧凑性是指它的存储空间除了存储有用数据外,没有用于存储其他附加的信息
紧凑性可以用‘存储密度’来度量:它是一个存储结构所存储的‘有用数据’和该结构(包括附加信息)整个存储空间大小之比。
利用指针,在结点的存储结构中附加指针字段称为链接法。两个结点的逻辑后继关系可以用指针的指向来表达
任意的逻辑关系,也可以使用这种指针地址来表达。一般的做法是将数据结点分为两部分:
数据字段 指针字段


抽象数据类型(Abstract Data Type)

数据类型(Data Type):
数据类型显式或隐含地规定了:
1,在程序执行期间变量或表达式所有可能的取值范围,
2,以及在这些值上允许执行的操作
即数据类型是一个值的集合和定义在这个值集上的一组操作的总称。
由用户定义,用以表示应用问题的数据模型。
ADT是指一种数据结构以及定义在该数据结构上的一组操作。
由基本的数据类型组成, 并包括一组相关的服务(或称操作)。
信息隐蔽和数据封装,使用与实现相分离。
ADT的定义
一个 ADT 的定义不涉及它的实现细节,在形式上可繁可简。通常包含以下内容:
抽象数据类型名
数据元素之间逻辑关系的定义
每种基本操作的接口(操作的名称和该操作的前置条件、输入、功能、输出、后置条件的定义)
描述

ADT 抽象数据类型名
Data
数据元素之间逻辑关系的定义
Operation
操作 1
前置条件:执行此操作前数据所必须的状态
输入:执行此操作所需要的输入
功能:该操作将完成的功能
输出:执行该操作后产生的输出
后置条件:执行该操作后数据的状态
操作 2
……
……
操作 n
endADT
ADT integer
Data 整数a:
Operation
Constructor
前置条件:整数a不存在
输入:一个整数b
功能:构造一个与输入值相同的整数输出:无
后置条件:整数a具有输入的值
Set
前置条件:存在一个整数a
输入:一个整数b
功能:修改整数a的值,使之与输入的整数值相同
输出:无
后置条件:整数a的值发生改变
Add
前置条件:存在一个整数a
输入:一个整数b
功能:将整数a与输入的整数b相加
输出:相加后的结果 后置条件:整数a的值发生改变
Sub
前置条件:存在一个整数a
输入:一个整数b
功能:将整数a与输入的整数b相减 输出:相减的结果
后置条件:整数a的值发生改变
endADT
ADT rectangle
Data
长方形的长和宽:w, h
Operation
Constructor
前置条件:长方形不存在
输入:一个长方形的长和宽
功能:根据输入长和宽构造长方形
输出:无 后置条件:长方形的长和宽具有输入值
S
前置条件:存在一个长方形
输入:无 功能:计算长方形的面积
输出:计算的结果
后置条件:长方形的长和宽保持不变
……
endADT
算法(algorithms):
是为了求解问题而给出的有限的指令序列,每条指令表示一个或多个操作。——解决问题的步骤
程序
是算法的一种实现,计算机按照程序逐步执行算法,实现对问题的求解。

算法的性质

1,有穷性:一个算法必须能在执行有穷步之后结束,且每一步都可在有穷时间内完成;
2,确定性:算法中每一条指令必须有确切的含义,不具有二义性。
3,可行性:算法中描述的操作都可通过已经实现的基本运算执行有限次来实现。
4,输入:一个算法有零个或多个输入,这些输入取自某个特定的对象的集合;
5,输出:一个算法有一个或多个输出,这些输出是同输入具有某种特定关系的量。
算法的描述
算法设计者在构思和设计了一个算法之后,必须清楚准确地将所设计的求解步骤记录下来,即描述算法。
常用的描述算法的方法有
自然语言
流程图
程序设计语言
伪代码等。
下面以欧几里得算法(用辗转相除法求两个自然数 m 和 n 的最大公约数并假设 m ≥ n )为例进行介绍

自然语言
① 输入 m 和 n ;
② 求 m 除以 n 的余数 r ;
③ 若 r 等于 0 ,则 n 为最大公约数,算法结束;否则执行第④步;
④ 将 n 的值放在 m 中,将 r 的值放在 n 中;
⑤ 重新执行第②步。
伪代码是介于自然语言和程序设计语言之间的方法,它采用某一程序设计语言的基本语法,操作指令可以结合自然语言来设计。

算法分析

解决同一个问题总是存在着多种算法,而算法设计者在所花费的时间和所使用的空间资源往往要两者之间采取折中,通常是采用某种以空间资源换取时间资源的策略
算法设计者可以通过算法分析,判断所提出的算法是否现实,分析算法的效率以求改进
算法分析的内容
算法运行所需要的时间,称为时间复杂性
事前估计法
事后统计法
算法运行所需要的辅助空间,称为空间复杂性
算法时间复杂度-算法的后期测试
事后统计法 — 程序运行测试
不同算法的程序通过一组或若干组相同的统计数据分辨其优劣。
在算法中的某些部位插装时间函数
time ( )
测定算法完成某一功能所花费时间
顺序搜索 (Sequenial Search)

int seqsearch ( int a[ ], int n, int x ) {//在a[0],…,a[n-1]中搜索x
    int i = 0;
    while ( i < n && a[i] != x )
          i++;
    if ( i == n ) 
 return -1;
    return i;
}

插装 time( ) 的计时程序

 double start, stop;
      time (&start); 
      int k = seqsearch (a, n, x);
      time (&stop);   
      double runTime = stop - start;
      cout << " " << n << " " 
      cout runTime << endl;

算法的后期测试

缺点:需先运行依据算法编制的程序
软、硬件环境影响测试结果

同一个算法用不同的语言实现,或者用不同的编译程序进行编译,或者在不同的计算机上运行时,效率均不相同。这表明使用绝对的时间单位衡量算法的效率是不合适的。

算法的时间复杂度度量
撇开与计算机硬件、软件有关的因素,可以认为一个特定算法“运行工作量”的大小,只依赖于问题的规模n,即输入量的大小。如:
对一个长度是n一维数组排序,问题规模为n
对一个mn的二维数组进行排序,问题规模为mn
算法执行时间T是问题规模的函数,计为T(n).
结论:用基本语句执行次数度量算法时间复杂性
事前估算法 — 时间复杂度估计
时间复杂度:
算法的执行时间(所有语句的语句频度之和)
T(n)=n+1+n(n+1)+n2=2n+2n2+1
问题规模:求解问题的输入量
lim T(n)/n2=lim(2n+2n2+1)/2n2=1
n->∞
当问题规模 n→∞时T(n)与某一量同阶,称作算法的渐近时间复杂度 (asymptotic time complexity,随着问题规模的增加,算法运行时间的增长趋势) :
记作:T(n)=O(n2) O是order的简写
时间复杂度只与算法中语句频度最大的语句(基本语句)有关, 而其它语句的时间可以不计
用F(n)代表算法中语句频度最大的语句的频度(基本语句)
则T(n)=O(F(n)): 时间复杂度: T(n)=O(F(n))

void matrix_addition(double **M1, double **M2, int n){
       for (int i=0 ; i<n; i++)  
      for (int j=0 ; j<n; j++)
   M1[i][j] = M1[i][j] +M2[i][j] ; 
}

void select_sort(int a[], int n ) { 
   for ( int i = 0; i <= n-1; ++i ){   
      j=i;
        for (k=i+1;k<n;++k)
             if(a[k]<a[j]) 
                j=k;
        if (j!=i)
         {w=a[j];a[j]=a[i];a[i]=w;} 
      }
   }

最坏、最好、和平均情况
由于算法实际执行的操作往往依赖于分支条件的走向,而输入数据的取值又影响这些分支走向,因此很多算法都无法得出独立于输入数据的渐近估计。
针对这一情况,提出了最好情况估计、最坏情况估计、平均情况估计。

int Find(int A[], int n,int k){
    for(i=0;i<n;i++)
         if(A[i]==k) break;
    return i;
}

算法执行时间分析:
如果数组的第一个元素恰好就是 k ,算法只要比较一个元素就行了,这是 最好情况 (最乐观的估计);
如果数组的最后一个元素是 k ,算法就要比较 n 个元素,这是 最坏情况 (最悲观的估计);
如果在数组中查找不同的元素 k ,假设数据是等概率分布,则平均要比较 n /2 个元素,这是 平均情况
算法的空间复杂度
算法的空间复杂度是指在算法的执行过程中,需要的辅助空间数量。
辅助空间是除算法本身和输入输出数据所占据的空间外,算法临时开辟的存储空间。通常记作:S ( n ) = O ( f ( n ))
其中, n 为问题规模,分析方法与算法的时间复杂度类似。
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

泡泡>3<

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值