4.1字符串

4.1.1字符串的逻辑结构

1.字符串的定义

字符串是n个字符组成的有限序列,串中包含的字符个数为串的串的长度

字符串包含 java 字符串包含多少个字符_字符串包含 java

空串:长度为 0 的串,不包含任何字符

空格串:有多个或一个空格组成,长度为空格数

子串:串中任意个连续的字符组成的子序列

主串:包含子串的串

子串的位置:子串的第一个字符在主串中的序号

字符串大小的比较:

字符串包含 java 字符串包含多少个字符_字符串包含 java_02

 2.字符串的抽象数据类型定义

ADT  String

DataModel

串中的数据元素仅由一个字符组成,相邻元素具有前驱和后继关系

Operation

StrAssign :串赋值

StrLength :求串S的长度

Strcat :串连接

StrSub :求子串

StrCmp :串比较

StrIndex :子串定位

StrInsert :串插入

StrDelete :串删除

endADT

4.1.2字符串的存储结构

字符串是数据元素为单个字符的线性表,一般采用顺序存储,即用数组来存储串的字符序列

方案 1:用一个变量来表示串的实际长度

字符串包含 java 字符串包含多少个字符_1024程序员节_03

方案 2:用数组的 0 号单元存放串的长度,从 1 号单元开始存放串值

字符串包含 java 字符串包含多少个字符_广义表_04

方案 3:在串尾存储一个不会在串中出现的特殊字符作为串的终结符,表示串的结尾

字符串包含 java 字符串包含多少个字符_1024程序员节_05

4.1.3模式匹配 

 

字符串包含 java 字符串包含多少个字符_广义表_06

 在主串S中寻找字串的T的过程称为模式匹配,T称为模式

1.BF算法

BF算法

字符串包含 java 字符串包含多少个字符_三元组_07

 从主串S的第一个在字符开始和模式T的第一个字符进行比较。若相等,则继续比较后续字符,否则,从主串的第二字符开始和模式T的第一个字符开始匹配。

1. 在串 S 和串 T 中设比较的起始下标 i 和 j;

2. 循环直到 S 或 T 的所有字符均比较完

    2.1 如果S[i] 等于T[j],继续比较 S 和 T 的下一个字符;

    2.2 否则,将 i 和 j 回溯,准备下一趟比较;

3. 如果T中所有字符均比较完,则返回匹配的起始比较下标;否则返回 0;

字符串包含 java 字符串包含多少个字符_1024程序员节_08

int BF(char S[ ], char T[ ])
{
    int i = 0, j = 0;   
    while (S[0] != '\0'&&T[0] != '\0')// 遍历字符串
    {
         if (S[i] == T[j]) {
             i++;   j++;
         }//对应匹配成功则继续往下  
         else {
             i = i – j + 1;    j = 0;
         }   //匹配不成功则回溯
     }
     if (T[j] == '\0') return (i – j + 1);  //至模式到终止符,表示匹配成功 
     else return 0;
}

BF算法——性能分析

最好情况:不成功的匹配都发生在串 T 的第 1 个字符

字符串包含 java 字符串包含多少个字符_数组_09

最坏情况:不成功的匹配都发生在串 T 的最后一个字符

字符串包含 java 字符串包含多少个字符_1024程序员节_10

 所以O(n*m)

2.KMP算法

希望某趟在S[i]和T[j]匹配失败后,下标i不回溯,下标j回溯至某个位置k,使得T[k]对准S[i]继续进行比较。

字符串包含 java 字符串包含多少个字符_广义表_11

用next[j]表示T[j]对应的k值

 

字符串包含 java 字符串包含多少个字符_三元组_12

 next数组的求法

void getNext(string T,int length, int next[])//计算next函数值

{
    int j=0,k=-1;
    next[0]=-1;
    while(j<length)
    {   if(k==-1||T[j]==T[k])
            next[++j]=++k;
        else
            k=next[k];
    }
}

KMP算法:

字符串包含 java 字符串包含多少个字符_字符串包含 java_13


1. 在串 S 和串 T 中分别设比较的起始下标 i 和 j;

2. 循环直到 S 或 T 的所有字符均比较完

     2.1 如果S[i]等于T[j],继续比较 S 和 T 的下一个字符;

           否则,将 j 向右滑动到next[j]位置,即 j=next[j];

