和上一篇定长度顺序实现差不多,都是用一块连续的内存地址来存储字节数据,唯一不同的在于堆串的内存是动态申请的,利用了C语言中的malloc、free、realloc函数。此类函数管理了内存中一块儿叫做自由存储区——”堆“的地方。因此该种形式的串实现被称作堆串。
实现思路和定长的静态串差不多。
在实现中遇到的问题:
1.静态串中第一个元素存储的是该串的总长度,后续的内存用来存内容。因此,真正的字符串顺序和其在数组中的下标一致。而在堆串之中,用一个结构体来表示堆串类型,结构体中有描述堆串长度的量,故在堆串中数组下标和字符序数会相差1。在实现时应当注意这一点。
2.由于堆串中Concat的实现特点,不能直接进行Concat(&S,S,T)的操作。 需要一个临时变量tmp,首先进行Concat(&tmp,S,T),然后StrCopy(&S,tmp)来完成和静态串中Concat(&S,S,T)相同的效果。具体请看实现。
HeapString.h头文件
#ifndef HEAPSTRING_H_INCLUDED
#define HEAPSTRING_H_INCLUDED
//串的堆分配主要依靠malloc和rellaoc以及free等函数实现
//在C语言中,存在一个称为”堆“的自由存储区,并由malloc()和free()来管理。
//若空间分配成功,返回的地址作为串的基址,当空间超过时
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include"Status.h"
//PS:在堆串中,串描述主体为一结构体
typedef struct
{
char* ch; //串的基地址
int length; //串的长度
}HString;
//函数列表
void InitString_H(HString* S);
//初始化S为空串
Status StrAssign_H(HString *T, char* chars);
//生成一个其值等于常量chars的串T
Status StrCopy_H(HString *T,HString S);
//由串S复制得到串T
Status StrEmpty_H(HString S);
//判空
Status StrCompare_H(HString S,HString T);
//比较字符串,若S>T,返回1 若S==T,返回0 若S<T,返回-1
int StrLength_H(HString S);
//求串长
Status ClearString_H(HString *S);
//清空
Status Concat_H(HString* T , HString S1 , HString S2);
//用T返回由S1和S2链接而成的新串
Status SubString_H(HString* Sub,HString S,int pos,int len);
//返回子串
int Index_H(HString S,HString T,int pos);
//返回从pos开始第一次子串T出现的序号,找到则返回0
Status Replace_H(HString *S,HString T ,HString V);
//用V来替换S中所有的不重叠的T子串
Status StrInsert_H(HString *S,int pos,HString T);
//在第pos个位置之前插入子串T
Status StrDelete_H(HString* H,int pos , int len);
//删除第pos个位置开始的len个字符
void DestroyString_H(HString* S);
//销毁
void ShowString_H(HString S);
//打印串
#endif // HEAPSTRING_H_INCLUDED
具体实现:HeapString.c
#include"HeapString.h"
void InitString_H(HString* S)
{
(*S).ch = NULL;
(*S).length = 0;
}
Status StrAssign_H(HString *T, char* chars)
{
int charsLength = strlen(chars);
(*T).ch = (char*)malloc(sizeof(char)*charsLength);
if(!((*T).ch))
{
return ERROR;
}
int i;
for( i=0; i<charsLength; i++)
{
(*T).ch[i] = chars[i];
}
(*T).length = charsLength;
return SUCCESS;
}
Status StrCopy_H(HString *T,HString S)
{
(*T).length = S.length;
(*T).ch = (char*)malloc(S.length*sizeof(char));
if(!(*T).ch)
{
printf("未申请到堆空间!\n");
return ERROR;
}
int i;
for(i = 0;i<S.length;i++)
{
(*T).ch[i] = S.ch[i];
}
return SUCCESS;
}
Status StrEmpty_H(HString S)
{
if(S.length == 0)
{
return YES;
}
else
{
return FALSE;
}
}
Status StrCompare_H(HString S,HString T)
{
int count = 0;
while(count<S.length&&count<T.length&&S.ch[count]==T.ch[count])
{
count++;
}//循环退出情况:超过任意一个字符串的长度、当下的两个字符比较不相等
if(count==T.length&&count == S.length)
{
return 0;
}
if(count==T.length)
{
return 1;
}
if(count == S.length)
{
return -1;
}
if(S.ch[count]>T.ch[count])
{
return 1;
}
else
{
return -1;
}
}
Status ClearString_H(HString *S)
{
(*S).length = 0;
(*S).ch = (char *)realloc((*S).ch,0); //是否能够直接释放已经分配的所有空间呢?
return SUCCESS;
}
Status Concat_H(HString* T , HString S1 , HString S2)
{
int i = 0;
(*T).length = S1.length + S2.length;
(*T).ch = (char*)malloc((S1.length+S2.length)*sizeof(char));
for( ; i<S1.length ; i++)
{
(*T).ch[i] = S1.ch[i];
}
for( ; i<(*T).length ; i++)
{
(*T).ch[i] = S2.ch[i-S1.length];
}
return SUCCESS;
}
Status SubString_H(HString* Sub,HString S,int pos,int len)
{
if(pos+len-1 > S.length)
{
printf("主串没有这么长!\n");
return ERROR;
}
(*Sub).length = len;
(*Sub).ch = (char*)malloc(sizeof(char)*len);
if((*Sub).ch == NULL)
{
printf("分配内存失败!\n");
return ERROR;
}
int i = pos - 1;
for( ; i<=pos-1+len-1; i++)
{
(*Sub).ch[i-pos+1] = S.ch[i];
}
return SUCCESS;
}
int Index_H(HString S,HString T,int pos) //注意:该函数返回下标
{
int i = pos - 1;
HString Sub;
if(T.length > S.length - pos +1)
{
printf("待寻子串不能长于目标主串!\n");
return -1;
}
for ( ;i <= S.length - T.length ;i++ ) //从pos-1位置一直到最后能到达的位置
{
SubString_H(&Sub,S,i+1,T.length);
if(!StrCompare_H(Sub,T))
{
return i;
}
}
return -1;
}
Status StrInsert_H(HString *S,int pos,HString T)
{
HString tmp ;
SubString_H(&tmp,*S,1,pos-1); //先生成前面的字符串
HString tmp1;
Concat_H(&tmp1,tmp,T);
ClearString_H(&tmp); //将临时变量置空以重用
HString tmp2;
SubString_H(&tmp,*S,pos,(*S).length-pos+1);
Concat_H(&tmp2,tmp1,tmp);
StrCopy_H(S,tmp2);
DestroyString_H(&tmp2);
DestroyString_H(&tmp1);
DestroyString_H(&tmp);
}
Status Replace_H(HString *S,HString T ,HString V)
{
HString tmp,stringTmp;
InitString_H(&tmp);
HString tmp1;
int i = 1 , qi = 1;
while(1)
{
i = Index_H(*S,T,qi)+1; //注意:index返回的是下标,这里让其增加1返回为序数
if(i == 0)
{
SubString_H(&stringTmp,*S,qi,(*S).length-qi+1);
Concat_H(&tmp1,tmp,stringTmp);
StrCopy_H(&tmp,tmp1);
ClearString_H(&tmp1);
StrCopy_H(S,tmp);
return SUCCESS;
}
SubString_H(&stringTmp,*S,qi,i-qi);
ShowString_H(stringTmp);
Concat_H(&tmp1,tmp,stringTmp);
StrCopy_H(&tmp,tmp1);
ClearString_H(&tmp1);
Concat_H(&tmp1,tmp,V);
StrCopy_H(&tmp,tmp1);
ClearString_H(&tmp1);
i = i+ T.length; //i指向下一个pos
qi = i;
}
}
Status StrDelete_H(HString* S,int pos , int len)
{
HString tmp,stringTmp;
HString tmp1; // 中间变量
InitString_H(&tmp);
SubString_H(&stringTmp,*S,1,pos-1);
Concat_H(&tmp1,tmp,stringTmp);
StrCopy_H(&tmp,tmp1);
ClearString_H(&tmp1);
SubString_H(&stringTmp,*S,pos+len,(*S).length-pos-len+1);
Concat_H(&tmp1,tmp,stringTmp);
StrCopy_H(&tmp,tmp1);
ClearString_H(&tmp1);
StrCopy_H(S,tmp);
}
void ShowString_H(HString S)
{
if(S.length == 0)
{
printf("S is empty! Nothing to show!\n");
return ;
}
int i;
for( i=0 ; i<S.length ; i++)
{
printf("%c",S.ch[i]);
}
printf("\n");
}
void DestroyString_H(HString* S)
{
ClearString_H(S);
free(&((*S).length));
free(S);
}
具体的测试函数大家可以自己写一写,欢迎大家使用该实现方法,如有bug请及时联系我。