前面已经完成了线性表、栈、队列等线性表的学习与实现,今天终于完成了线性结构中另一重要的数据结构----串(string),来和大家分享一下,共同进步。
串,又称字符串。
其实串就是由一个或多个字符组成的字符序列,使用串可以方便地存储我们想要存储的一切信息。
假如我们现在需要存储某个同学的具体姓名、某个名人名言、某个段落、某篇文章,这些信息中既包含有数字信息、英文信息、中文信息、标点符号、特殊符号等,我们此时就可以用 串(string) 来进行存储了。
串拥有很多操作方法,如初始化字符串、拷贝字符串、检索字符串、截取字符串、连接字符串、插入字符串、删除字符串、替换字符串、比较字符串等,使用这些方法可以很方便地对字符串进行各种操作,实现用户的需要。
串可以分为顺序串和堆串。
顺序串采用字符数组进行实现,由于采用字符数组需要预先开辟一个固定的存储空间,而且不易拓展,所以这篇文章暂时不为大家推荐顺序串,顺序串具体的代码我一会分享给大家。
堆串采用堆的方法动态地为串的内容开辟内存空间,能够有效的节约内存资源,并有益于串的扩展操作和兼容操作,便于用户操作。
下面是串的具体实现代码,如果有小伙伴有不理解的地方或者疑虑,欢迎留言评论~
串的定义
#include<stdio.h>
#include<stdlib.h>
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2
#define STRING_INIT_SIZE 100
//定义字符串 string 类型
typedef struct StringNode{
char *content; //字符串内容 content
int length; //字符串长度 length
}*String;
所有方法的声明
int initString(String &string); //初始化线性化结构 串(string)
int destroyString(String &string); //销毁字符串string
int isEmptyString(String &string); //判断是否为空串
int strLength(String &string); //返回字符串的长度
void printString(String &string); //打印字符串string
int clearString(String &string); //清空字符串
int assignString(String &string, char chars[]); //生成一个值为常量为chars的字符串string
int copyString(String &string, String s); //拷贝字符串,将字符串s拷贝赋值给string
int compareString(String &string, String s); //对比两个字符串,若string>s,返回>0,相等返回0,否则返回<0
int concatString(String &string, String s1, String s2); //将s1和s2连接的新串赋值给string
int subString(String &string, String &s, int pos, int len); //截取字符串,以s串返回string字符串第pos开始len个长度的串
int indexString(String &string, String s, int pos); //检索字符串,返回string串第pos位置后第一次和s串相同子串的开始位置,否则返回0
int replaceString(String &string, String s1, String s2); //替换字符串,以串s2替换掉string串中所有的串s1
int insertString(String &string, String s, int pos); //插入字符串,将子串s插入到string字符串的第pos个位置
int deleteString(String &string, int pos, int len); //删除字符串,删除string字符串中第pos个位置开始,长度为n的字串
初始化字符串数据类型
//使用字符数组对串进行初始化
int assignString(String &string, char chars[])
{
int i, j;
char *p = chars; //定义一个字符指针指向字符数组
while(*p != '\0' && *p != '\n') //循环统计字符数组长度
{
p++;
i++; //计数器累加
}
string->content = (char *)malloc(i*sizeof(char)); //动态地为串的内容开辟相应地内存空间存储串信息
string->length = i; //设置串的长度
for(j = 0; j < i; j++)
{
string->content[j] = chars[j]; //将字符数组内容复制给串的内容
}
string->content[j] = '\0'; //字符串内容的最后一位设置为字符结束符
return OK; //返回结果
}
拷贝字符串
//复制字符串,将字符串s的内容复制给string
int copyString(String &string, String s)
{
int length = s->length; //记录字符串s的长度
if(length == 0) //若字符串的长度为0,则直接清空string串,返回
{
clearString(string);
return OK;
}
else //否则
{
//根据新的内容使用realloc()函数重新为串string开辟内容空间
string->content = (char *)realloc(string->content, length*sizeof(char));
char *p = s->content, *q = string->content; //定义p指针指向s内容,q指针指向string内容
while(*p != '\0' && *p != '\n') //使用p指针重复读取s之中的内容,直至s串结束
{
*q = *p; //将p指针中的内容赋值给q指针指向的内容,进行复制
p++;
q++; //p、q指针累加,指向串中的下一内容
}
*q = '\0'; //复制完毕,q指针指向的string串以'\0'结束
string->length = s->length; //更新串string的长度
return OK; //返回结果
}
}
比较字符串
//对两个字符串string和s进行比较,
//若string > s,返回 > 0;
//若string < s,返回 < 0;
//否则返回0
int compareString(String &string, String s)
{
//循环比较string串和s串,当string和s的第一个字符相等时,比较第2个,再相等比较第3个...,直至string串或s串结束
for(int i = 0; i < string->length && i < s->length; i++)
{
if(string->content[i] != s->content[i]) //若两个串的某个位置的字符串不等
return string->content[i] - s->content[i]; //返回它们的差值,即为结果(ASCLL码)
}
return string->length - string->length; //若持续相等,返回它们的长度的差值
}
连接字符串
//将字符串s1和字符串s2连接成为新的字符串string
int concatString(String &string, String s1, String s2)
{
int length = s1->length + s2->length, i; //记录s1和s2字符串长度之和
string->content = (char *)realloc(string->content, length*(sizeof(char))); //重新为string串内容开辟此长度的空间
//通过循环的方式连接两个字符串
for(i = 0; i < length; i++)
{
if(i < s1->length) //若 i < s1的长度,则先添加s1字符串内容
string->content[i] = s1->content[i];
else //之后再添加s2字符串的内容
string->content[i] = s2->content[i-(s1->length)];
}
string->content[i] = '\0'; //连接形成的新的字符串string以'\0'结束
string->length = length; //更新字符串string的长度
return OK; //返回结果
}
截取字符串
//截取字符串,把string字符串的第pos个位置开始,长度为len的子字符串截取下来,赋值给s返回
int subString(String &string, String &s, int pos, int len)
{
if(pos < 1 || pos > string->length || len < 0 || len > string->length+1)
return ERROR; //若截取参数有误,直接返回错误信息
int i = 0; //定义计数器
s->content = (char *)malloc(len*sizeof(char)); //动态为s字符串开辟长度为len的字符串内容
s->length = len; //并设置字符串的长度
//从字符串的第pos个位置开始,循环进行截取内容
for(i = pos-1; i < pos-1+len; i++)
{
s->content[i-(pos-1)] = string->content[i]; //截取内容赋值给s字符串
}
s->content[i-(pos-1)] = '\0'; //为s字符串的最后字符'\0'作为字符串结束标志
return OK; //返回结果
}
插入字符串
//在字符串string的第pos个位置插入新的字符串s
int insertString(String &string, String s, int pos)
{
if(s->length == 0 || pos < 1 || pos > string->length+1)
return ERROR; //若插入参数有误,直接返回错误信息
int length = string->length + s->length; //对插入的长度进行增加保存
int i = 0;
String new_string; //定义新的new_string字符串准备接收
initString(new_string); //初始化new_string字符串
new_string->content = (char *)malloc(length*sizeof(char)); //动态为该字符串开辟长度为length的空间
//循环通过3段连接的方式进行字符串的添加,暂添加至new_string
for(i = 0; i < length; i++)
{
if(i < pos-1)
new_string->content[i] = string->content[i]; //添加pos之前string字符串的内容
else if(i >= pos-1 && i < pos - 1 + s->length)
new_string->content[i] = s->content[i-(pos-1)]; //添加s字符串的内容
else
new_string->content[i] = string->content[i-s->length]; //添加pos位置之后string字符串的内容
}
new_string->content[i] = '\0'; //字符串new_string内容以'\0'结束标志
new_string->length = length; //设置字符串长度
copyString(string, new_string); //进行字符串复制,即此时string便是已成功插入的字符串
return OK; //返回结果
}
删除字符串
//删除字符串string从第pos个位置开始,长度为len的子串
int deleteString(String &string, int pos, int len)
{
if(pos < 1 || pos > string->length || len < 1 || pos - 1 + len > string->length)
return ERROR; //若删除参数有误,直接返回错误信息
int i,j;
String new_string; //同插入字符串操作,定义新的字符串new_string
initString(new_string); //初始化字符串
new_string->content = (char *)malloc((string->length-len)*(sizeof(char))); //为新的字符串内容动态开辟空间
//循环通过2段字符串的连接进行子串的删除
for(i = 0, j = 0; i < string->length; i++)
{
if(i < pos-1)
new_string->content[j++] = string->content[i]; //添加pos位置之前的string串的内容
if(i >= pos-1+len)
new_string->content[j++] = string->content[i]; //添加pos-1+len位置之后string串的内容,便实现删除
}
new_string->content[j] = '\0'; //字符串new_string内容以'\0'结束标志
new_string->length = string->length-len; //设置字符串的长度
copyString(string, new_string); //进行字符串复制,即此时string便是已成功删除子串的字符串
return OK; //返回结果
}
替换字符串
//字符串替换操作,将string串中所有s1子串替换为s2子串
int replaceString(String &string, String s1, String s2)
{
if(string->length == 0) //string为空串,直接返回
return ERROR;
if(indexString(s2, s1, 1) != 0) //s2中包含s1子串,会造成递归无限替换,直接返回
return ERROR;
for(int i = 0; i < string->length; i++) //循环检索所有的情况
{
int j = indexString(string, s1, i+1); //从第i+1个位置后检索string串是否包含s1串,若包含,返回子串开始位置
if(j > 0) //若包含
{
deleteString(string, j, s1->length); //删除string中的从j位置开始的子串 s1
insertString(string, s2, j); //添加子串s2 到字符串string的第j个位置,替换成功
}
}
return OK; //返回结果
}
检索字符串
//从第pos个位置开始,检索string中是否包含子串s,若包含返回第一次发现子串的起始位置,否则返回0
int indexString(String &string, String s, int pos)
{
if(pos > string->length)
return ERROR; //若pos位置有误,直接返回
String new_string;
initString(new_string); //定义并初始化新的字符串new_string
for(int i = pos-1; i < string->length; i++) //从第pos个位置循环检索每一个子串
{
subString(string, new_string, i+1, s->length); //截取string串中的每个子串
if(compareString(new_string, s) == 0) //若该子串和子串s相等,说明检索成功
return i+1; //返回该子串的起始位置
}
return FALSE; //否则,返回false,即0
}
字符串判空、清空、销毁、打印字符串
//判断字符串string是否为空串
int isEmptyString(String &string)
{
if(string->length == 0)
return TRUE; //空串返回1
else
return FALSE; //否则返回0
}
//返回字符串string的长度,冗余操作
int strLength(String &string)
{
return string->length;
}
//清空字符串string
int clearString(String &string)
{
free(string->content); //释放string字符串内容空间
string->content = NULL; //设置string内容空间为NULL
string->length = 0; //设置string内容长度为0
return OK; //返回结果
}
//销毁字符串string
int destroyString(String &string)
{
clearString(string); //清空字符串string
free(string); //释放字符串string空间
string = NULL; //字符串string为NULL
return OK; //返回结果
}
//打印字符串string
void printString(String &string)
{
printf("字符串的内容为:\n");
printf("%s\n", string->content);
printf("长度---->%d.\n", string->length);
return;
}
好啦,明天有空再把串的顺序实现代码分享给大家,加油~