2.2 如果 j=-1,则将 i 和 j 分别加 1,准备下一趟比较;

 3. 如果 T 中所有字符均比较完毕,则返回匹配的起始下标;否则返回 0;

int  KSP(string s, string t) {
	int i = 0, j = 0;
	while (s[i] != '\0' && t[j] != '\0') {
		if (s[i] == t[j]) {
			i++;j++
		}
		else {
			j = next[j];//匹配不成功,j回溯
		}
		if (j == -1) {
			i++; j++;//j回溯到最后一个依然不成功,i++
		}
	}
}

4.2多维数组

4.2.1数组的逻辑结构

1.数组的定义

数组:由一组类型相同的数据元素构成的有序集合,每个数据元素称为一个数组元素(简称为元素),每个元素受 n(n≥1)个线性关系的约束,每个元素在 n 个线性关系中的序号i1、i2、…、in 称为该元素的下标,并称该数组为 n 维数组

字符串包含 java 字符串包含多少个字符_1024程序员节_14

2.数组的抽象数据类型定义 

在数组上一般不能执行删除与插入某个数组元素的操作,数组没有插入和删除操作,所以,不用预留空间,适合采用顺序存储

读操作:给定下标读取相应的数组元素

写操作:给定下标存储或修改相应数组元素

4.2.2数组的存储结构与寻址

按行优先:先存储行号较小的元素,行号相同者先存储列号较小的元素

按列优先:先存储列号较小的元素,列号相同者先存储行号较小的元素

以按行优先为例:

字符串包含 java 字符串包含多少个字符_数组_15

字符串包含 java 字符串包含多少个字符_数组_16

 

字符串包含 java 字符串包含多少个字符_数组_17

4.3矩阵的压缩存储

4.3.1特殊矩阵的压缩存储

1.对称矩阵

字符串包含 java 字符串包含多少个字符_数组_18

字符串包含 java 字符串包含多少个字符_数组_19

2.三角矩阵

字符串包含 java 字符串包含多少个字符_广义表_20

只存上三角或下三角,相同元素只存一个 

字符串包含 java 字符串包含多少个字符_数组_21

字符串包含 java 字符串包含多少个字符_广义表_22

 3.对角矩阵的压缩存储

 将对角矩阵的非零元素按行存储压缩到一维数组中

字符串包含 java 字符串包含多少个字符_1024程序员节_23

 4.3.2稀疏矩阵的压缩存储

稀疏矩阵是零元素居多的矩阵

三元组表示非零元素的行号、列号、非零元素值

三元组结构定义:

template <typename DataType>
struct element
{
     int row, col;
     DataType item 
};

1.三元组顺序表:采用顺序存储结构存储三元组表

const int MaxTerm = 100;
struct SparseMatrix
{
      element data[MaxTerm];
      int mu, nu, tu; 
};

字符串包含 java 字符串包含多少个字符_1024程序员节_24

字符串包含 java 字符串包含多少个字符_三元组_25

采用链接存储结构存储三元组表)

 将每个非零元素对应的三元组存储为一个链表节点,结点由五个域构成。

字符串包含 java 字符串包含多少个字符_1024程序员节_26

data:表示存储非零元素对应三元组

right:表示同一行的下一个三元组结点

down:表示同一列的下一个三元组结点 

struct OrthNode
{
    Element data;
    OrthNode *right, *down;
};

 将稀疏矩阵每一行的非零元素按其列号从小到大由right域构成一个行链表,每一列的非零元素按其行号从小到大由down域构成一个列链表。

为了实现对某一行链表的头指针进行快速查找,将这些头指针存储在一个数组HA中,同理,对于列,存储在HB中

字符串包含 java 字符串包含多少个字符_1024程序员节_27

4.4拓展 

4.4.1稀疏矩阵的转置

算法一:

