对于数据结构的这些方面其实主要是为了做个总结,记录知识点
串的定义:是由零个或多个字符组成的有限序列,也称为字符串
串当中的字符数目n称为是串的长度,零个字符的串可以称为是空串,需要注意的是这个空串和空格串是不同的,空格串是只包含空格的串,空格串是有长度的,可以不止有一个空格
子串与主串,串中任意个数的连续字符组成的子序列称为该串的子串,相应地,包含子串的串称为主串,子串在主串中的位置就是子串的第一个字符在主串中的序号
对于串的比较其实是通过组成串的字符之间的编码来进行的,而字符的编码指的是字符在对应字符集中的序号
只有在串中对应的每个字符都相等情况下,两个字符串才会相等
如果是一个字符串会小于另外一个字符串,可能出现的情况如下所示
给定两个串:s=”a1a2……an”,t=”b1b2……bm”,当满足以下条件之一时,s < t
- 1.n < m,且ai=bi(i=1,2,……,n),其中n代表s字符串的长度,s代表t字符串的长度,前面字符串都相同,但是s字符串的长度比t字符串小也就说明s字符串小于t字符串
- 2.存在某个k≤min(m,n)这是k>1的时候,使得ai=bi(i=1,2,……,k-1),ak < bk,如果两个字符串从第一个字符就开始不相等也就是说a1 != b1的话就直接只比较a1和b1的大小
其实我们的英语词典就是按照字符串大小的顺序来进行排列的,所以我们查找单词的时候其实也就是在比较字符串的大小
关于串的抽象数据结构如下所示
ADT 串(string)
Data
串中元素仅由一个字符组成,相邻元素具有前驱和后继关系。
Operation
StrAssign(T, *chars): 生成一个其值等于字符串常量chars的串T
StrCopy(T, S): 串S存在,由串S复制得串T
ClearString(S): 串S存在,将串清空。
StringEmpty(S): 若串S为空,返回true,否则返回false。
StrLength(S): 返回串S的元素个数,即串的长度。
StrCompare(S, T): 若S>T,返回值>0,若S=T,返回0,若S<T,返回值<0。
Concat(T, S1, S2): 用T返回由S1和S2联接而成的新串。
SubString(Sub, S, pos, len): 串S存在,1≤pos≤StrLength(S),
且0≤len≤StrLength(S)-pos+1,用Sub返
回串S的第pos个字符起长度为len的子串。
Index(S, T, pos): 串S和T存在,T是非空串,1≤pos≤StrLength(S)。
若主串S中存在和串T值相同的子串,则返回它在主串S中
第pos个字符之后第一次出现的位置,否则返回0。
Replace(S, T, V): 串S、T和V存在,T是非空串。用V替换主串S中出现的所有
关于串的抽象数据类型的定义其实主要为的就是将我们生活中可能用到的一些算法给集合在一起体现程序设计当中问题的分解,在串当中抽象数据结构的定义更加关注的是怎么去查找子串的位置,怎么得到指定位置的子串、替换子串等,其实就是为了处理我们现实生活中可能遇到的问题所设计的
串的存储结构分为两种,一种是顺序存储结构还有一种是链式存储结构,串的顺序存储结构是用一组地址连续的存储单元来存储串,我们会为串去分配一个固定长度的存储区,一般是用定长的数组来定义的
我们在C语言当中定义一个字符数组的时候我们需要多加一个长度,因为编译器会自动的帮我们添加一个’\0’,这样方便去确定其的字符串的长度,下面字符数组当中只有两个字符但是我们定义的字符数组的长度为3
char s[3] = {'a','c'};
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include <stdio.h>
#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
#define MAXSIZE 40
typedef int Status;
typedef int ElemType;
/*
typedef char String[MAXSIZE + 1]; 定义了一种类型,类型的名字叫String,这种类型的结构是长度为MAXSIZE+1的char数组。
所以,String s1,s2;就是定义了s1,s2是两个char数组,等同于以下定义:
char s1[MAXSIZE+1];
char s2[MAXSIZE+1];
*/
//0号存储单元存放的是串的长度
typedef char String[MAXSIZE+1];
//生成一个其值为chars的字符串T
Status StrAssign(String T,char *chars)
{
int i;
if (strlen(chars)>MAXSIZE) {
return ERROR;
}else
{
T[0]=strlen(chars);
for (i=1;i<=T[0];i++) {
T[i]=*(chars+i-1);
}
return OK;
}
}
//通过S串复制得到T串
Status StrCopy(String T,String S)
{
int i;
for (i=0;i<=S[0];i++) {
T[i]=S[i];
}
return OK;
}
/*若S为空串,则返回TRUE,否则返回FALSE*/
Status StrEmpty(String S)
{
if(S[0]==0)
return TRUE;
else
return FALSE;
}
//若串S和T都存在的话,若S>T的话返回值就大于0,若S=T,则返回值=0,若S<T,则返回值小于0
int StrCompare(String S,String T)
{
int i;
for (i=1;i<=S[0]&&i<=T[0];++i) {
if (S[i]!=T[i]) {
return S[i]-T[i];
}
}
return S[0]-T[0];
}
//返回串的元素长度
int StrLength(String S)
{
return S[0];
}
//串S存在,操作结果就是S清为空串
Status ClearString(String S)
{
//将串的长度设置为零
S[0]=0;
return OK;
}
/* 用T返回S1和S2联接而成的新串。若未截断,则返回TRUE,否则FALSE */
Status Concat(String T,String S1,String S2)
{
int i = 0;
//如果两个串的长度加在一起小于MAXSIZE,直接拼接就好了
if (S1[0]+S2[0]<=MAXSIZE) {
for (i=1;i<=S1[0];i++) {
T[i]=S1[i];
}
for (i=1;i<=S2[0];i++) {
T[S1[0]+i]=S2[i];
}
T[0]=S1[0]+S2[0];
return TRUE;
}else
{
for (i=1;i<S1[0];i++) {
T[i]=S1[i];
}
for (i=1;i<=MAXSIZE-S1[0];i++) {
T[S1[0]+i]=S2[i];
}
T[0]=MAXSIZE;
return FALSE;
}
}
//用Sub返回串S的第pos个字符起长度为len的子串
Status SubString(String Sub,String S,int pos,int len)
{
int i;
//如果pos小于1或者大于串的长度或者len小于0,或者len比从pos个字符起的长度大
if (pos<1 || pos>S[0] ||len<0 || len>S[0]-pos+1) {
return ERROR;
}
for (i=1;i<=len;i++) {
Sub[i]=S[pos+i-1];
}
Sub[0]=len;
return OK;
}
//返回子串T在主串S中第pos个字符之后的位置。若不存在,则函数返回值为0
int Index(String S,String T,int pos)
{
/* i用于主串S中当前位置下标值,若pos不为1,则从pos位置开始匹配 */
int i = pos;
/* j用于子串T中当前位置下标值 */
int j = 1;
while (i<=S[0]&&j<=T[0]) {
//如果两个字母相等的话继续比较
if (S[i]==T[j]) {
++i;
++j;
}
else /* 指针后退重新开始匹配 */
{
i=i-j+2; /* i退回到上次匹配首位的下一位 */
j=1; /* j退回到子串T的首位 */
}
}
//这就说明已经成功匹配完成
if (j > T[0]) {
return i-T[0];
}
else
{
return 0;
}
}
//如果主串S中第pos个字符之后存在与T相等的子串,则返回第一个这样的子串在S中的位置,否则返回0 */
int Index2(String S,String T,int pos)
{
int n,m,i;
String sub;
if (pos>0) {
//获取S串的长度
n=StrLength(S);
m=StrLength(T);
i=pos;
while (i<=n-m+1) {
//取S主串当中第i个位置长度为m的子串
SubString(sub, S, i, m);
//进行比较,如果两个串不相等
if (StrCompare(sub,T)!=0) {
++i;
}
else
return i;
}
}
//表示没有子串和T相等,所以返回0
return 0;
}
/* 初始条件: 串S和T存在,1≤pos≤StrLength(S)+1 */
/* 操作结果: 在串S的第pos个字符之前插入串T。完全插入返回TRUE,部分插入指的是MAXSIZE是小于S[0]和T[0]的大小了,只插入T[0]的部分,返回FALSE */
Status StrInsert(String S,int pos,String T)
{
int i;
if (pos<1 || pos>S[0]+1) {
return ERROR;
}
//如果两个字符串的长度加在一起是小于等于最大长度的话就是完全插入的
if (S[0]+T[0]<=MAXSIZE) {
//把pos后面的给移动到i+T[0]这边
for (i=S[0];i>=pos;i--) {
S[i+T[0]]=S[i];
}
for (i=pos;i<pos+T[0];i++) {
S[i]=T[i-pos+1];
}
S[0]=S[0]+T[0];
return TRUE;
}
else
{
int len = MAXSIZE-S[0];
for (i=MAXSIZE;i>=pos; i--) {
S[i]=S[i-len];
}
for (i=pos; i<pos+len; i++) {
S[i]=T[i-pos+1];
}
S[0]=MAXSIZE;
return FALSE;
}
}
//从串S中删除第pos个字符起长度为len的子串
Status StrDelete(String S,int pos,int len)
{
int i;
//这里的pos>S[0]-len+1,S[0]是30,len如果是10的话,那么pos可以是从21开始正好到30是为10个字符
if (pos<1 || pos>S[0]-len+1 || len<0) {
return ERROR;
}
for (i=pos+len; i<=S[0];i++) {
S[i-len]=S[i];
}
S[0]-=len;
return OK;
}
//用V替换主串S中出现的所有与T相等的不重叠的子串
Status Replace(String S,String T,String V)
{
//从串S的第一个字符开始去查找串T
int i=1;
if (StrEmpty(T)) {
return ERROR;
}
do {
//如果Index函数的返回值为0的就说明没有早点
i = Index(S, T, i); /* 结果i为从上一个i之后找到的子串T的位置 */
if (i) /* 串S中存在串T */
{
//删除该串T
StrDelete(S, i, StrLength(T));
//在原串T的位置插入串V
StrInsert(S, i,V);
//在插入的串V后面继续查找串T
i+=StrLength(V);
}
} while (i);
return OK;
}
//输出字符串T
void StrPrint(String T)
{
int i;
for (i=1; i<=T[0]; i++) {
printf("%c",T[i]);
}
printf("\n");
}
对于串的链式存储,一个结点可以存储一个字符,当然也可以存储多个字符,这会影响串的处理的效率,我们需要去根据实际情况去做出选择