字符串的基础知识

4.1字符串

4.1.1字符串的逻辑结构

1.字符串的定义

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

字符串的基础知识_第1张图片

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

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

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

主串:包含子串的

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

字符串大小的比较:

字符串的基础知识_第2张图片

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

ADT  String

DataModel

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

Operation

       StrAssign 串赋值

       StrLength 求串S的长度

       Strcat 串连接

       StrSub 求子串

       StrCmp 串比较

       StrIndex 子串定位

       StrInsert 串插入

       StrDelete 串删除

endADT

4.1.2字符串的存储结构

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

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

字符串的基础知识_第3张图片

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

字符串的基础知识_第4张图片

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

字符串的基础知识_第5张图片

4.1.3模式匹配 

 

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

1.BF算法

BF算法

字符串的基础知识_第6张图片

 从主串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

字符串的基础知识_第7张图片

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 个字符

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

 所以O(n*m)

2.KMP算法

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

字符串的基础知识_第8张图片

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

 字符串的基础知识_第9张图片

 next数组的求法

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

{
    int j=0,k=-1;
    next[0]=-1;
    while(j

KMP算法:

字符串的基础知识_第10张图片

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 线性关系中的序号i1i2、…、in 称为该元素的下标,并称该数组n 维数

字符串的基础知识_第11张图片

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

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

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

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

4.2.2数组的存储结构与寻址

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

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

以按行优先为例:

字符串的基础知识_第12张图片

 字符串的基础知识_第13张图片

4.3矩阵的压缩存储

4.3.1特殊矩阵的压缩存储

1.对称矩阵

字符串的基础知识_第14张图片

字符串的基础知识_第15张图片

字符串的基础知识_第16张图片

2.三角矩阵

字符串的基础知识_第17张图片只存上三角或下三角,相同元素只存一个 

字符串的基础知识_第18张图片

字符串的基础知识_第19张图片

 3.对角矩阵的压缩存储

 将对角矩阵的非零元素按行存储压缩到一维数组中字符串的基础知识_第20张图片

 4.3.2稀疏矩阵的压缩存储

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

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

三元组结构定义:

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

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

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

字符串的基础知识_第21张图片字符串的基础知识_第22张图片

 2.十字链表(采用链接存储结构存储三元组表)

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

字符串的基础知识_第23张图片

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

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

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

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

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

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

字符串的基础知识_第24张图片

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

 算法二:

字符串的基础知识_第25张图片

字符串的基础知识_第26张图片

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

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.广义表的存储结构

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

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

字符串的基础知识_第27张图片

表结点:存储广义表

原子结点:存储单元素

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

hp:指向表头的指针

tp:指向表尾的指针

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

字符串的基础知识_第28张图片

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;
}

你可能感兴趣的:(算法,1024程序员节)