数据结构(C语言描述) 引论

1 算法及其复杂性的概念

1.1 算法与程序

算法是只解决问题的一种方法或一个过程,是由若干条指令组成的有穷序列。且具有下述4条性质。
①输入:有零个或多个由外部提供的量作为算法的输入。
②输出:算法产生至少一个量作为输出。
③确定性:组成算法的每条指令是清晰的,无歧义的。
④有限性:算法中每条指令的执行次数是有限的,执行每条指令的时间也是有限的。
程序是算法用某种程序设计语言的具体实现。

1.2 算法复杂性的概念

算法的复杂性有时间复杂性和空间复杂性之分。
可操作性最好且最有实际价值的是最坏情况下的时间复杂性。

1.3 算法复杂性的渐近性态

渐近复杂性只要关心T(n)的阶。

2 算法的表达与数据表示

2.1 问题求解

(1)将实际问题数学化。
(2)对于确定的数学问题,设计求解的方法,即算法设计。
(3)用计算机上的一种程序设计语言来表达已设计好的算法。
(4)在计算机上编辑、调试和测试制好的程序。

2.2 表达算法的抽象机制

算法实现有如下三要素:
(1)作为运算序列中各种运算的对象和结果的数据
(2)运算序列中的各种运算
(3)运算序列中的控制转移。
这三要素依序分别简称为数据、运算和控制。

机器语言
直接用机器语言表达算法有许多缺点,如下所述。
(1)大量繁杂的细节牵制着程序员,使他们不可能有更多的时间和精力去从事创造性的劳动,执行对他们来说更为重要的任务,如确保程序的正确性、高效性。
(2)程序员既要把握程序设计的全局又要深入每一个局部直到实现的细节,即使智力超群的程序员也常常会顾此失彼,屡出差错,因而所编制的程序可靠性差,且开发周期长。
(3)由于用机器语言进行程序设计的思维和表达方式与人们的习惯大相径庭,只有经过较长时间职业训练的程序员才能胜任,使得程序设计曲高和寡。
(4)机器语言的书面形式全是“密码”,可读性差,不便于交流与合作。
(5)机器语言高度依赖于具体的计算机,可移植性和可重用性差。

汇编语言
汇编语言实现了机器语言的抽象,它将机器语言的每一条指令符号化。

高级语言
在运算方面,高级语言允许原封不动第运用算法语言的算术运算、逻辑运算、关系运算、算术表达式和逻辑表达式外,还引入强有力的函数等工具,并让用户自定义。
在数据表示方面,把所有的数据加以分类。
在控制方面,高级语言通常提供表达算法控制转移的如下万式:
(1)默认的顺序控制;
(2)条件(分支)控制:
(3)选择(情况)控制;
(4)循环控制:
(5)函数调用,包括递归函数调用;
(6)无条件转移。

3 抽象数据类型

3.1 抽象数据类型的基本概念

求解该问题的算法,按照自顶向下逐步求精的原则。
顶层的运算步骤是指定义在数据模型级上的运算步骤。
底层的运算步骤是指顶层抽象运算的具体实现。
两者关系:
底层运算是顶层运算的细化,底层运算为顶层运算服务。为了将顶层算法与底层算法隔开,使二者在设计时不会互相牵制、互相影响,必须对二者的接口进行一次抽象。让底层只通过这个接口为顶层服务,顶层也只通过这个接口调用底层的运算。这个接口就是抽象数据类型, 其英文术语是Abstract DataTypes, 简记为ADT。抽象数据类型是算法设计和程序设计中的重要概念。严格地说,它是算法的一个数据模型连同定义在该模型上并作为该算法构件的一组运算。

3.2 使用抽象数据类型的好处

使用抽象数据类型将给算法和程序设计带来很多好处,如下所述。
(1)算法顶层的设计与底层的实现分离,在进行顶层设计时不必考虑所用的数据和运算如何表示和实现;反之,在进行数据表示和底层运算实现时,只要定义清楚抽象数据类型,而不必考虑在什么场合引用。这样做,算法和程序设计的复杂性降低了,条理性增强了,既能提高开发程序原型的速度,又能减少开发过程中的差错,保证编出来的程序有较高的可靠性。
(2)算法设计与数据结构设计隔开,允许数据结构自由选择、从容比较、优化算法和提高程序运行的效率。
(3)数据模型和该模型上的运算统一在抽象数据类型中,反映了它们之间内在的互相依赖和互相制约的关系,便于空间和时间耗费的折中,灵活地满足用户的要求。
(4)由于顶层设计和底层实现的局部化,在设计中出现的差错也是局部的,因而容易查找,容易纠正。在设计中常常要做的增、删、改也都是局部的,因而也都很容易进行。因此,用抽象数据类型表述的程序具有较好的可维护性。
(5)编出来的程序自然地呈现模块化,而且抽象数据类型的表示和实现都可以封装起来,便于移植和重用。
(6)为自顶向下逐步求精和模块化提供一种有效的途径和工具。
(7)编出来的程序结构清晰,层次分明,便于程序正确性的证明和复杂性的分析。

