一、字符串和数组的基本概念
字符串是以字符作为数据元素的线性表,是重要的非数值处理对象
数组作为一种数据结构,特点是数据元素本身可以具有某种结构,但属于同一数据类型
二、字符串
2.1 字符串的定义
字符串是0个或多个字符组成的有限序列,只包含空格的串称为空格串
2.2 字符串的比较
假设有字符串X,Y,其长度分别为n,m
当下列条件之一成立时,称X<Y
(一)n<m,且Xi = Yi (i = 1,2,3,4…)
(二)存在某个k<=min(m,n),使得Xi = Yi(i = 1,2,3,4…,k-1),且Xk<Yk
e.g: “abcd” = “abcd”;“abc”<“abcd”;“abac”<“anaec”;“abafg”<“abc”
2.3 字符串的存储结构
字符串一般采用顺序存储
2.4 字符串的模式匹配
给定两个字符串S和T,在主串S中寻找子串T的过程称为模式匹配,T称为模式
2.4.1 朴素的模式匹配算法(BF算法)
BF算法的基本思想:从主串S的第一个字符串开始和模式T的第一个字符串进行比较,若相等,则继续比较二者的后续字符;否则,从主串的第二个字符开始和模式T的第一个字符进行比较。直到所有字符串比较完毕
算法:
void connect(char s[],char t[]){
int i=0;
int j=0;
while(1){
if(s[i] == t[j]){
i++;
j++;
if(t[j] == '\0'){
cout<<"匹配成功"<<endl;
i = i-j+1; //找到匹配成功时在主串中的初始位置
cout<<"主串中匹配位置为:"<<i<<endl;
return ;
}
}else if(s[i] != t[j]){
i = i-j+1; //回溯,回到上次匹配位置的下一个位置
j = 0;
}
if(s[i] == '\0'){
cout<<"匹配失败"<<endl;
return ;
}
}
}
时间性能的分析
(一)最好的情况下,每趟不成功的匹配都发生在模式T的第一个字符
e.g: S = “aaaaaaaaaaabc” ; T = “bc”;
时间复杂度O(m+n);
(一)最坏的情况下,每趟不成功的匹配都发生在模式T的最后一个字符
e.g: S = “aaaaaaaaaaab” ; T = “aaab”;
时间复杂度O(m×n);
2.4.2 改进的模式匹配算法(KMP算法)
KMP算法的基本思想:主串不进行回溯
BF算法的特点是主串回溯;而KMP算法的特点是主串不回溯,子串即模式串回溯
KMP算法:
void connect(char s[],char t[],int next[]){
int i=0;
int j=0;
int lens = strlen(s);
int lent = strlen(t);
while(1){
if(s[i] == t[j] || j == -1){
i++;
j++;
if(j == lent){
cout<<"匹配成功"<<endl;
i = i-j+1;
cout<<"主串中匹配位置为:"<<i<<endl;
return ;
}
}else if(s[i] != t[j]){
j = next[j];
}
if(i == lens){
cout<<"匹配失败"<<endl;
return ;
}
}
}
next数组的实现算法:
int next[j];
int m = -1; //前缀
int n = 0; //后缀
next[0] = -1;
while(n<j){
if(m == -1 || t[m] == t[n]){
m++;
n++;
next[n] = m;
}else{
m = next[m];
}
}
时间性能的分析
KMP算法的时间复杂度为O(m+n)
三、多维数组
3.1 数组的定义
数组是由类型相同的数据元素构成的有序集合,每一个数据元素成为一个数组元素
二维数组,如:a[x][y] 其中x表示行的数量,y表示列的数量
3.2 矩阵压缩
矩阵压缩的基本思想:①为多个值相同的元素只分配一个存储空间;②对零元素不分配存储空间
3.2.1 对称矩阵的压缩
令i,j分别为在矩阵中对应的位置,k为每个矩阵元素在一维数组中对应的元素下标
若是下三角矩阵,则:k = i*(i - 1)/2+j-1;
若为上三角矩阵,则:k = j*(j - 1)/2+i-1;
3.2.2 三角矩阵的压缩
令i,j分别为在矩阵中对应的位置,k为每个矩阵元素在一维数组中对应的元素下标
若是下三角矩阵,则:k = i*(i - 1)/2+j-1(i<=j时),k = n*(n+1)/2 (i>j);
若为上三角矩阵,则:k = j*(j - 1)/2+i-1(i<=j时),k = n*(n+1)/2 (i>j);
3.2.3 对角矩阵的压缩
令i,j分别为在矩阵中对应的位置,k为每个矩阵元素在一维数组中对应的元素下标
则:k = 2*i+j-3;
3.2.4 稀疏矩阵的压缩存储
3.2.4.1 三元组顺序表
思路:
1、首先创建一个结构体,用于存储每个非零矩阵元素的下标和数值
typedef struct element{
int row,col; //三元组的行号、列号
int item; //三元组的值
}Element;
2、再创建一个结构体数组,每个数组元素包含了row,col和item值,存入数据元素的代码:
void TripleMatrix::setItem(int row,int col,int item){
if(item == 0){
cout<<"不用存入"<<endl;
return;
}else if(tu>=(mu*nu)){
cout<<"矩阵已满"<<endl;
return;
}else{
int i = 0;
if(tu==0){
//初始时,对第一个元素赋值
data[tu].row = row;
data[tu].col = col;
data[tu].item = item;
tu++;
}else{
while(i<tu){
//循环判断,找到合适的位置插入到其中
if(data[i].row<row ) //跟当前位置的元素比较,如果要插入的元素的row比当前的要小,则退出,插入到这个位置;否则就加一
i++;
else if(data[i].row == row && data[i].col < col) //如果要插入的元素的row与当前的row相同,比较col的值,如果小一些,则退出;否则就加一
i++;
else
break;
}
if((data[i].col == col) && (data[i].row == row)) //如果row与col的值相同,则覆盖
data[i].item = item;
else{
for(int j=tu;j>i;j--)
data[j] = data[j-1];
data[i].row = row;
data[i].col = col;
data[i].item = item;
tu++;
}
}
}
}
3.2.4.2 十字链表法
略
3.2.5 矩阵的加法
bool MatrixAdd(TripleMatrix a,TripleMatrix b,TripleMatrix& c){
if(a.mu != b.mu || a.mu != c.mu ||a.nu != b.nu ||a.nu != c.nu ){
return false;
}else{
for(int i=1;i<=a.mu;i++){
for(int j=1;j<=a.nu;j++){
int item = a.getItem(i,j) + b.getItem(i,j);
if(item!=0)
c.setItem(i,j,item);
}
}
c.printTripleMatrix();
return true;
}
}
3.2.6 矩阵的乘法
bool MatrixMulty(TripleMatrix a,TripleMatrix b,TripleMatrix& c){
int item = 0;
if(a.mu != b.nu || a.mu != c.mu ||a.nu != b.mu ||b.nu != c.nu ){
//矩阵 c 的行数由矩阵 a 的行数决定 矩阵 c 的列数由矩阵 b 的列数决定
return false;
}else{
for(int i=1;i<=a.mu;i++){
// 控制矩阵a的行数的变化
for(int j=1;j<=b.nu;j++){
//控制矩阵b的列数的变化
for(int z=1;z<=b.mu;z++){
//矩阵a的每一行的列元素 以及控制矩阵b的每一列的行元素
item = item + a.getItem(i,z) * b.getItem(z,j);
}
if(item!=0)
c.setItem(i,j,item);
item = 0;
}
}
c.printTripleMatrix();
return true;
}
}