栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

数据结构与算法:线性表之串

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

数据结构与算法:线性表之串

串(或者字符串)是由零个或者多个字符组成的有限序列,一般记为s=‘a1a2a3…an’(n>=0)其中,s是串的名,用单括号括起来的字符串序列是串的值;ai(1<=i<=n)可以是字母、数字或其他字符;串中字符的数目n称为串的长度。零个字符的串称为空串,它的长度为0。


目录
  • 1. 串的概念
    • 1.1 串的定义
    • 1.2 子串的定义
    • 1.3 串与线性表的区别:
  • 2. 串的基本操作
    • 2.1 定长顺序储存表示
      • 2.1.1 定义
      • 2.1.2 代码如下
    • 2.1.1 串连接
      • 2.1.1.1 代码
    • 2.1.2 求子串
      • 2.1.2.1 代码
    • 2.2 堆分配存储表示
      • 2.2.1 定义
      • 2.2.2 代码如下
      • 2.2.3 基本操作
        • 2.2.3.1 赋值操作
        • 2.2.3.2 求子串
        • 2.2.3.3 比较操作
        • 2.2.3.4 定位操作
    • 2.3 串的块链存储表示
      • 定义
  • 3.串的模式匹配
          • 1、BF算法(又称古典的、经典的、朴素的、穷举的)
          • 2、KMP算法(特点:速度快)
          • next[i][j]=k:


1. 串的概念 1.1 串的定义

串是由零个或者多个字符组成的有序序列。一般记为S=“a1a2…an”(n>=0)。当n=0时称为空串(注意与空格串区分)。

1.2 子串的定义

串中任意个连续的字符组成的子序列称为该串的子串。

只有当两个串的长度相等,并且各个对应位置上的字符都相等时才称这两个串是相等的。

另,串值必须用一对单括号括起来,但单括号本身不属于串,他的作用只是为了避免与变量名或数的常量混淆。

1.3 串与线性表的区别:

(1)串的数据对象限定为字符集;(英文字符——ASCII,中英文——Unicode)

(2)串的基本操作通常以子串为操作对象,而线性表以单个元素作为操作对象。

2. 串的基本操作 2.1 定长顺序储存表示 2.1.1 定义

用一组地址连续的储存单元存储串值得字符序列。在串的定长顺序存储结构中,按照预定义的大小,为每个定义的串变量分配一个固定长度的存储区。

2.1.2 代码如下
#define MAXLEN 255   //预定义最大串长255
typedef struct{
    char ch[MAXLEN];   //每个分量存储一个字符
    int length;   //串的实际长度
}SString;

这里所用的顺序存储的字符串从下标为1的数组分量开始存储,下标为0的分量闲置不用。(本文采用的存储方式)

有的教程采用ch[0]充当length,缺点是只可以表示0-255的长度;还有在串值后面加一个不计入串长的结束标记字符‘’,此时的串长为隐含值,缺点是每次需遍历求串长。

2.1.1 串连接

串连接:把两个串s1和s2首尾连接成一个新串s,即s<-s1+s2

2.1.1.1 代码
int StrConcat(s1,s2,s)
    char s1[],s2[],s[];//将串s1,s2合并到串s,合并成功返回1,否则返回0
{
    int i =0,j,len1,len2;
    len1 = StrLength(s1);
    len2 = StrLength(s2);
    
    if(len1+len2>MAXSIZE-1) return 0;    //s 长度不够
 
    j = 0 ;
    while(s1[j]! =""){
        s[i] = s1[j];
        i++;
        j++;
    }
     while(s2[j]! =""){
        s[i] = s2[j];
        i++;
        j++;
    }
    s[i] = "";
    return 1;
}
2.1.2 求子串

将串s中从第i个字符开始长度为len的字符序列复制到串s中,

2.1.2.1 代码
int StrSub(char *t ,char *s,int i , in len){
//用t返回串s中第i个字符串开始的长度为len的子串,1<=i串长
    
    int slen;
    slen = StrLength(s);
    if(i<1 || i>slen || len<0 || len>slen-i+1){
        return 0;
    }
    
    for(j =0 ; j
        t[j] =s[i+j-1];
        t[j] ="";
        return 1;
    }
}
2.2 堆分配存储表示 2.2.1 定义

在顺序串上的插入、删除操作并不方便,必须移动大量的字符,而且当操作中出现串值序列的长度超过上界MAXSIZE时,只能用截尾法处理。要克服这个弊病,只有不限定串的最大长度,动态分配串值的存储空间。

堆分配存储结构的特点是:仍以一组地址连续的存储单元存放串的字符序列,但其存储空间是在算法执行过程中动态分配得到的。在C语言中,由动态分配函数malloc()和free()来管理。利用函数malloc()为每一个新产生的串分配一块实际需要的存储空间,若分配成功,则返回一个指针,指向串的起始地址。

由于堆分配存储结构的串既有顺序存储结构的特点,在操作中又没有串长的限制,显得很灵活,因此,在串处理的应用程序中常被选用。

2.2.2 代码如下
typedef struct{
    char *ch;   //按串长分配存储区,ch指向串的基地址
    int length;   //串的长度
}HString;
 
