数据结构的基本概念
- 数据:能够输入到计算机的描述客观事物的符号
- 数据项:描述事物的其中一项指标
- 数据元素:用于描述一个完整的事物。
- 数据结构:由数据元素和元素之间的关系构成一个整体
- 算法:数据结构所具备的功能(解决问题的方法)。
四种基本类型的数据结构
-
集合:元素之间没有任何关系
-
线性表:元素之间存在一对一关系
数组、链表、功能受限的表(栈、队列)。 1、数组:在内存中连续存储多个元素的结构,在内存中的分配也是连续的。 优点:1、按照索引查询元素速度快 2、按照索引遍历数组方便 缺点:1、数组的大小固定后就无法扩容了 2、数组只能存储一种类型的数据 3、添加,删除的操作慢,因为要移动其他的元素。 2、链表:物理存储单元上非连续的、非顺序的存储结构,数据元素的逻辑顺序是通过链表的指针地址实现。 优点:对内存要求低,添加删除方便 缺点:查找速度慢,要遍历链表,容易产生内存碎片 3、栈:仅在线性表的一端进行操作,后进先出的数据结构。 常用于实现递归。 4、队列:在线性表的一端添加元素,另一端取出元素,先进先出。
数据结构的存储方式
顺序存储:在一块连续的内存空间存储元素与元素之间的关系。
优点是随机访问时速度快,不易产生内存碎片。
缺点时对内存要求高,添加和删除不方便
非顺式(链式):元素随机存储内存空间中,元素中存储指向其他元素的地址。
优点是对内存要求低,添加删除方便
缺点是查找速度慢,不能随机访问,容易产生内存碎片
功能受限的表
栈:仅在线性表的一端进出元素,后进先出的数据结构。
顺序栈(容量在限)、链式栈(可以无限容量)。
一般常用于,表达式解析,内存管理(函数的调用提供支持)。
队列:在线性表的一端添加元素,另一端取出元素,先进先出。
顺序队列、链式队列。
通用链表
void* 万能指针,可以与任意类型的指针呼唤。
int* = void*
void* = int*
需要把链表的数据域换成void*类型。
注意:由于存储类型的不确定,因此类型的运算规则不确定,当需要使用到关系运算运算时,需要链表的使用者提供运算(提供一个函数供链表调用),这种模式叫回调。
void*不能直接解引用,需要先转换成其他有效类型。
树
概念
元素之间存储一对多的数据结构,常用于表现族谱关系、组织关系等,也可以借助特殊的树型结构实现查找、排序等算法,一般使用倒悬树的方式表示
树的相关术语
1、根结点:树的最上层元素,有且只能有一个。
2、子结点:该结点的对应下一层元素。
3、父结点 :该结点的对应上一层元素。
4、叶子结点:没有子结点的元素,一般处于树的最底层。
5、兄弟结点:具有同一个父结点的元素,处于同一层。
6、高度:指的是树的层数。
7、密度:指的是树的结点数(包括根结点)。
8、度:指的是结点的子结点的数量。
普通树
普通树的子结点的数量没有限制
顺序存储:
1、每个结点一行
下标 数据 父结点下标
0 R -1
2、兄弟结点连续存储
下标 数据 父结点下标 第一个子结点下标
0 R -1 1
3、兄弟结点连续存储
下标 数据 父结点下标 第一个子结点 最后一个子结点
0 R -1 1 3
链式序存储
typedef struct Node
{
TYPE data;
struct Node* brother;
struct Node* child;
}Node;
二叉树
- 二叉树的子结点的数量至多为2个。
- 遍历:
1、前序遍历:根,左,右
2、中序遍历:左,根,右
3、后序遍历:左,右,根
4、层序遍历:从上到下,先左后右 - 普通二叉树:对二叉树的结点没有位置及数量上的要求。
- 满二叉树:树的每一层的结点数量 pow(2,层数-1)
- 完全二叉树:除了最后一层,其他每一层的结点数量都是pow(2,层数-1),最后层的结点按照从左往右的顺序存储。
- 有序二叉树:所有的左子结点都小于根结点,所有右子结点都大于根结点。
- 平衡二叉树:首先是有序的二叉树,树的左右子树的高度相差不超过1,并且子树的子树都满足这个要求。