# 没有书本,就把数据结构的记录mark在这个地方
2020/03/23
顺序存储和随机存储是两种物理存储结构。其并列的是索引存储和散列存储
👉线性表的顺序存储结构是一种随机存取 的存储结构,线性表的链式存储结构是一种() 的存储结构。
顺序存取,随机存取是指对于存储在物理存储结构种的数据的访问读写方式
顺序存取:数据只可以按照顺序来依次存取
随机存取:数据可以不需要按照顺序来随机存取
顺序线性表可以随机存取
链式线性表可以顺序存取
为了弥补上述两个表的缺陷,建立静态/动态链表(用顺序表实现链表)的方式 。
图自👉静态链表
备用表头一般在物理地址首位,每一次添加删除,都需要对表头的次下标做修改。
数据链表表尾的次下标(游标)是0,即备用表头
一个数据组需要,增删改查。静态链表整体还是类似链表,删时,不需要大动干戈。
删时,将数据表被删除项游标赋值给前一项游标,再回收空间
备用链表和数据链表的存储空间依旧受到初次分配的影响
静态链表在创建时已经申请分配了空间(有限),动态链表则在使用时才申请分配空间(无限)
Brute Force BF算法(所谓的暴力解法?)
KMF算法(跳过方法)
20200326
数组在内存中的存储方式👉图自数组的顺序存储及(C语言)实现
以列序为主:
以行序为主:
查找方式
如果二维数组采用以行序为主的方式,则在二维数组 a_nm 中查找 a_ij 存放位置的公式为:
LOC(i,j) = LOC(0,0) + (i*m + j) * L;
20200327
下转自👉矩阵乘法
十字链表 = 三元组链表 + 域表头数组
遍历获得的三元表是有序的(以先行后列为例)
一次循环中:
1)对于行插入非零数字,如果列序大于链内数据,则在最右append;如果小于,则在表头append
2)对于列插入非零数字,如果行序大于~~~
行逻辑链接的顺序表解决矩阵乘积算法
对矩阵的乘积进行深度剖析,矩阵 A 和矩阵 B 相乘的运算过程是这样的:
- 首先,找到矩阵 A 中第一行的非 0 元素,分别是 A11 = 3和 A14 = 5;(由于行逻辑链接的顺序表中存储的都是非 0 元素,查找的过程就需要使用记录每行第一个非 0 元素的首地址的数组来完成)
- 用 3 去和 B 中对应的第一行中的非 0 元素相乘,矩阵 B 中第一行非 0 元素是 B12 = 2,所以 3*2 = 6 ,因为 6 是 A11 和 B12 相乘的结果,所以暂时存放在 C12 中;用 5 去和 B 中对应的第 4 行的非 0 元素相乘,由于矩阵 B 中第 4 行没有非 0 元素,所以,第一行的计算结束;(相加)
- 以此类推。
无论如何使用三种存储形式做加法,三元表的行内列内顺序都是一致的(递增)。
使用十字链表来解决加法问题:
1)如果A中非零位置,B中为零,则A不变
2)如果A中非零元素,B中非零,且和为非零,直接在A中叠加(为零则删除)
3)如果A中零位置,B中为非零,则将B位置元素append入A
4)如果都为零,则不变
广义表
可以存储表的表 (数组只能存储不可再分的数据类型)
原子和子表
通常,广义表中存储的单个元素称为 "原子",而存储的广义表称为 "子表"。
例如创建一个广义表 LS = {1,{1,2,3}},我们可以这样解释此广义表的构成:广义表 LS 存储了一个原子 1 和子表 {1,2,3}。
以下是广义表存储数据的一些常用形式:
- A = ():A 表示一个广义表,只不过表是空的。
- B = (e):广义表 B 中只有一个原子 e。
- C = (a,(b,c,d)) :广义表 C 中有两个元素,原子 a 和子表 (b,c,d)。
- D = (A,B,C):广义表 D 中存有 3 个子表,分别是A、B和C。这种表示方式等同于 D = ((),(e),(b,c,d)) 。
- E = (a,E):广义表 E 中有两个元素,原子 a 和它本身。这是一个递归广义表,等同于:E = (a,(a,(a,…)))。
注意,A = () 和 A = (()) 是不一样的。前者是空表,而后者是包含一个子表的广义表,只不过这个子表是空表。
union关键字,定义union下面的成员变量共享一块内存,每一个成员在任一时刻有且只有一个成员使用此块内存。
NOTE:节点必须被表节点引领
typedef struct GLNode{
int tag;//标志域
union{
char atom;//原子结点的值域
struct{
struct GLNode * hp,*tp;
}ptr;//子表结点的指针域,hp指向该子表的表头;tp指向该子表的表尾
};
}*Glist;
NOTE:表节点相当于{ }
typedef struct GLNode{
int tag;//标志域
union{
int atom;//原子结点的值域
struct GLNode *hp;//子表结点的指针域,hp指向表头
};
struct GLNode * tp;//这里的tp相当于链表的next指针,用于指向下一个数据元素
}*Glist;
20200330
所谓队列,就是有从队头弹出,队尾压入的。
起初队尾和队头重合,弹出后队头向后移动,压入前队尾向前移动。
无论是什么结构的队列,当队头和队尾重合的时候,则队列要么已满无法写入,要么就不存在元素了。
链式队列有一个专用的空队头,所以弹出不用移动指针。
广义表长度,第一层所含的元素
广义表深度,相当于不确定分叉的n叉树深度
停止条件:(每次只记录最大值)
当为原子时返回0,再前一次中+1
当为空表时返回1
for 把每个表中元素遍历一遍
int GlistDepth(Glist C){
//如果表C为空表时,直接返回长度1;
if (!C) {
return 1;
}
//如果表C为原子时,直接返回0;
if (C->tag==0) {
return 0;
}
int max=0;//设置表C的初始长度为0;
for (Glist pp=C; pp; pp=pp->ptr.tp) {
int dep=GlistDepth(pp->ptr.hp);
if (dep>max) {
max=dep;//每次找到表中遍历到深度最大的表,并用max记录
}
}
//程序运行至此处,表明广义表不是空表,由于原子返回的是0,而实际长度是1,所以,此处要+1;
return max+1;
}
表头!指的是表的第一个元素。
表尾!指的时表的第一个元素之后的组成的表。