C语言中如何用一个字符串替换一个主串中的子串
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C语言中如何用一个字符串替换一个主串中的子串相关的知识,希望对你有一定的参考价值。
参考技术A 参考以下代码#include
<string.h>
//oldstr原字符串,
newstr新字符串,
oldsubstr原字符串中要替换的
子串
,
newsubstr新字符串中替换后的
新子
串
void
replace(char
*oldstr,
char
*newstr,
char
*oldsubstr,
char
*newsubstr)
int
i,
j;
int
nLen
=
strlen(oldstr);
int
nLenSub
=
strlen(oldsubstr);
for(i=0,
j=0;
i<nLen;)
if(0
==
strncmp(oldstr+i,
oldsubstr,
nLenSub))
strcat(newstr+j,
newsubstr);
j
+=
strlen(newsubstr);
i
+=
nLenSub;
else
newstr[j++]
=
oldstr[i++];
数据结构-串数组和广义表
串、数组和广义表
串
串的定义
串(String)——零个或多个任意字符组成的有限序列
-
子串:串中任意个连续字符组成的子序列称为该串的子串
真子串是指不包含自身的所有子串
-
主串:包含子串的串相应地称为主串
-
字符位置:字符在序列中的序号为该字符在串中的位置
-
子串位置:子串第一个字符在主串中的位置
-
空格串:由一个或多个空格组成的串,与空串不同
串相等:当且仅当两个串的长度相等并且各个对应位置上的字符都相同时,这两个串才是相等的。
- 所有空串是相等的。
串的类型定义、存储结构及运算
ADT String
数据对象:D=a_i|a_i∈CharacterSet,i=1,2,...,n,n≥0
数据关系:R_1=<a_i-1,a_i>|a_i-1,a_i∈D,i=1,2,...,n
基本操作:
StrAssign(&T,chars) //串赋值
StrCompara(S,T) //串比较
StrLength(S) //求串长
Concat(&T,S1,S2) //串连结
SubString(&Sub,S,pos,len) //求子串
StrCopy(&T,S) //串拷贝
StrEmpty(S) //串判空
ClearString(&S) //清空串
Index(S,T,pos) //子串的位置
Replace(&S,T,V) //串替换
StrInsert(&S,pos,T) //子串插入
StrDelete(&S,pos,len) //子串删除
DestroyString(&S) //串销毁
ADT String
-
串的顺序存储结构
#define MAXLEN 255 typedef struct char ch[MAXLEN+1]; //存储串的一维数组 int length; //串的当前长度 SString;
-
串的链式存储结构——块链结构
优点:操作方便 缺点:存储密度较低(存储密度=串值所占的存储/实际分配的存储)
可将多个字符存放在一个结点中,以克服其缺点
#define CHUNKSIZE 80 //块的大小可由用户定义 typedef struct Chunk char ch[CHUNKSIZE]; struct Chunk *next; Chunk; typedef struct Chunk *head,*tail; //串的头指针和尾指针 int curlen; //串的当前长度 LString; //字符串的块链结构
-
串的模式匹配算法
算法目的:
确定主串中所含**子串(模式串)**第一次出现的位置(定位)
算法应用:
搜索引擎、拼写检查、语言翻译、数据压缩
算法种类:
-
BF算法(Brute-Force,又称古典的、经典的、朴素的、穷举的)
简单匹配算法,采用穷举法的思路,从S的每一个字符开始依次与T的字符进行匹配
int Index_BF(SString S,SString T) int i=1,j=1; while(i<=S.length&&j<=T.length) if(s.ch[i]==t.ch[j])++i;++j;//主串和子串依次匹配下一个字符 elsei=i-j+2;j=1;//主串、子串指针回溯重新开始下一次匹配 if(j>=T.length) return i-T.length;//返回匹配的第一个字符的下标 else return 0;//模式匹配不成功
若n为主串长度,m为子串长度,最坏情况是总次数为:(n-m)*m+n=(b-m+1) * m,若m<<n,则算法复杂度O(n * m)
-
KMP算法(特点:速度快)
利用已经部分匹配的结果而加快模式串的滑动速度?
且主串S的指针i不必回溯!可提速到O(n+m)!
为此,定义**next[j]**函数,表明当模式中第j个字符与主串中相应字符“失配”时,在模式中需重新和主串中该字符进行比较的字符的位置。
n e x t [ j ] = m a x k ∣ 1 < k < j , 且 " p 1 . . . p k − 1 " ( 从头开始的 k − 1 个元素 ) = " p j − k + 1 . . . p j − 1 " ( j 前面的 k − 1 个元素 ) 当此集合非空时 0 当 j = 1 时 1 其他情况 next[j]= \\begincases max\\k|1<k<j,且"p_1...p_k-1"(从头开始的k-1个元素)="p_j-k+1...p_j-1"(j前面的k-1个元素)\\\\\\ \\quad \\quad \\quad \\quad 当此集合非空时\\\\ 0\\quad 当j=1时\\\\ 1\\quad 其他情况 \\endcases next[j]=⎩ ⎨ ⎧maxk∣1<k<j,且"p1...pk−1"(从头开始的k−1个元素)="pj−k+1...pj−1"(j前面的k−1个元素)当此集合非空时0当j=1时1其他情况
int Index KMP(SString S,SString T,int pos) 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];/*i不变,j后退*/ if(j>T.length) return i-T.length;/*匹配成功*/ else return 0;/*返回不匹配标志*/ void get_next(SString T,int &next[]) i=1;next[1]=0;j=0; while(i<T.length) if(j==0|T.ch[i]==T.ch[j]) ++i;++j; next[i]=j; else j=next[j]; //next改进 void get_nextval(SString T,int &nextval[]) i=1;nextval[1]=0;j=0; while(i<T.length) 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];
-
数组
数组:按一定格式排列起来的、具有相同类型的数据元素的集合。
一维数组:若线性表中的数据元素为非结构的简单元素,则称为一维数组。
一维数组的逻辑结构:线性结构。定长的线性表。
声明格式:数据类型 变量名称[长度];
二维数组:若一维数组中的数据元素又是一维数组结构,则称为二维数组。
二维数组的逻辑结构:
-
非线性结构
每一个数据元素既在一个行表中,又在一个列表中。
-
线性结构、定长的线性表
该线性表的每个数据元素也是一个定长的线性表。
声明格式:数据类型 变量名称[行数] [列数];
在C语言中,一个二维数组类型也可以定义为一维数组类型(其分量类型为一维数组类型),即:
typedef elemtype array2[m][n];
//等价于
typedef elemtype array1[n];
typedef array1 array2[m];
三维数组:若二维数组中的元素又是一个一维数组,则称作三维数组。
n维数组:若n-1维数组中的元素又是一个一维数组结构,则称作n维数组。
结论:线性表结构是数组结构的一个特例,而数组结构又是线性表结构的扩展。
数组特点:结构固定——定义后,维数和维界不再改变。
数组基本操作:除了结构的初始化和销毁之外,只有取元素和修改元素值的操作。
特殊矩阵的压缩存储
矩阵:一个由mxn个元素排成的m行n列的表。
矩阵的常规存储:将矩阵描述为一个二维数组。
矩阵的常规存储的特点:可以对其元素进行随机存取;矩阵运算非常简单;存储的密度为1。
不适宜常规存储的矩阵:值相同的元素很多且呈某种规律分布;零元素多。
矩阵的压缩存储:为多个相同的非零元素只分配一个存储空间;对零元素不分配空间。
-
对称矩阵
特点:在n×n的矩阵a中,满足如下性质:aij=aji(1≤i,j≤n)
存储方法:只存储下(或者上)三角(包括主对角线)的数据元素。共占用n(n+1)/2个元素空间。
-
三角矩阵
特点:对角线以下(或者以上)的数据元素(不包括对角线)全部为常数c。
存储方法:重复元素c共享一个元素存储空间,共占用n(n+1)/2+1个元素空间:sa[1…n(n+1)/2+1]
存储下标 上三角矩阵: k = ( i − 1 ) × ( 2 n − i + 2 ) / 2 + j − i + 1 i ≤ j n ( n + 1 ) / 2 + 1 i > j 下三角矩阵: k = i × ( i − 1 ) / 2 + j i ≥ j n ( n + 1 ) / 2 + 1 i < j 存储下标\\\\ 上三角矩阵:k= \\begincases (i-1)×(2n-i+2)/2+j-i+1\\quad i≤j \\\\ n(n+1)/2+1\\quad i>j \\endcases\\\\ 下三角矩阵:k= \\begincases i×(i-1)/2+j\\quad i≥j \\\\ n(n+1)/2+1\\quad i<j \\endcases 存储下标上三角矩阵:k=(i−1)×(2n−i+2)/2+j−i+1i≤jn(n+1)/2+1i>j下三角矩阵:k=i×(i−1)/2+ji≥jn(n+1)/2+1i<j -
对角矩阵(带状矩阵)
特点:在n×n的方阵中,所有非零元素都集中在以主对角线为中心的带状区域中,区域外的值全为0,则称为对角矩阵。常见的有三对角矩阵、五对角矩阵、七对角矩阵等。
存储方法:以对角线的顺序存储
稀疏矩阵:设在m×n的矩阵中有t个非零元素。令δ=t/(m×n),当δ≤0.05时称为稀疏矩阵。
压缩存储原则:存各非零元的值、行列位置和矩阵的行列数。
注意:为更可靠描述,通常再加一个“总体”信息:即总行数、总列数、非零元素总个数。
三元组顺序表又称有序的双下标法。
三元组顺序表的优点:非零元在表中按行有序存储,因此便于进行依行顺序处理的矩阵运算。
三元组顺序表的缺点:不能随机存取。若按行号存取某一行中的非零元,则需从头开始进行查找。
稀疏矩阵的链式存储结构:十字链表
优点:它能够灵活地插入因运算而产生的新的非零元素,删除因运算而产生的新的零元素,实现矩阵的各种运算。
在十字链表中,矩阵的每一个非零元素用一个结点表示,该结点除了(row,col,value)以外,还要有两个域:
- right:用于链接同一行中的下一个非零元素;
- down:用以链接同一列中的下一个非零元素。
广义表
广义表(又称列表Lists)是n≥0个元素a0,a1,…,a_n-1的有限序列,其中每一个ai或者是原子,或者是一个广义表。
广义表通常记作:LS=(a1,a2,…,an) 其中:LS为表名,n为表的长度,每一个ai为表的元素。
习惯上,一般用大写字母表示广义表,小写字母表示原子。
表头:若LS非空(n≥1),则其第一个元素a1就是表头。记作head(LS)=a1。 注:表头可以是原子,也可以是子表。
表尾:除表头之外的其它元素组成的表。记作tail(LS)=(a2,…,an)。 注:表尾不是最后一个元素,而是一个子表。
广义表的性质
-
广义表中的数据元素有相对次序;一个直接前驱和一个直接后继
-
广义表的长度定义为最外层所包含元素的个数
-
广义表的深度定义为该广义表展开后所含括号的重数
A=(b,c)的深度为1,B=(A,d)的深度为2,C=(f,B,h)的深度为3
注意:“原子”的深度为0;“空表”的深度为1。
-
广义表可以为其他广义表共享;如:广义表B就共享表A。在B中不必列出A的值,而是通过名称来引用,B=(A)
-
广义表可以是一个递归的表。如:F=(a,F)
注意:递归表的深度是无穷值,长度是有限值。
-
广义表是多层次结构,广义表的元素可以是单元素,也可以是子表,而子表的元素还可以是子表,…。
广义表可以看成是线性表的推广,线性表是广义表的特例。
广义表的结构相当灵活,在某种前提下,它可以兼容线性表、数组、树和有向图等各种常用的数据结构。
当二维数组的每行(或每列)作为子表处理时,二维数组即为一个广义表。
广义表的基本运算
- 求表头GetHead(L):非空广义表的第一个元素,可以是一个单一的元素,也可以是一个子表
- 求表尾GetTail(L):非空广义表除去表头元素以外其它元素所构成的表。表尾一定是一个表
以上是关于C语言中如何用一个字符串替换一个主串中的子串的主要内容,如果未能解决你的问题,请参考以下文章