数据结构_day02_08-30

1、绪论

1. 基本概念和术语

  • 数据类型

一个值的集合和定义在这个值集上的一组操作的集合

高级语言中,显式或隐式规定在程序执行期间变量和表达的所有可能的取值范围

  • 抽象数组类型(ADT)

抽象:抽取出实际问题的本质

形式定义:(D,S,P)三元组

D是数据对象

S是D的关系集

P是对D的基本操作集

定义格式:

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

基本操作的定义格式:

基本操作名(参数表)
  初始操作: <初始条件描述>
  操作结果: <操作结果描述>

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

以实现虚数抽象数据结构为例:

// 定义数据对象及其关系
struct Complex
{
	float realpart;
	float imagpart;
};

// 打印复数
void PrintComplex(struct Complex* p)
{
	if (p->imagpart > 0)
	{
		printf("%.2f+%.2fi\n", p->realpart, p->imagpart);
	}
	else if (p->imagpart == 0)
	{
		printf("%.2f\n", p->realpart);
	}
	else
	{
		printf("%.2f%.2fi\n", p->realpart, p->imagpart);
	}
	
}

// 声明基本操作
void Assign(struct Complex* p, float real, float imag);
void Add(struct Complex* p, float real, float imag);
void Minus(struct Complex* p, float real, float imag);
void Multiply(struct Complex* p, float real, float imag);
void Divide(struct Complex* p, float real, float imag);

int main()
{
	struct Complex complex = { 1.0f, 1.0f };
	//Add(&complex, 1.0f, -1.0f);
	//Minus(&complex, 2.0f, 3.0f);
	//Multiply(&complex, 3.0, 2.0);
	Divide(&complex, 1.0f, 1.0f);
	PrintComplex(&complex);

	return 0;
}

// 实现基本操作
// 构造
void Assign(struct Complex* p, float real, float imag)
{
	p->realpart = real;
	p->imagpart = imag;
}
// 加
void Add(struct Complex* p, float real, float imag)
{
	p->realpart += real;
	p->imagpart += imag;
}
// 减
void Minus(struct Complex* p, float real, float imag)
{
	p->realpart -= real;
	p->imagpart -= imag;
}
// 乘
void Multiply(struct Complex* p, float real, float imag)
{
	float tmp = p->realpart;
	p->realpart = p->realpart * real - p->imagpart * imag;
	p->imagpart = tmp * imag + p->imagpart * real;
}
// 除
void Divide(struct Complex* p, float real, float imag)
{
	struct Complex tmp = { real, -1 * imag };
	float fm = real * real + imag * imag;
	Multiply(&tmp, p->realpart, p->imagpart);
	p->realpart = tmp.realpart / fm;
	p->imagpart = tmp.imagpart / fm;
}


3. 算法和算法分析

算法:解决特定问题的方法和步骤

算法的描述:

  • 自然语言
  • 流程图:传统流程图(框图)、NS流程图(盒图)
  • 伪代码
  • 程序代码

算法的特性:

  1. 有穷性:一个算法必须总是在执行有穷步骤之后结束,且每一步都在有穷时间内完成
  2. 确定性:每一条指令必须有确切的含义
  3. 可行性:算法描述的操作可以通过已经实现的基本操作执行有限次来实现
  4. 输入
  5. 输出

评价算法的标准:

  1. 正确性:在合理的数据输入下,在有限的运行时间内可以得到正确的结果
  2. 可读性:算法应易于人的理解
  3. 健壮性:当输入非法数据时,可以适当地做出正确反应或做出相应处理
  4. 高效性:消耗尽量少的时间和空间

4. 时间复杂度

算法时间效率的度量:

算法执行所消耗的时间

度量方法:

  • 事前分析:估算

  • 事后统计:实际运行程序测算

    (由于事后统计需要实现算法,且较依赖于软硬件等环境因素,从而造成误差)

算法运行时间 = ∑(一个简单操作所需的时间 * 简单操作次数)

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

由于计算机的软硬件环境会影响语句的执行时间,故可简化为只考虑语句频度

另外,可以再进行简化,即仅考虑其数量级,忽略其倍数

最终,可简化为T(n) = O(f(n)),称为算法的渐进时间复杂度,简称时间复杂度

其中,f(n)是T(n)的同数量级函数(时间增长率与fn增长率相同)

例:

T(n) = 2n^3 + 3n^2 + 2n + 1

当n->∞时,T(n) / n^3 -> 2,为非零常数,故T(n)与n^3是同数量级,该算法时间复杂度为O(n^3)

一般情况下,不必计算所有的执行次数,仅找到最大次数即为该算法的时间复杂度

时间复杂度的计算:

  1. 找出语句频度最大的那条语句作为基本语句
  2. 计算基本语句的频度得到问题规模n的某个函数f(n)
  3. 取其数量级用符号"O"表示