数据结构回顾学习笔记
- 这次数据结构回顾笔记,是我对数据结构回顾学习的笔记。回顾过程是参考易百教程网站上数据结构教程进行的,觉得浅显易懂很有帮助,因此参考对之前的知识进行了回顾。在此进行统一的引用说明。如有侵权,请联系,会及时删除。
全部笔记本来想一次上传的,但是貌似内容过多,一次上传不了,故分几个部分上传。
1. 基本术语
- 数据:数据可以定义为基本值或值集合
- 组项:具有从属数据项的数据项称为组项
- 记录:记录可以定义为各种数据项的集合
- 文件:文件是一种类型实体的各种记录的集合
- 属性和实体:实体表示某些对象的类。它包含各种属性。每个属性表示该实体的特定属性
- 字段:字段是表示实体属性的单个基本信息单元
2. 数据结构的优点
- 效率:程序的效率取决于数据结构的选择。合适的数据结构可以提高程序的效率
- 可重用性:数据结构是可重用的,即当实现了特定的数据结构,就可以在其他地方使用它。也将数据结构的实现编译到不同客户端使用的程序库中。
- 抽象:数据结构由ADT指定,它提供抽象级别。客户端程序仅通过接口使用数据结构,而不涉及实现细节。
3. 数据结构的分类
1). 线性数据结构
线性数据结构,是指数据结构的所有元素按照线性顺序的排列方式,元素以非分层方式存储,除了第一个和最后一个元素,它的每个元素具有后继元素和前导元素。
线性数据结构有以下类型:
- 数组:数组是类似数据项的集合,每个数据项称为数组的元素。 元素的数据类型可以是任何有效的数据类型,如char,int,float或double。数组的元素共享相同的变量名,但每个元素都带有一个不同的索引号,这些索引号也称为下标。 数组可以是一维的,二维的或多维的
- 链表:链表是一种线性数据结构,用于维护内存中的列表。它可以存储在非连续内存位置的节点集合中。链表中的每个节点都包括指向相邻节点的指针
- 队列:队列是一个线性列表,它的元素只能从一端插入,这段可以叫做后端,而只能在另外一段出队(或者称为删除),这一端可以称为前端
2). 非线性数据结构
非线性数据结构不形成序列,也就是说每个项目或者元素以非线性排列的方式与两个或者更多的其他项目连接。数据元素不按照顺序结构排列
非线性数据结构的类型如下:
-
树:树是多级的数据结构,其元素之间具有层次关系,树的元素也称为节点。层次中最底层的节点称为叶节点,而最顶层节点称为根节点。 每个节点都包含指向相邻节点的指针。
树数据结构基于节点之间的父子关系。 除了叶节点之外,树中的每个节点可以具有多个子节点,而除了根节点之外,每个节点可以具有最多一个父节点。 树可以分为许多类别。 - 图:图可以定义为由被称为边缘的链接连接的元素集(可以用顶点表示)的图表示。图不同于树,图可以有循环而树不能有循环
4. 数据结构的基本操作
- 遍历:每个数据结构都包含一组数据元素。遍历数据结构表示要访问到数据结构的每一个元素,以便执行某些特定的操作,比如搜索或排序。
- 插入:插入时在任何位置将元素添加到数据结构的过程。如果数据结构的大小是n,那么只能在n-1个数据元素之间插入新的元素
- 删除:从数据结构中删除元素的过程称为删除。可以在任意随机位置数据结构中删除元素。如果要从空的数据结构中删除删除元素,则会发生下溢
- 搜索:在数据结构中查找元素的位置的过程称为搜索。
- 排序:按照特定的顺序排列数据结构的过程称之为排序。有许多算法可以用于执行排序,比如冒泡排序,选择排序等待
- 合并:当两个列表分别为大小M和N的列表A和列表B时,相似类型的元素,连接产生第三个列表,列表C的大小(M+N),这个过程称为合并
5. 数据结构算法
算法是用于解决特定问题的明确定义的步骤的过程,算法是有限的逻辑或者指令集,他是为了完成某个预定义任务而编写的。算法并不是完整的程序或者代码,知识问题的解决方案(逻辑),可以使用流程图或者伪代码等表示。
对于数据结构,主要的算法类别有:
- 排序: 为按特定顺序排序项目而开发的算法
- 搜索:为搜索数据结构内的数据项而开发的算法
- 删除:为从数据结构中删除现有元素而开发的算法
- 插入:为在数据结构中插入项目而开发的算法、
- 更新:为更新数据结构中的现有元素而开发的算法
判断算法的优劣性,以及性能衡量标准是:
- 时间复杂度:表示程序运行到完成所需时间的一种方式
- 空间复杂度:算法在执行过程中所需的内存空间量。 在有限的内存可用和多用户系统的情况下,需要空间复杂性
每个算法的必要元素有:
- 规范:计算过程的描述
- 前提条件:输入条件
- 算法的主体:一系列清晰明确的指令
- 后置条件:输出条件
算法的特征:
-
输入:算法必须具有
0
个或明确定义的输入 -
输出:算法必须具有
1
个或明确定义的输出,并且应与所需的输出匹配 - 可行性:必须在有限步数后终止算法
- 独立性:算法必须具有独立于任何编程代码的逐步指导
- 明确无误(确定性):算法必须明确无误。每个步骤和输入/输出必须清晰,并且只能产生一个含义
6. 算法的性能分析
一般对算法的所需时间评价有三种类型:
- 最坏情况 :定义了算法占用大量时间的输入
- 平均情况:程序执行需要平均时间
- 最佳情况:定义算法占用最少时间的输入
1). 渐进符号
-
大欧符号(
Ο
)表达算法运行时间上线的正式方法,它测量时间复杂度的最坏情况或最长时间,算法完成其操作所需的时间。
-
欧米茄符号(
Ω
)表示算法运行时间下限的正式方法。它衡量算法可能完成的最佳时间量或者最佳的案例时间复杂度。如果要求算法在不使用上限的情况下花费至少一定的时间,使用大
Ω
表示法。它用于限制输入大小的运行时间的增长。如果运行时间是
Ω(f(n))
,则对于较大的n
值,对于常数(k)
,运行时间至少为k * f(n)
-
西塔符号(
θ
)表示算法运行时间的上限和下限的正式方式
考虑算法的运行时间是
θ(n)
,如果一次(n)
变得足够大,则对于某些常数k1
和k2
,运行时间最多为k2-n
并且至少为k1≤n
。 它表示如下
7. 指针
指针用于指向存储在计算机内存中任何位置的值的地址。获取存储在该位置的值称为解除引用指针。指针提高了重复过程的性能。
指针有四个运算符号:
++
,--
,+
,-
指针数组:可以定义数组以容纳多个指针
指针的指针:C/C++允许指针的指针
将指针传递给C语言的函数:通过引用或者地址传递参数使得被调用函数可以在调用函数中更改传递的参数
从C语言函数返回指针:允许函数返回指向局部变量,静态变量和动态分配内存的指针
int a = 10;
int *b= &a;
printf("%d",a);//打印10,因为a的值是10
printf("%d",&a);//打印2000,因为a的所在地址是2000
printf("%d",&b);//打印3000,因为b的地址是3000
printf("%d",*b);//打印2000,因为存储的是a的地址2000
- 指针的说明程序
#include <stdio.h> int main(){ int a = 5; int *b; b = &a; printf("value of a = %d\n", a); printf("value of a = %d\n", *(&a)); printf("value of a = %d\n", *b); printf("address of a = %u\n", &a); printf("address of a = %d\n", b); printf("address of b = %u\n", &b); printf("value of b = address of a = %u\n", b); system("pause"); return 0; }
- 指针的指针说明程序
#include <stdio.h> int main(){ int a = 5; int *b; int **c; b = &a; c = &b; printf("value of a = %d\n", a); printf("value of a = %d\n", *(&a)); printf("value of a = %d\n", *b); printf("value of a = %d\n", **c); printf("value of b = address of a = %u\n", b); printf("value of c = address of b = %u\n", c); printf("address of a = %u\n", &a); printf("address of a = %u\n", b); printf("address of a = %u\n", *c); printf("address of b = %u\n", &b); printf("address of b = %u\n", c); printf("address of c = %u\n", &c); system("pause"); return 0; }
8. 结构体
结构是一种复合数据类型,它定义了一组变量列表,这些变量将放在一个内存块中的一个名称下。 它允许通过使用指向结构的一个指针来访问不同的变量。结构体的定义大致如下:
struct structure_name
{
data_type member1;
data_type member2;
...
...
data_type memeber;
};
结构体的优点:
- 可以保存不同数据类型的变量
- 可以创建包含不同类型属性的对象
- 允许跨程序重用数据布局
- 用于实现其他数据结构,如链表,堆栈,队列,树,图等。
#include<stdio.h>
#include<conio.h>
void main()
{
struct employee
{
int id ;
float salary ;
int mobile ;
};// 定义结构体变量
struct employee e1,e2,e3 ;
clrscr();
printf ("\nEnter ids, salary & mobile no. of 3 employee\n");
scanf ("%d %f %d", &e1.id, &e1.salary, &e1.mobile);
scanf ("%d%f %d", &e2.id, &e2.salary, &e2.mobile);
scanf ("%d %f %d", &e3.id, &e3.salary, &e3.mobile);
printf ("\n Entered Result ");
printf ("\n%d %f %d", e1.id, e1.salary, e1.mobile);
printf ("\n%d%f %d", e2.id, e2.salary, e2.mobile);
printf ("\n%d %f %d", e3.id, e3.salary, e3.mobile);
getch();
}