void tran(matrix& a, matrix& b) {//a b均为三元组
	int pa, pb, col;//数组a角标 数组b角标  col列元素
	b.mu = a.nu; b.mu = a.nu; b.tu = a.tu;//行列互换
	//mu 三元组a所代表矩阵的总行数  nu 三元组a所代表矩阵的总列数    tu 三元组a所代表矩阵的总非零元素的个数
	pb=0;
		for (col = 1; col <= a.mu; col++) {//依次遍历三元组a代表矩阵的每一列
			for(pa=0;pa<a.tu;pa++){//遍历三元组a
				if(a.data[pa].col==col){
					b.data[pb].row = a.data[pa].col;
					b.data[pb].col = a.data[pa].row;
					b.data[pb].item = a.data[pa].item;
					pb++;
			}
		}

 算法二:

字符串包含 java 字符串包含多少个字符_数组_28

字符串包含 java 字符串包含多少个字符_字符串包含 java_29

void tran(matrix& a, matrix& b) {//a b均为三元组
int i, j, k;
b.mu = a.nu; b.mu = a.nu; b.tu = a.tu;//行列互换
//mu 三元组a所代表矩阵的总行数  nu 三元组a所代表矩阵的总列数    tu 三元组a所代表矩阵的总非零元素的个数
for(i = 0; i < a.tu; i++) {//依次遍历三元组a代表矩阵的每一列
	j = a.data[i].col;//去三元组的列号
	num[j]++;//num初始化
}
copt[1] = 0;
for (i = 0; i < a.tu; i++) {
	copt[i] = copt[i - 1] = num[i - 1];
}
for(i=0;i<a.tu;i++){//遍历三元组a
	j = a.data[i].col;
	k = copt[j];
	b.data[k].row = a.data[i].col;
	b.data[k].col = a.data[i].row;
	b.data[k].item = a.data[i].item;
	copt[j]++;//该列到下一个位置
	}

4.4.2广义表

1.广义表定义

广义表是哪个数据元素的有限序列,每个数据元素可以是不同的,可以是单个数据,也可以是一个集合,通常大写字母表示广义表,小写字母表示单个元素。

广义表中数据元素的个数称为广义表的长度

广义表中括号最大嵌套层数称为广义表的深度

称第一个元素为表头

除去表头其他元素称为表尾

(1)A=()——A是一个空表,其长度为零,深度为1

(2)B=(e)——表B只有一个原子e,B的长度为1,深度为1

(3)C=(a,(b,c,d))——表C的长度为2,两个元素分别为原子a和子表(b,c,d),深度为2

(4)D=(A,B,C)——表D的长度为3,三个元素都是广义表。显然,将子表的值代入后,则有D=(( ),(e),(a,(b,c,d))),深度为3

(5)E=(E)——这是一个递归的表,它的长度为2,E相当于一个无限的广义表E=(a,(a,(a,(a,…)))),深度为无穷。

广义表的逻辑结构图:

广义表的数据元素a用一个节点来表示;若x为单元素,则用矩形结点表示;若x为广义表,则用圆形结点表示;

广义表的特性:

  1. 广义线性
  2. 元素复合性:数据元素有两种单元素和子表
  3. 元素递归性
  4. 元素共享性

2.广义表的存储结构

采用链接存储结构来存储广义表。

头尾表示法:若广义表不空,则可分解为表头和表尾,反之,对确定的表头和表尾可以确定一个广义表。

字符串包含 java 字符串包含多少个字符_广义表_30

表结点:存储广义表

原子结点:存储单元素

tag:区分表结点域原子结点

hp:指向表头的指针

tp:指向表尾的指针

atom:存放单元素的的数据域

字符串包含 java 字符串包含多少个字符_字符串包含 java_31

Glist creatGlist(Glist C){
    C=(Glist)malloc(sizeof(Glist));
    C->tag=1;
    C->hp=(Glist)malloc(sizeof(Glist));
    C->tp=NULL;
    //表头原子a
    C->hp->tag=0;
    C->atom='a';
    C->hp->tp=(Glist)malloc(sizeof(Glist));
    C->hp->tp->tag=1;
    C->hp->tp->hp=(Glist)malloc(sizeof(Glist));
    C->hp->tp->tp=NULL;
    //原子b
    C->hp->tp->hp->tag=0;
    C->hp->tp->hp->atom='b';
    C->hp->tp->hp->tp=(Glist)malloc(sizeof(Glist));
    //原子c
    C->hp->tp->hp->tp->tag=0;
    C->hp->tp->hp->tp->atom='c';
    C->hp->tp->hp->tp->tp=(Glist)malloc(sizeof(Glist));
    //原子d
    C->hp->tp->hp->tp->tp->tag=0;
    C->hp->tp->hp->tp->tp->atom='d';
    C->hp->tp->hp->tp->tp->tp=NULL;
    return C;
}