数据结构知识梳理
引言:针对的群体1.期末备考的学生2.想对数据结构建立知识体系的人
数据结构个人一共分为5类:线性表(一对一)、树(一对多)、图(多对多)、查找、排序,对于学会数据结构的话,应该还要再加一个数据结构基本概念
接下来就围绕这几个部分来整理:
一、数据结构基本概念
- 数据 :是所有能输入到计算机中并能被计算机程序识别和处理的符号集合
- 数据元素:是数据的基本单位
- 数据项 :构成数据元素的最小单位
- 数据结构 :相互之间存在一定关系的数据元素的集合
- 逻辑元素 : 数据元素以及数据元素之间的逻辑关系
&ps:这里只要记住2.3即可。
- 什么是好算法?
答:5个特性,正确性, 健壮性, 可理解性, 抽象分级, 高效性
二、线性表(顺序表、链表、栈、队列、字符串)
1. 顺序表
(1)逻辑关系:由存储位置决定
(2)存储结构 :
#define MaxSize 100
typedef int DataType;
typedef struct{
DataType data[MaxSize];
int length;
}SeqList;
//存储结构:一个数组 + 存储长度的变量
(3) 时间复杂度 :
①O(1)
答:判空、求长、按位查找
②O(n)
答:遍历、按值查找、删除、插入
- 插入
- 删除
2.单链表
(1)逻辑关系:由指针决定
(2)存储结构 :
typedef int DataType;
typedef struct{
DataType data;
struct Node* next;
}Node;
//存储结构:一个数据 + 一个指针
(3) 时间复杂度 :
①O(1)
答:判空、求长、头删、头插
②O(n)
答:遍历、按位查找、按值查找、尾删除、尾插
- 头插
void push_front(List *list,ElemType x) //头插法
{
Node *s=(Node*)malloc(sizeof(Node));
s->date=x;
s->next=NULL;
s->next = list->fist->next;
list->fist->next = s;
if(list->size == 0)
list->last = s;
list->size++;
}
- 头删
void pop_front(List *list) //头删法
{
if(list->size ==0)
{
printf("链表已经为零,输入错误");
return;
}
Node *p=list->fist->next;
list->fist->next = p->next;
free(p);
if(list->size == 1)
{
list->last = list->fist;
}
list->size--;
}
- 尾插
void push_back(List *list,ElemType x) //尾插法
{
Node *s=(Node*)malloc(sizeof(Node));
s->date=x;
s->next=NULL;
list->last->next = s;
list->last=s;
list->size++;
}
- 尾删
void pop_back(List *list) //尾删法
{
if(list->size == 0)
{
printf("链表已经为空,不能删除\n");
return;
}
Node *p=list->fist->next;
while(p->next != list->last)
{
p=p->next;
}
free(list->last);
list->last=p;
list->last->next=NULL;
list->size--;
}
3.循环双链表
(1)插入操作:
在节点p的后面插入一个新节点s,需要修改4个指针:
s->prior = p;
s->next = p->next;
p->next->prior = s;
p->next = s;
(2)删除操作:
设节点p指向待删节点,删除操作可通过下述两条语句完成:
p->prior->next = p->next;
p->next->prior = p->prior;
4.栈==(操作受限的线性表)==
(1)定义:先进后出
(2)分类:顺序栈、链栈(与线性表一样)
5.队列==(操作受限的线性表)==
(1)定义:先进先出
(2)分类:顺序栈、链栈(与线性表一样)
6.字符串==(操作受限的线性表)==
(1)定义:字符组成的有限集合——用数组实现
(2)分类:顺序栈、链栈(与线性表一样)
&ps:普通高校,KMP考的少,这里不多赘述。抓住next数组的实现也就成功了一半了,有需要的可自查。
7.数组(承接字符串)
(1)数组的存储结构:①以行序为主序
②以列序为主序
(2)数组的寻址:行序(列序同理)
&ps:小学问题:[1,7)之间有几个数?
答案:7-1 = 6
(3)矩阵的压缩存储:①对称矩阵的压缩存储
数组的寻址:行序(列序同理)k = i * (i - l) / 2 + j - 1(等差数列求和公式,公差为1)
②三角矩阵的压缩存储(同对称矩阵)
(4)稀疏矩阵的压缩存储:①三元组顺序表
②十字链表
三、树和二叉树
树
1.专业术语(重点)
- 节点的度:某节点所拥有子树的个数
- 叶子节点:度为0的节点
- 路径长度:路径上经过的边数
2.存储结构
(1)双亲表示法
字面意思:指向该节点的双亲
(2)孩子表示法
字面意思:指向该节点的孩子
(3)孩子兄弟表示法(又称二叉链表表示法)
字面意思:该节点设置两个指针,一个指向其兄弟,一个指向其孩子
这里树与二叉树的转化就是利用孩子兄弟表示法的——给定一颗树,可以找到唯一的一颗二叉树与之对应
3.树的遍历
(1)前序遍历
(2)中序遍历
(3)后序遍历
(4)层序遍历
二叉树==(重点)==
(1)二叉树的特点
答:每个节点最多有两棵子树,所以二叉树不存在大于度为2的节点
(2)特殊二叉树
-
满二叉树
特点
- 叶子只能出现在最下一层
- 只有度为0和度为2的节点
-
完全二叉树
特点
- 深度为k的完全二叉树在k-1层是满二叉树
- 叶子节点只能出现在最下两层,且最下层的叶子节点都集中在左侧连续的位置
- 如果有度为1的节点,只可能有一个,且该节点只有左孩子
(3)二叉树的基本性质
- 在一颗二叉树中,如果叶子节点的个数为n0, 度为2的节点个数为n2,则 n0 = n2 + 1
&ps:也就是叶子节点,永远比有儿女的节点多一个
- 二叉树的第i层上最多有==2^(i-1)==个节点
- 在一颗深度为k的节点中最多有2^k - 1个节点
- 对一颗具有n个节点的完全二叉树从1开始编号,则对于编号为i(1 <= i <= n)的节点,
- 如果i > 1,则节点i的双亲的编号为i/2(向下取整);否则节点i是根节点,无双亲
- 如果2i <= n,则节点i的左孩子的编号为2i;否则无左孩子
- 如果2i + 1<= n,则节点i的左孩子的编号为2i + 1;否则无左孩子
(4)二叉树的遍历(同树的遍历)
&ps;常考题型:①给你前序序列,和中序序列,让你还原二叉树
②给你中序序列,和中序序列,让你还原二叉树
(5)最优二叉树(哈夫曼算法)
①建树过程
- 初始化:把所有节点准备好
- 选取与合并:选取两个最小的节点,合并后放入树中
- 重复
②哈夫曼树的作用
答:把使用频率高的字符用尽可能短的编码,把使用频率低的字符用稍长长的编码,这样可以获得更好的空间效率
应用:文件的压缩
四、图
(1)分类
- 有向图
- 无向图
- 强连通:在无向图中,任意顶点之间都有路径
(2)图的遍历操作
- 深度优先遍历(类似树的前序遍历)
- 广度优先遍历(类似树的层序遍历)
(3)图的存储结构的实现
①邻接矩阵
#define MaxSize 100
typedef char DataType;
typedef struct{
DataType vertex[MaxSize];
int edge[MaxSize][MaxSzie];//存放边的二维数组
int vertexNum,edgeNum;//图的顶点数和边数
}MGraph;
1为有边,0为无边
②邻接表
#define MaxSize 100
typedef char DataType;
typedef stuct{
int adjivex;
struct EdgeNode* next;
}EdgeNode;
typedef struct{
DataType vertex;
Edge* first;
}VertexNode;
typedef struct{
VertexNode adjlist[MaxSize];
int vertexNum,edgeNum;
}ALGraph;
(4)最小生成树
定义:在图的所有生成树中,代价最小的生成树称为最小生成树
- Prim算法
假设有V0 ~ V5,5个节点,从V0开始,选取与V0邻接最小的边。然后再在这两个已选的节点中,选择与他们邻接的边。然后重复
- Kruskal算法
在所有的节点中,每次选取权值最小的边
(5)最短路径
- Dijkstra算法
类似Prim算法,不过这个不回头,只在最后一个节点上找。
五、查找
(1)顺序查找(线性查找)
时间复杂度:O(n)
(2)折半查找(在排序好的基础上查找)
时间复杂度:(log n)
(3)哈希表(散列表)
①设计方法
- 直接定址法——H(key) = a X key + b(a,b为常数)
- 除留余数法——H(key) = key mod P
- 平方取中法——平方取中间两位
②处理冲突的方法
- 开放地址法
- 线性探测——遇到位置被占往后加一
- 二次探测——遇到位置被占往后加i2,第一次被占往后加一,第二次往后加22 == 4,
- 拉链法(链地址法)
六、排序
(1)插入排序
- 直接排序
时间复杂度:O(n^2)
- 希尔排序
时间复杂度: O(nlog n) ~O(n^2)
(2)交换排序
- 冒泡排序
时间复杂度: O(n^2)
- 快速排序
时间复杂度: O(nlog n)
辅助空间:O(log n) ~O(n)
(4)选择排序
- 简单选择排序
时间复杂度: O(n^2)
- 堆排序
时间复杂度: O(nlog n)
(5)归并排序
- 二路归并排序
时间复杂度: O(nlog n)
辅助空间:O(n^2)