计算机上非数值处理的对象基本上是字符串数据,在较早的程序设计语言中,字符串是作为输入输出的常量出现。随着语言程序的加工和发展产生了字符串处理。但是现在我们用的计算机硬件结构主要反应的数值计算的需要。因此,在处理字符串数据时比处理整型数和浮点数要复杂的多,而且在不同的类型应用中,所处理的字符串具有不同的特点,要有效的实现字符串的处理,就必须更具具体情况使用合适的存储结构,如:定长顺序存储结构,堆分配存储结构,块链存储结构。定长顺序存储结构比较简单,我们就不单独讨论。本篇博客我们讨论一下堆分配存储结构的串
名词解释
名词 | 解释 |
---|---|
串 | 由零个或多个字符组成的有限序列 |
长度 | 串中字符的个数 |
空串 | 零个字符的串 |
子串 | 串中任一连续的字符组成的串 |
组串 | 包含了子串的的串相应的成为主串 |
位置 | 通常字符在串中的序列称为该字符在串中的位置 |
串的堆分配存储结构
typedef struct {
char *ch;
int length;
}HeapString;
基本操作
HeapString InitHeapStr();
Status HeapStrAssign(HeapString *hStr, char *chars);
int HeapStrLength(HeapString s);
int HeapStrCompare(HeapString hStr_1, HeapString hStr_2);
Status ClearHeapStr(HeapString *hStr);
Status SubHeapStr(HeapString hStr, HeapString *subStr, int pos, int length);
Status ConcatHeapStr(HeapString *desHStr, HeapString srcHStr_1, HeapString srcHStr_2);
Status HeapStrCopy(HeapString *desHStr, HeapString srcHStr);
void PrintHeapStr(HeapString hStr);
基本操作实现
初始化
HeapString InitHeapStr() {
HeapString hStr;
hStr.ch = NULL;
hStr.length = 0;
return hStr;
}
注意:在初始化一个串的时候一定要将ch
指向NULL
和串的长度标记为0
,不然在后续操作中判断ch
是否存在或者求串的长度出现问题
赋值
int StrLen(char *s) {
int length = 0;
while(s[length] != '\0') {
length++;
}
return length;
}
Status HeapStrAssign(HeapString *hStr, char *chars) {
if(hStr->ch) {
printf("test: hStr->ch");
free(hStr->ch);
}
hStr->length = 0;
int length = StrLen(chars);
if (!(hStr->ch = (char *)malloc(length * sizeof(char)))) {
printf("%s error : 内存溢出\n", __func__);
return OVERFLOW;
} else {
for (int i = 0; i < length; i++) {
hStr->ch[i] = chars[i];
hStr->length += 1;
}
return OK;
}
}
注意:在赋值之前需要先检测hStr->
是否被分配过内存,如果被分配过内存则需要先free
不然会造成内存泄漏
获取串的长度
int HeapStrLength(HeapString s) {
return s.length;
}
比较串的大小
int HeapStrCompare(HeapString hStr_1, HeapString hStr_2) {
if (hStr_1.length == hStr_2.length) {
return 0;
} else if (hStr_1.length > hStr_2.length) {
return 1;
} else {
return -1;
}
}
注意:这里的比较大小并不是比较串的长度,而已将两个串中的字符对应的ASCII
码进行逐一的比较,一旦遇到ASCII
码值不一样的就马上返回结果
清除字符串
Status ClearHeapStr(HeapString *hStr) {
if(hStr && hStr->ch) {
free(hStr->ch);
hStr->ch = NULL;
hStr->length = 0;
return OK;
} else {
printf("%s error : 参数错误\n", __func__);
return ERROR;
}
}
注意:清除分配空间的时候别忘记了更新串的长度
连接两个串
Status ConcatHeapStr(HeapString *desHStr, HeapString srcHStr_1, HeapString srcHStr_2) {
int length = srcHStr_1.length + srcHStr_2.length;
if (desHStr->ch) {
free(desHStr->ch);
desHStr->length = 0;
}
if (!(desHStr->ch = (char *)malloc(length * sizeof(char)))) {
printf("%s error : 内存溢出\n", __func__);
return OVERFLOW;
}
for (int i = 0; i < srcHStr_1.length; i++) {
desHStr->ch[i] = srcHStr_1.ch[i];
desHStr->length += 1;
}
for (int i = 0; i < srcHStr_2.length; i++) {
desHStr->ch[srcHStr_1.length+i] = srcHStr_2.ch[i];
desHStr->length += 1;
}
return OK;
}
获取子串
Status SubHeapStr(HeapString hStr, HeapString *subStr, int pos, int length) {
if (length <= 0 || pos <= 0 || hStr.length < length) {
printf("%s error : 参数错误\n", __func__);
return ERROR;
}
if (subStr->ch) {
free(subStr->ch);
subStr->length = 0;
}
if (!(subStr->ch = (char *)malloc(length * sizeof(char)))) {
printf("%s error : 内存溢出\n", __func__);
return OVERFLOW;
}
for (int i = 0; i < length; i++) {
subStr->ch[i] = hStr.ch[pos-1+i];
subStr->length += 1;
}
return OK;
}
注意:获取子串的时候操作位置和长度的异常处理
拷贝串
Status HeapStrCopy(HeapString *desHStr, HeapString srcHStr) {
if (desHStr->ch) {
free(desHStr->ch);
desHStr->length = 0;
}
if (!(desHStr->ch = (char *)malloc(srcHStr.length * sizeof(char)))) {
printf("%s error : 内存溢出\n", __func__);
return OVERFLOW;
}
for (int i = 0; i < srcHStr.length; i++) {
desHStr->ch[i] = srcHStr.ch[i];
desHStr->length += 1;
}
return OK;
}
注意:此处拷贝为深拷贝,不能简单的指针赋值
打印串信息
void PrintHeapStr(HeapString hStr) {
printf("HeapString info\n\tch:");
for (int i = 0; i < hStr.length; i++) {
printf("%c", hStr.ch[i]);
}
printf("\n\tlen: %d \n", hStr.length);
}
欢迎讨论
Email:[email protected]
Github:https://github.com/LHCoder2016/DataStructure