4 数据结构、数据类型和抽象数据类型

数据结构,即数据由哪些成分数据构成、以什么方式构成、呈什么结构。
数据是按照数据结构分类的,具有相同数据结构的数据属于同一类。
数据类型是按照数据结构划分的,所以一类数据结构对应着一种数据类型。最常用的数据结构是数值结构和记录结构。
抽象数据类型把数据类型和数据类型上的运算绑定并封装。

5 用C语言描述数据结构与算法

C语言的优点是类型丰富,语句精炼,使用灵活。

5.1 变量和指针

5.1.1 变量

变量是程序设计语言对存储单元的抽象,它具有以下属性。
变量名(name) :变量名是用于标识变量的符号。
地址(address) :变量的地址是变量所占据的存储单元的地址。变量的地址属性也称为左值。
大小(size) :变量的大小指该变量所占据的存储空间的数量(以字节数来衡量) 。
类型(type) :变量的类型指变量所取的值域及对变量所能执行的运算集。
值(value) :变量的值是指变量所占据的存储单元中的内容。这些内容的意义由变量的类型决定。变量的值属性也称为右值。
生命期(lifetime) :变量的生命期是指在执行程序期间变量存在的时段。
作用域(scope) :变量的作用域是指在程序中变量被引用的语句范围。

5.1.2 指针变量

指针变量用于存放对象的存储地址。例如:
在这里插入图片描述

5.2 函数与参数传递

5.2.1 函数

C语言中函数定义包括4个部分:函数名、形参表、返回类型和函数体。
函数的使用者通过函数名来调用该函数。调用函数时,将实参传递给形参作为函数的输入,函数体中的处理程序实现该函数的功能, 最后将得到的结果作为返回值输出。下面的函数max是一个简单函数的例子。
int max(in tx, in ty)2{3return xy?x:y;}
其中, max是函数名。函数后圆括号中的int x, int y是形参。函数前面的int是返回类型。花括号内是函数体,它实现函数的具体功能。
C语言中函数一般都有一个返回值。如果所定义的函数不需要返回值, 可使用vid来表示它的返回类型。函数的返回值通过函数体中的return语句返回。ream语句的作用是返回一个与返回类型相同类型的值, 并中止函数的执行。

5.2.2 参数传递

实参传递给形参。
一种是按值传递。另一种是按地址传递。

5.3 结构

5.3.1 定义结构

定义结构C语言的结构为自定义数据类型提供了灵活方便的方法, 可用于实现抽象数据类型的思想,将说明与实现分离。结构由结构名和结构的数据成员组成。说明结构的标准形式如下。
struct构名
{
数据成员列表
};

5.3.2 指向结构的指针

指向结构的指针指向结构的指针值是相应的结构变量所占据的内存空间的首地址。

5.3.3 用typedef定义新数据类型

关键字typedef常与结构一起用于定义新数据类型。

5.3.4 访问结构变量的数据成员

用圆点运算符(.)访问结构变量的数据成员。定义为指向结构的指针类型的变量用箭头运算符(->)访问结构变量的数据成员。

5.3.5 新数据类型变量初始化

使用自定义数据类型变量前通常需要初始化操作。

5.4 动态存储分配

5.4.1 动态存储分配函数malloc()和free()

C语言的标准函数malloc()和free()可用于动态存储分配。

5.4.2 动态数组

为了在运行时创建一个大小可动态变化的一维浮点数组x, 可先将x声明为一个float类型的指针。然后用函数malloc) 为数组动态地分配存储空间。例如, 语句floatx=malloc(nsizeof(float) )创建一个大小为n的一维浮点数组,然后可用x[0]x[1],…x[n-1]访问每个数组元素。

5.4.3 二维数组

C语言提供了多种声明二维数组的机制。在许多情况下,当形参是一个二维数组时,必须指定第二维的大小。例如,a[][10]是一个合法的形参,a[][]则不是。为了克服这种限制,可以使用动态分配的二维数组。

6 递归

6.1 递归的基本概念

直接或间接调用自身的算法称为递归算法。

6.1.1 阶乘函数

在这里插入图片描述

6.1.2 Fibonacci数列

在这里插入图片描述

6.2 间接递归

通过调用别的函数间接地调用其自身。

7 小结

介绍了算法的基本概念、表达算法的抽象机制,以及算法的计算复杂性概念和分析方法。简要阐述了数据类型、数据结构和抽象数据类型的基本概念,以及这3个重要概念的区别和内在联系。概述了C语言的若干重要特性和采用C语言与自然语言相结合的方式描述算法的方法。最后介绍了递归的概念,以及递归在数据结构和算法设计中的应用。

猜你喜欢

转载自blog.csdn.net/qq_45059457/article/details/114322282