第一章:绪论
1.1数据结构的基本概念
1.数据:数据是信息的载体,是描述客观事物属性的数、字符以及所有能输入到计算机中并被程序识别
和处理的符号的集合。
2.数据元素:数据元素是数据的基本单位,通常作为一个整体进行考虑和处理。一个数据元素可由若干
数据项组成,数据项是构成数据元素的不可分割的最小单位。例如,学生记录就是一个数据元素,它由
学号、姓名、性别等数据项组成。
3.数据对象:数据对象是具有相同性值的数据元素的集合,是数据的一个子集。
4.数据类型:数据类型是一个值的集合和定义再此集合上的一组操作的总称。
1)原子类型。其值不可再分的数据类型。如bool 和int 类型。
2)结构类型。其值可以再分解为若干成分(分量)的数据类型。
3)抽象数据类型。抽象数据组织及与之相关的操作。
5.数据结构:数据结构是相互之间存在一种或多种特定关系的数据元素的集合。
1.2数据结构的三要素
1.数据的逻辑结构:
逻辑结构是指数据元素之间的逻辑关系,即从逻辑关系上描述数据。
逻辑结构包括:
- 集合结构:结构中的数据元素之间除“同属一个集合”外,别无其它关系。
- 线性结构:结构中的数据元素之间只存在一对一的关系,除了第一个元素,所有元素都有唯一前
驱;除了最后一个元素,所有元素都有唯一后继。 - 树形结构:结构中数据元素之间存在一对多的关系。
- 图状结构:数据元素之间是多对多的关系。
2.数据的存储结构(物理结构):
存储结构是指数据结构在计算机中的表示(又称映像),也称物理结构。
存储结构包括: - 顺序存储:把逻辑上相邻的元素存储在物理位置也相邻的存储单元中,元素之间的关系由存储单元
的邻接关系来体现。 - 链式存储:逻辑上相邻的元素在物理位置上可以不相邻,借助指示元素存储地址的指针来表示元素
之间的逻辑关系。 - 索引存储:在存储元素信息的同时,还建立附加的索引表,索引表中的每项称为索引项,索引项的
一般形式是(关键字,地址) - 散列存储:根据元素的关键字直接计算出该元素的存储地址,又称哈希(Hash)存储。
3.数据的运算:施加在数据上的运算包括运算的定义何实现。运算的定义是针对逻辑结构的,指出运算
的功能;运算的实现是针对存储结构的,指出运算的具体操作步骤。
1.3算法的基本概念
程序=数据结构+算法
算法(algorithm)是对特定问题求解步骤的一种描述,它是指令的有限序列,其中的每条指令表示一个
或多个操作。
算法的特性:
1.有穷性:一个算法必须总在执行有穷步之后结束,且每一步都可在有穷时间内完成。
2.确定性:算法中每条指令必须有确定的含义,对于相同的输入只能得到相同的输出。
3.可行性:算法中描述的操作都可以通过已经实现的基本运算执行有限次来实现。
4.输入:一个算法有零个或多个输入,这些输入取自于某个特定的对象的集合。
5.输出:一个算法有一个多个输出,这些输出是与输入有着某种特定关系的量。
好的算法达到的目标:
- 正确性:算法应能够正确的求接问题。
- 可读性:算法应具有良好的可读性,以帮助人们理解。
- 健壮性:输入非法数据时,算法能适当地做出反应或进行处理,而不会产生莫名奇妙地输出结果。
- 效率与低存储量需求:效率是指算法执行的时间,存储量需求是指算法执行过程中所需要的最大存
储空间,这两者都与问题的规模有关。
1.4算法的时间复杂度
一般情况下,算法中基本操作重复执行的次数是问题规模n的某个函数f(n),算法的时间量度记作T
(n)=O(n),它表示随问题规模n的增大而增大,算法执行时间的增长率和f(n)的增长率相同,称作算法
的渐近时间复杂度,简称时间复杂度。
时间复杂度是一种衡量算法执行时间的度量方式,它表示随着输入规模的增长,算法的执行时间如何增加。
在计算时间复杂度时,我们通常考虑算法执行基本操作的次数(比如循环迭代次数、条件判断次数、函数调用次数等),并用大O符号(O)来表示。下面是一些常见的时间复杂度及其对应的表示方式:
常数时间复杂度(O(1)):无论输入规模的大小,算法的执行时间都是常数级别的。
线性时间复杂度(O(n)):算法的执行时间与输入规模成线性关系,当输入规模增加一倍时,执行时间也增加一倍。
对数时间复杂度(O(log n)):算法的执行时间与输入规模的对数成关系,常见于分治算法或二分查找等。
线性对数时间复杂度(O(n log n)):算法的执行时间介于线性和对数之间,常见于快速排序、归并排序等排序算法。
平方时间复杂度(O(n^2)):算法的执行时间与输入规模的平方成关系,常见于嵌套循环算法。
指数时间复杂度(O(2^n)):算法的执行时间随着输入规模的增加呈指数级增长,常见于穷举搜索等问题。
以上只是一些常见的时间复杂度,还有其他更高阶的复杂度如立方阶(O(n3))、指数对数阶(O(2(log n)))等。
需要注意的是,时间复杂度只关注算法的执行时间与输入规模的关系,并不考虑具体的常数因子。因此,两个具有相同时间复杂度的算法在实际执行中可能有不同的执行时间。此外,时间复杂度是对算法的整体评估,并不表示每一种输入情况下都具有相同的执行时间。
1.5算法的空间复杂度
算法的空间复杂度S(n)定义为该算法所耗费的存储空间,它是问题规模n的函数。记为S(n)=O(g(n))。
算法的空间复杂度描述了算法执行所需的额外存储空间的量级。它衡量了算法在运行过程中所使用的内存空间。以下是常见的空间复杂度表示法及其含义:
O(1):常数空间复杂度,表示算法所需的额外空间是一个常量。无论输入规模大小如何,算法所需的额外空间是固定的。
O(n):线性空间复杂度,表示算法所需的额外空间随着输入规模线性增长。例如,如果算法需要一个与输入规模成比例的数组来存储数据,则空间复杂度为O(n)。
O(n^2):平方空间复杂度,表示算法所需的额外空间随着输入规模的平方增长。这通常发生在嵌套循环的情况下,每次循环都需要额外的空间。
O(log n):对数空间复杂度,表示算法所需的额外空间随着输入规模的对数增长。这通常出现在使用递归或分治算法的情况下,每次递归调用都需要一些额外的空间。
O(nlog n):线性对数空间复杂度,表示算法所需的额外空间随着输入规模乘以其对数增长。这在某些排序算法(如快速排序和归并排序)中常见。
需要注意的是,空间复杂度通常指的是算法在运行过程中额外使用的存储空间,并不包括输入数据本身的存储空间。另外,空间复杂度的分析也可以基于最坏情况、平均情况或最好情况下的空间使用量。
在实际应用中,了解和考虑算法的空间复杂度对于有效地管理内存资源、优化算法性能以及解决特定问题非常重要。
1.4 常见复杂度
数据结构的时间复杂度和空间复杂度是衡量算法性能的重要指标。时间复杂度描述了算法执行所需的时间量级,而空间复杂度描述了算法执行所需的额外存储空间的量级。
1.4.1下面是一些常见数据结构的时间复杂度和空间复杂度的例子:
-
数组(Array):
- 访问元素:O(1)
- 插入/删除元素(在末尾):O(1)
- 插入/删除元素(在中间或开头):O(n)
- 空间复杂度:O(n)
-
链表(Linked List):
- 访问元素:O(n)
- 插入/删除元素(在末尾):O(1)
- 插入/删除元素(在中间或开头):O(1)
- 空间复杂度:O(n)
-
栈(Stack):
- 压栈(push):O(1)
- 出栈(pop):O(1)
- 空间复杂度:O(n)
-
队列(Queue):
- 入队(enqueue):O(1)
- 出队(dequeue):O(1)
- 空间复杂度:O(n)
-
哈希表(Hash Table):
- 查找/插入/删除元素:平均情况下为O(1),最坏情况下为O(n)
- 空间复杂度:O(n)
-
二叉树(Binary Tree):
- 查找元素(在平衡二叉树中):O(log n)
- 插入/删除元素(在平衡二叉树中):O(log n)
- 空间复杂度:O(n)
这些是一些常见数据结构的时间复杂度和空间复杂度的示例,但并不代表所有情况。具体的时间和空间复杂度可能会受到实现细节、具体操作和算法优化等因素的影响。因此,在选择和使用数据结构时,理解其复杂度是非常重要的,以便在特定应用场景中做出正确的选择。
1.4.2以下是一些常见算法的时间和空间复杂度的示例:
-
线性搜索(Linear Search):
- 时间复杂度:O(n)
- 空间复杂度:O(1)
-
二分搜索(Binary Search):
- 时间复杂度:O(log n)
- 空间复杂度:O(1)
-
冒泡排序(Bubble Sort):
- 时间复杂度:O(n^2)
- 空间复杂度:O(1)
-
插入排序(Insertion Sort):
- 时间复杂度:O(n^2)
- 空间复杂度:O(1)
-
选择排序(Selection Sort):
- 时间复杂度:O(n^2)
- 空间复杂度:O(1)
-
快速排序(Quick Sort):
- 时间复杂度:
- 平均情况:O(n log n)
- 最坏情况:O(n^2)
- 空间复杂度:O(log n)
- 时间复杂度:
-
归并排序(Merge Sort):
- 时间复杂度:O(n log n)
- 空间复杂度:O(n)
-
堆排序(Heap Sort):
- 时间复杂度:O(n log n)
- 空间复杂度:O(1)
-
广度优先搜索(Breadth-First Search,BFS):
- 时间复杂度:O(V + E),其中 V 是顶点数,E 是边数
- 空间复杂度:O(V)
-
深度优先搜索(Depth-First Search,DFS):
- 时间复杂度:O(V + E),其中 V 是顶点数,E 是边数
- 空间复杂度:O(V)
这些时间和空间复杂度是基于平均情况的估计,具体的复杂度可能因实现方式、算法优化和输入数据的特性而有所不同。在实际应用中,需要根据具体情况选择适合的算法来平衡时间和空间的需求。
以下是一些常见算法的时间和空间复杂度的示例:
-
线性搜索(Linear Search):
- 时间复杂度:O(n)
- 空间复杂度:O(1)
-
二分搜索(Binary Search):
- 时间复杂度:O(log n)
- 空间复杂度:O(1)
-
冒泡排序(Bubble Sort):
- 时间复杂度:O(n^2)
- 空间复杂度:O(1)
-
插入排序(Insertion Sort):
- 时间复杂度:O(n^2)
- 空间复杂度:O(1)
-
选择排序(Selection Sort):
- 时间复杂度:O(n^2)
- 空间复杂度:O(1)
-
快速排序(Quick Sort):
- 时间复杂度:
- 平均情况:O(n log n)
- 最坏情况:O(n^2)
- 空间复杂度:O(log n)
- 时间复杂度:
-
归并排序(Merge Sort):
- 时间复杂度:O(n log n)
- 空间复杂度:O(n)
-
堆排序(Heap Sort):
- 时间复杂度:O(n log n)
- 空间复杂度:O(1)
-
广度优先搜索(Breadth-First Search,BFS):
- 时间复杂度:O(V + E),其中 V 是顶点数,E 是边数
- 空间复杂度:O(V)
-
深度优先搜索(Depth-First Search,DFS):
- 时间复杂度:O(V + E),其中 V 是顶点数,E 是边数
- 空间复杂度:O(V)
这些时间和空间复杂度是基于平均情况的估计,具体的复杂度可能因实现方式、算法优化和输入数据的特性而有所不同。在实际应用中,需要根据具体情况选择适合的算法来平衡时间和空间的需求。
1.4.3基本语法时间/空间复杂度
基本语法操作的时间和空间复杂度通常是固定的,不会随着输入数据的规模而变化。以下是一些基本语法操作的时间和空间复杂度:
-
赋值操作:
- 时间复杂度:O(1)
- 空间复杂度:O(1)
-
算术运算(加法、减法、乘法、除法):
- 时间复杂度:O(1)
- 空间复杂度:O(1)
-
逻辑运算(与、或、非):
- 时间复杂度:O(1)
- 空间复杂度:O(1)
-
条件语句(if-else语句):
- 时间复杂度:O(1)
- 空间复杂度:O(1)
-
循环语句(for循环、while循环):
- 时间复杂度:取决于循环的次数和循环体内部操作的复杂度
- 空间复杂度:O(1)
-
函数调用:
- 时间复杂度:取决于函数内部操作的复杂度
- 空间复杂度:取决于函数内部使用的变量和数据结构的空间复杂度
请注意,这些时间和空间复杂度是基于单个基本语法操作的估计。在实际编程中,还需要考虑到循环、递归、函数调用等多个基本操作的组合情况,并结合具体的算法和数据结构来评估整个程序的时间和空间复杂度。