文章目录
说明
本博客用于记录本人的学习历程,本人水平有限,如有错误,欢迎在评论区指出。
本博客中的代码均由C++实现。
如果你觉得看完这篇文章有收获,就动动小手点个赞吧!
一、字符串
1.1 字符串的逻辑结构
字符串定义
字符串是由n(n>=0)个字符组成的一个有限序列,当n=0是被称为空串。
string str = "abcdefg";
其中,双引号引起来的内容就是串值,其长度即为字符串的长度。
注:空格也可以是字符串的元素。
字符串之间的大小关系由字符编码之间的大小关系决定。
子串定义
由字符串任意个连续字符组成的子序列被成为 子串,包含子串的字符串就被称为 主串。子串第一个元素在主串的位置被成为子串在主串的位置。
1.2 字符串的存储结构
字符串一般用顺序结构储存,即用数组储存。一般有三种方式储存字符串的长度
- 在数组的最后一个存储位置储存
- 在数组的0号空间储存,即串值从下标为1开始
- 在串尾储存一个特殊字符来作为结尾
1.3 模式匹配
给定两个字符串 s和t ,在主串s中寻找子串t的过程被称为 模式匹配 ,若匹配成功返回子串在主串的位置,否则返回-1
1.3.1 BF算法
BF算法的思想比较简单,就是蛮力匹配,时间复杂度较高。
伪代码描述
算法:BF(S,T)
输入:主串S,子串T
输出:子串在主串中的位置
1.在串s和串t中设置起始下标分别为i=0,j=0
2.重复以下操作,直到S或T的所有字符比较完毕
2.1若S[i]等于T[i],继续比较下一对字符,即i++,j++
2.2若S[i]不等于T[i],i要回溯到此趟比较开始的位置的下一位,j回到T串的起始位置,准备开始下一趟比较
3.如果T中的字符全部比较完毕,则匹配成功,否则匹配失败
C++代码实现:
int BF(char S[],char T[])
{
int start=0;
int i=0,j=0;
while(S[i]!='\0'&&T[i]!='\0')
{
if(S[i]==T[i])
{
i++;
j++;
}
else
{
start++;
i=start;
j=0;
}
}
if(T[i]=='\0')return start+1;
rerturn 0;
}
1.3.2 KMP算法
KMP算法的效率要比BF算法高很多,改进的地方是不进行回溯。
二、多维数组
2.1 数组的逻辑结构
数组是由类型相同的数据元素构成的有序集合,每个数据元素称为一个数组元素,每个元素受n(n>=1)个线性关系的约束。一维数组可以看做一个线性表,二维数组可以看作元素是线性表的线性表。
2.2 数组的储存结构和寻址
由于内存是一维结构,而多维数组是多维结构,所以需要将多维结构映射到一维结构。主要有两种方式,行优先,列优先。
按行优先
基本思想是先储存行号较小的元素,如果行号相同就先储存列号较小的元素
寻址公式:
LOC(i,j) = LOC(0,0) + (n * i+j) * L
按列优先
基本思想是先储存列号较小的元素,如果列号相同就先储存行号较小的元素
寻址公式:
LOC(i,j) = LOC(0,0) + (m * j+i) * L
三、矩阵压缩储存
3.1 特殊矩阵
3.1.1 对称矩阵
对称矩阵关于主对角线对称,因此只需要储存下三角部分(包括对角线)。原来需要nn的空间,现在只需要n(n+1)/2个存储空间。
3.1.2 三角矩阵
上三角矩阵压缩:
对于元素处于上三角区域,即元素aij,其中i≤j,元素 aij,在第i行中是第 (j−i+1)个元素,规定:每个元素所占的长度为 e,可得
对于元素处于下三角区域,即元素 aij,其中 i>j,因为下三角区的元素值都一样(如果元素的值有效),则把它放到存储区的最后一个单元:
下三角矩阵压缩
对于元素处于下三角区域,即元素aij,其中i≥j,元素 aij在第 i行为第j个元素,现规定每个元素占用的单位为 e,可得:
,对于上三角区的元素将其放到存储区的最后一个单元,可得地址公式:
和上三角存储的一样。
3.1.3 对角矩阵
对角矩阵的压缩方法是将对角矩阵的非零元素按行储存到一维数组中,
元素aij在一维数组中的序号为 前i-1行元素个数+第i行元素的个数,即2i+j-2
,因为一维数组的元素下标是从0开始的,所以地址为2i+j-3
3.2 稀疏矩阵
定义
对于那些零元素数目远远多于非零元素数目,并且非零元素的分布没有规律的矩阵称为稀疏矩阵。人们无法给出稀疏矩阵的确切定义,一般都只是凭个人的直觉来理解这个概念,即矩阵中非零元素的个数远远小于矩阵元素的总数,并且非零元素没有分布规律。
压缩存储
稀疏矩阵中非零元素较少,零元素较多,因此可以采用只存储非零元素的方法来进行压缩存储。
但是非零元素分布没有任何规律,所以在进行压缩存储的时侯需要存储非零元素值的同时还要存储非零元素在矩阵中的位置,即非零元素所在的行号和列号,也就是在存储某个元素比如aij的值的同时,还需要存储该元素所在的行号i和它的列号j,这样就构成了一个三元组(i,j,aij)的线性表。
template<typename T>
struct element
{
int row,col;
T item;
}
三元组可以采用顺序表示方法,也可以采用链式表示方法,这样就产生了对稀疏矩阵的不同压缩存储方式。
1.稀疏矩阵的顺序实现
若把稀疏矩阵的三元组线性表按顺序存储结构存储,则称为稀疏矩阵的三元组顺序表。
顺序表中除了存储三元组外,还应该存储矩阵行数、列数和总的非零元素数目,这样才能唯一的确定一个矩阵。
const int MAXSIZE = 1e5;
struct SparseMatrix
{
element data[MAXSIZE];
int md,nu,tu;
}
2.稀疏矩阵的十字链表实现
十字链表结点分为三类 :
表结点,它由五个域组成,其中i和j存储的是结点所在的行和列,right和down存储的是指向十字链表中该结点所有行和列的下一个结点的指针,v用于存放元素值。
行头和列头结点,这类结点也有域组成,其中行和列的值均为零,没有实际意义,right和down的域用于在行方向和列方向上指向表结点,next用于指向下一个行或列的表头结点。
总表头结点,这类结点与表头结点的结构和形式一样,只是它的i和j存放的是矩阵的行和列数。
十字链表可以看作是由各个行链表和列链表共同搭建起来的一个综合链表,每个结点aij既是处在第i行链表的一个结点,同时也是处在第j列链表上的一个结点,就你是处在十字交叉路口上的一个结点一样,这就是十字链表的由来。
十字链表中的每一行和每一列链表都是一个循环链表,都有一个表头结点。