HString S;
S.ch=(char *)malloc(MAXLEN*sizeof(char));
S.length=0;

在C语言中,存在一个称为“堆”的自由存储区,并用malloc()和free()函数来完成动态存储管理。

2.2.3 基本操作 2.2.3.1 赋值操作
//赋值操作
void StrAssign(SString &str)
{
	char cc;
	int i=0;
	scanf("%c",&cc);
	while(cc!='#'&&i
		i=i+1;
		str.ch[i]=cc;
		scanf("%c",&cc);
	}
	str.ch[i+1]='';  //字符串结束标记
	str.length=i;  //串长为i
}
2.2.3.2 求子串
bool SubString(SString &s1,SString &s,int pos,int len)
{
	if(pos+len-1>s.length)//子串范围越界
		return false;
	for(int i=pos;i 
2.2.3.3 比较操作 
//比较操作
int StrCompare(SString S,SString T)
{
	//若S>T,则返回值>0;若S=T,则返回值=0,若S
		if(S.ch[i]!=T.ch[i])
			return S.ch[i]-T.ch[i];
	}
	//扫描过的所有字符都相同,则长度长的串更大
	return S.length-T.length;
}
2.2.3.4 定位操作
//定位操作
int Index(SString S,SString T)
{
	int i=1,n=S.length,m=T.length;
	SString sub;//用于暂存子串
	while(i<=n-m+1)
	{
		if(SubString(sub,S,i,m))
		{
			if(StrCompare(sub,T)!=0)
				++i;
			else
				return i;//返回子串在主串的位置
		}
	}
	return 0;//S中不存在与T相等的子串
}
2.3 串的块链存储表示 定义

串的链式存储与线性表相似,但由于串结构的特殊性,结构中的每个元素数据都是一个字符,如果也简单的应用链表存储串值,一个结点对应一个字符,就会存在很大的空间浪费,因此一个结点可以存放多个字符,最后一个结点若是未被占满时,可以用 “#” 或其它非串值字符补全。

为了便于进行串的操作,当以链表存储串值时,除头指针外还可附设一个尾指针指示链表中的最后一个结点,并给出当前串的长度。称如此定义的串存储结构为块链结构。

3.串的模式匹配 1、BF算法(又称古典的、经典的、朴素的、穷举的)

算法思想:

(1)将主串的第pos个字符和模式的第一个字符比较,若相等,继续逐个比较后续字符;若不等,从主串的下一字符起,重新与模式的第一个字符比较;

(2)直到主串的一个连续子串字符序列与模式相等 。返回值为S中与T匹配的子序列第一个字符的序号,即匹配成功。否则,匹配失败,返回值 0。

//简单模式匹配算法(BF)
int BFIndex(SString S,SString T)
{
	int i=1,j=1;//i,j分别指向主串和模式串
	while(i<=S.length&&j<=T.length)
	{
		if(S.ch[i]==T.ch[j])
		{
			i++;//继续比较后续字符
			j++;
		}
		else
		{
			i++;//检查下一子串
			j=1;
		}
	}
	if(j>T.length)
		return i-T.length;
	else
		return 0;
}
2、KMP算法(特点:速度快)

算法思想:

此算法可以在O(n+m)的时间数量级上完成串的模式匹配操作。其改进在于:每当一趟匹配过程中出现字符比较不等时,不需回溯i指针,而是利用已经得到的“部分匹配”的结果将模式向右“滑动”尽可能远的一端距离后,继续进行比较。

模式串的next函数的定义:

next[i][j]=k:

①当j=1(t1与si比较不等时,下一步进行t1与si+1的比较)时Max{k|1

②k=1(不存在相同子串,下一步进行t1与si的比较)

KMP算法描述:

int Index_KMP(Sstring S, Sstring T,int pos)
{
   //利用模式串T的next函数求T在主串S中第pos个字符之后的位置
  //其中,T非空,1<=pos<=S.length
 
   i=pos;j=1;
   while(i<=S.length&&j<=T.length)   //两个串均未比较到串尾
   {
      if(j==0||S.ch[i]==T.ch[j]){++i; ++j;}   //继续比较后继字符
      else j=next[j];   //模式串向右移动
   }
   if(j>T.legnth)return i-T.length;   //匹配成功
   else return 0;   //匹配失败
}

计算next函数值的算法描述:

void get_next(Sstring T,int next[])
{
   //求模式串T的next函数值并存入数组next
   i=1;next[1]=0;j=0;
   while(i
      if(j==0||T.ch[i]==T.ch[j]){++i;++j;next[i]=j;}
      else j=next[i][j];
   }
}

计算next函数修正值的算法描述:

void get_nextval(Sstring T,int nextval[])
{
   //求模式串T的next函数修正值并存入数组nextval 
   i=1;nextval[1]=0;j=0;
   while(i
      if(j==0||T.ch[i]==T.ch[j])
      {
         ++i;++j;
         if(T.ch[i]!=T.ch[j])nextval[i]=j;
         else nextval[i]=nextval[j];
      }
      else j=nextval[j];
   }
}
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/869351.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号