个人在学习数据结构时所记录的一些笔记,如有错误欢迎指正,谢谢!
笔记记录主要参考B站中的青岛大学-王卓老师的视频。
链接:数据结构与算法基础(青岛大学-王卓)_哔哩哔哩_bilibili
结构:数据元素相互之间的关系称为结构(数据元素不是孤立存在的,它们之间存在着某种关系)
数据结构:相互之间存在一种或者多种特定关系的数据元素集合。(逻辑结构+物理结构+运算和实现)
逻辑结构划分方法:
- 线性结构和非线性结构
- 集合、线性、树形、图状
- 集合结构:数据元素之间除了同属于一个集合的关系外,无任何其他关系
- 线性结构:一对一
- 树形结构:一对多
- 图状结构:多对多
存储结构:顺序、链式、索引、散列
数据类型(DT):是一组性质相同的值的集合以及定义于这个值集合上的一组操作的总称
抽象数据类型(ADT):是指一个数字模型以及定义在此数学模型上的一组操作 (对象+关系+操作)
算法的定义:对特定问题求解方法和步骤的一种描述,它是指令的有限序列。其中每个指令表示一个或多个操作
算法特性:有穷性、确定性、可行性、有零个或多个输入、有一个或多个输出
算法设计的要求:正确性、可读性、健壮性(鲁棒性)、高效性
同一线性表中的元素必定具有相同特性,数据元素间的关系是线性关系
顺序存储定义:把逻辑上相邻的数据元素存储在物理上相邻的存储单元中的存储结构
顺序表位置计算:LOC(ai) = LOC(a1)+(i-1)*l
顺序表的优缺点:
优点:
存储密度大(节点本身所占存储/节点结构孙占存储量)
可以随机存取表中任一元素
缺点:
在插入、删除时,需要移动大量元素
浪费存储空间
属于静态存储形式,数据元素的个数不能自由扩充
链表的优缺点:
优点:
节点空间可以动态申请和释放
插入和删除时不需要移动数据元素
缺点:
存储密度小,但每个结点的指针域需要额外的存储空间
非随机存取结构
头指针:存储第一个节点的地址信息,是指向链表中第一个节点的指针,若链表存在头结点,则头指针指向头结点
头结点:在链表第一个节点之前附加的一个节点
设置头结点的好处:
- 便于对第一个节点的处理
- 便于空表和非空表的统一处理
链表的特点:
- 节点在存储器中的位置是任意的,即逻辑上相邻的数据元素在物理上不一定相邻
- 访问时只能通过头指针进入链表依次访问,为顺序存取
头插法:
- 从一个空表开始,重复读入数据 L=(LinkList)malloc(sizeof(LNode); L->next = null
- 生成新节点,将读入数据存放到新节点的数据域中 p -> data = a
- 从最后一个节点开始,依次将各节点插入到链表的前端 p -> next = L ->next
尾插法:
- 从一个空表L开始,将新结点逐个插入到链表的尾部,尾指针r指向链表的尾结点
- 初始时,r与L均指向头结点,将新节点插入到尾结点后,r指向新节点
r = L;
p->date = a;
p->next= NULL;
r->next = p;
r = p;
双向链表的添加
s->prior = p->prior;
p->prior->next = s;
s->next = p;
p->prior = s;
双向链表的删除
p->prior->next = p->next;
p->next->prior = p->prior;
栈和队列是限定插入和删除只能在表的“端点”进行的线性表
栈:后进先出(LIFO),仅操作栈顶
队列:先进先出(FIFO),插入操作队头,删除操作在队尾
栈空:base == top 栈满:top - base = stacksize
队空:front = rear = 0 循环队满:(rear + 1)% MAXQSIZE = front
队列的长度:(rear - front + MAXQSIZE)% MAXQSIZE
串:仅由字符组成的特殊线性表
广义表:
求表头GetHead(L):非空广义表的第一个元素,可以是一个元素也可以是一个字表
求表尾GetTail(L):非空广义表出去表头元素以外其它元素所构成的表。表尾一定是一个表
例: D=(E,F)=((a,(b,c)),F)
GetHead(D)= E GetTail(D)= (F)
GetHead(E)= a GetTail(D)= ((b,c))
GetHead(((b,c)))= (b,c) GetTail(D)= ()
GetHead((b,c))= b GetTail(D)= (c)
GetHead((c))= (c) GetTail(D)= ()
数据的逻辑结构:
线性结构:线性表、栈、队列、字符串、数组、广义表
非线性结构:树形结构、图形结构
树:
节点:数据元素以及指向子树的分支
根节点:非空树种无前驱结点的结点
结点的度:结点拥有的子树数
树的度:树内各结点的度的最大值
树的深度:树中结点的最大层次(根为第一层)
叶子结点:度为0的结点
有序树:书中结点的各子树从左至右有序
二叉树的特点:
二叉树中不存在度大于2的结点
子树有左右之分,次序不可颠倒
二叉树可以是空集合,根可以有空的左子树或空的右子树
二叉树不是树!!!(树不分左右,但二叉树一定分为左还是右)
二叉树的性质:
二叉树的第i层上最多有2^(i-1)个结点(i>=1)
深度为k的二叉树最多有2^k - 1个结点(k>=1) ==> 满二叉树
对任意一颗二叉树T,叶子树为n0,度为2的节点数为n2,则n0 = n2 + 1
完全二叉树的性质: ==> 路径最短的二叉树
具有n个结点的完全二叉树的深度为log2n + 1(向下取整)
对于一个结点 i(i !=1),其双亲结点为 i/2(向下取整),左孩子为 2i,右孩子为2i+1
先序遍历(根左右) 中序遍历(左根右) 后序遍历(左右根)
由先序和中序 或 后序和中序可以确定唯一一颗二叉树
树的中序遍历访问次序为先左再右最后再根,类似于二叉树的后序遍历
哈夫曼树(最优二叉树):带权路径长度(WPL)最短的(二叉)树,哈夫曼树中仅有度为0和2的结点,不存在度为1的结点,哈夫曼树中共有2n-1个结点
构造哈夫曼树:
- 首先将所有单结点作为根
- 然后选择两个最小的结点作为树,删除这两个结点并将组成的结点和放回
- 重复至仅剩一个结点
图:G=(V,E) V:顶点(数据元素)的有穷非空集合 E:边的有穷集合
无向图:每条边都是无方向的 有向图:每条边都是有方向的
完全图:任意两个点都有一条边相连 无向:n(n-1)/2 有向:n(n-1)
邻接表的特点
方便找任一丁点的所有“邻接点”
节约稀疏图的空间(需要N个头指针+2E个结点)
对于无向图,方便计算任一顶点的度;对于有向图,只能计算出度
不方便检查任意一对顶点间是否存在边
邻接矩阵与邻接表表示法的关系
对于任一确定的无向图,邻接矩阵是惟一的,单邻接表不唯一
邻接矩阵的空间复杂度为O(n^2),而邻接表的空间复杂度为O(n+e)
邻接矩阵多用于稠密图,而邻接表多用于稀疏图