数据结构---05---堆串---20205106009---郭睿玥
/*郭睿玥第五次算法实验作业*/ /*实验原理 串的堆存储结构,与定长顺序串的存储结构类似,都是用一维数组地址连续的存储单元存储串 的字符序列,不同的是堆串的存储空间是在程序执行过程中动态分配的。 在系统中存在一个称为“堆”的自由存储区,每当建立一个新串时,可以通过动态分配函数从 这个空间中分配一块实际串所需的存储空间,来存储新的串值。只要空间能分配成功,则在操作的 过程中就不会发生“截断”的情况。C语言采用malloc()、free()等函数完成动态存储管理。 */ /*实验环境 CodeBlocks*/ /*实验目的 1. 了解顺序串的结构特点及有关概念; 2. 理解顺序串的存储结构; 3. 掌握顺序串的基本操作算法。 */ /*实验内容 建立顺序串,完成顺序串的基本操作:初始化、求串长、串赋值、串连接、求子串、串比较、字串定位、串插入、子串删除、串替换、串清空、串输出等。 */ #include<stdio.h> #include<string.h> #include<stdlib.h> #define MAXSIZE 100 typedef int Status;// 定义函数返回值类型 typedef char ElemType; // 定义每条数据的结构体类型 typedef struct{//定义串 char *stri;//若不是空串则按照串长度分配空间,否则为NULL int length;//串长 }string;//别名 Status insitstring(string * SS){//初始化 SS->stri =NULL;//空串不分配空间 SS->length = 0;//空串串长为0 return 1; } Status lengthstring(string * SS)//求串长 { return SS->length;//返回SS的元素个数,串长度包含在数据结构中因此直接返回即可 } void StrAssign(string *SS,char str1[])//串赋值 { int i,j; if (SS->length)//如果不是空串则清空需要赋值的串 free(SS); //清空操作 for(i=0;str1[i]!=NULL;i++)//循环查找所要赋值的字符数组,直到字符数组的某个元素为空,循环次数就是串长度 { ; } SS->length=i;//串长度赋值 if(i){ SS->stri=(char*)malloc(SS->length*sizeof(char*));//根据串长度申请空间 if(!SS->stri)//如果分配失败则结束 exit(-1);//退出 for(j=0;j<SS->length;j++)//通过循环逐个元素赋值,j表示循环次数,也表示被赋值的元素下标 { SS->stri[j]=str1[j];//赋值操作 } } else {//如果输入的字符数组不合理则重新输入 printf("请重新输入\n");//提示 char ch1[MAXSIZE];//新建数组 gets(ch1);//输入 StrAssign(SS,ch1);//递归调用赋值函数 } return 0;//程序结束返回 } void printstring(string T)//串输出 { int i; for(i=0;i<T.length;i++)//通过循环逐个元素输出,i表示循环次数,也表示被赋值的元素下标 printf("%c",T.stri[i]);//输出元素的值 printf("\n");//换行 } Status constring(string *SS,string *S)//串连接 { int i,j; SS->stri=(char*)realloc(SS->stri,(SS->length+S->length )*sizeof(char));//根据需要连接的两个穿分配空间 if(!SS->stri)//如果分配失败则结束 { printf("分配空间失败");//提示 exit(-1);//退出 } else{//如果成功,则通过循环,按照顺序一个个把S的元素增加到SS内,i表示S下标,j表示SS下标 for(i=0,j=SS->length;i<S->length;i++,j++)//循环,一共执行S->length次 SS->stri[j]=S->stri[i];//赋值 SS->length+=S->length;//改变串长 } return 1;//返回 } Status comparestring(string * SS,string *S)//串比较 { int i,j; if(SS->length!=S->length)//首先比较串长,如果两个串的串长不一致比较无意义,故不进行比较 { printf("两个串的长度不一致无法比较\n");//提示 return 5;//返回 } for(i=0;i<SS->length;i++)//通过循环,按照顺序逐个比较知道找到第一个两个串不一样的元素 { if(SS->stri[i]>S->stri[i])//如果SS的第i个元素大,则返回1 return 1; if(SS->stri[i]<S->stri[i])//如果S的第i个元素大,则返回 return -1; //如果两个一样大则循环继续 } return 0; } void clearstring(string * SS)//串清空 { if (SS->stri)//如果不是空串则清空需要赋值的串 free(SS);//清空操作 insitstring(SS);//调用初始化函数 printf("清空成功");//提示 return 0;//返回 } Status emptystring(string * SS)//串判空 { if (SS->length = 0) //空串的串长为0可以直接判断 return 0; //空串返回0 return 1;//非空串返回1 } Status insertstring(string * SS,string * S,int pos)//串插入 { if(pos < 0||pos-1>SS->length)//判断插入位置是否合法 { printf("插入位置不正确\n");//提示 return 0;//由于插入的位置不合法故函数无法进行 } int i=SS->length-1,j=i+S->length,k; SS->stri=(char*)realloc(SS->stri,(SS->length+S->length )*sizeof(char));//根据需要连接的两个穿分配空间 if(!SS->stri)//如果分配失败则结束 { printf("内存分配失败");//提示 exit(-1);//退出 } for(k=0;k<SS->length-pos+1;i--,j--,k++)//通过循环,从后往前一直到要插入的位置的串元素依次后移 SS->stri[j]=SS->stri[i];//后移操作 for(i=0,j=pos-1;i<S->length;i++,j++)//通过循环,从要插入串的位置开始,依次赋值 SS->stri[j]=S->stri[i];//赋值 SS->length=SS->length+S->length;//改变串长 printf("插入后的串为");//提示 printstring(*SS);//调用输出函数输出插入后的串 return 0; } Status findstring(string * substr,string SS,int pos,int len)//截取子串 { int i; if(!substr->stri)//如果不是空串则清空串 free(substr->stri);//清空操作 else { substr->stri=(char*)malloc(len*sizeof(char));//为子串分配空间 if(!substr->stri)//如果分配失败则结束 { printf("存储分配失败");//提示 exit(-1);//退出 } for(i=0;i<len;i++)//通过循环,从需要截取子串的位置开始,按照参数中的len截取子串 substr->stri[i]=SS.stri[i+pos-1];//逐个元素截取 substr->length=len;//子串长度就是参数中的len return 1;//返回 } } Status searchsub(string * SS,string substr)//子串定位 { int i=1,j=0,k; do{ if(substr.stri[0]==SS->stri[j])//如果SS中存在子串则substr的第一个元素一定和ss的某个元素相等,如果相等往下比较,不相等ss后移 { k=j+1; while(i<substr.length)//通过循环判断串的第i+1到第i+1+substr.length个元素的值是不是都和substr串一致 { if(substr.stri[i]!=SS->stri[k])//如果当前元素和子串的元素不一致则跳出循环 { i=1;//返回初始状态方便下一次判断 j++;//j后移 break;//跳出循环 } else {//如果一直接着判断下一个元素 i++; k++; } } if(i==substr.length)//判断是否进行完毕 break;//循环结束 } else j++;//如果SS中的第j个元素和子串中第0个元素不等则j后移 }while(j<SS->length);//循环条件 if(j==SS->length)//如果j能等于SS的串长则没有这个子串 { printf("没有这个子串");//提示 return -1;//返回 } printf("字串位于第%d\n",j+1);//输出子串位置 return j+1;//返回子串位置 } void deletesub(string* SS,string substr,int pos)//子串删除 { int i,len; char *p;//定义一个指针 len=substr.length; if(pos<0||len<0||pos+len-1>SS->length)//判断删除位置是否合法 { printf("删除位置不正确\n");//提示 return 0;//由于删除的位置不合法故函数无法进行 } p=(char*)malloc(SS->length-len);//根据需要删除的子串分配空间 if(!p)//如果分配失败则结束 exit(-1);//退出 for(i=0;i<pos-1;i++)//将串第pos位置之前的字符复制到p中 p[i]=SS->stri[i]; for(i = pos-1;i < SS->length-len;i++)//将串第pos+len位置以后的字符复制到p中 p[i] = SS->stri[i+len];//逐个元素复制 SS->length=SS->length-len;//修改串的长度 free(SS->stri);//释放原来的串S的内存空间 SS->stri=p;//将串的str指向p字符串 return 1;//返回 } void repalcesub(string * SS,string substr,string*S)//串替换,用S替换串SS中的所有子串substr { int i=0,j; if(substr.length==0)//判断要替换的串是否是空串 return 0;//返回 do{//通过循环替换所有子串 i=searchsub(SS,substr);//通过调用定位函数找到子串位置 if(i==-1)//如果没有这个子串结束 return 0;//返回 insertstring(SS,S,i);//在找到的位置里插入要替换的子串 j=i+S->length;//j表示要被替换子串当前的位置 deletesub(SS,substr,j);//根据位置删除要被替换的子串 printf("现在s1为");//提示 printstring(*SS);//输出替换后的SS }while(i!=-1); } int main() { char ch[MAXSIZE]; string S1,S2,sub;//建立两个串 int postion,length;//位置和长度 printf("请输入S1\n");//提示 gets(ch);//输入S1的串数据 insitstring(&S1);//初始化S1 StrAssign(&S1,ch);//用输入的字符数组为S1赋值 printf("请输入S2\n");//提示 gets(ch);//输入S2的串数据 insitstring(&S2);//初始化S2 StrAssign(&S2,ch);//用输入的字符数组为S1赋值 printf("s1为");//提示 printstring(S1);//输出S1 printf(",长度为%d\n",lengthstring(&S1));//输出S1长度 printf("s2为");//提示 printstring(S2);//输出S2 printf(",长度为%d\n",lengthstring(&S2));//输出S2长度 if(comparestring(&S1,&S2)==0)//通过比较函数的返回值比较S1,S2是否相等 printf("两者相等\n");//提示 if(comparestring(&S1,&S2)==1)//通过比较函数的返回值比较S1,S2是否相等 printf("s1大\n");//提示 if(comparestring(&S1,&S2)==-1)//通过比较函数的返回值比较S1,S2是否相等 printf("s2大\n");//提示 //有关插入的一系列操作 printf("请输入你想插入的位置\n");//提示 scanf("%d",&postion);//输入位置 insertstring(&S1,&S2,postion);//调用插入函数 //有关连接的一系列操作 constring(&S1,&S2);//调用连接函数 printf("连接后的子串为");//提示 printstring(S1);//输出S1 printf(",长度为%d\n",lengthstring(&S1));//输出S1现在长度 //有关截取子串的一系列操作 printf("截取子串\n");//提示 printf("请输入截取子串的位置\n");//提示 scanf("%d",&postion);//输入要截取的起始位置 printf("请输出字串长度\n");//提示 scanf("%d",&length);//输入要截取的长度 while(postion<0||length<0||postion+length-1>S1.length)//判断截取的子串是否合法 { printf("无法插入请重新输入\n");//提示 printf("请输入截取子串的位置\n");//提示 scanf("%d",postion);//重新输入位置 printf("请输出字串长度\n");//提示 scanf("%d",length);//重新输入长度 } findstring(&S2,S1,postion,length);//调用截取子串函数 printf("该字串为");//提示 printstring(S2); //有关子串删除的一系列操作 printf("字串删除\n");//提示 printf("首先,字串定位\n");//提示 postion=searchsub(&S1,S2);//调用函数寻找第一个子串位置 deletesub(&S1,S2,postion);//根据刚才的位置删除子串 printf("现在s1为");//提示 printstring(S1);//输出现在的S1 //有关子串替换的一系列操作 printf("把S1的子串替换为\n");//提示 gets(ch);//输入要替换的数据 insitstring(&sub);//初始化sub StrAssign(&sub,ch);//赋值 printf("替换为\n");//提示 printstring(sub);//打印子串 repalcesub(&S1,S2,&sub);//调用替换子串函数 return 0; } /*实验结果 请输入S1 ILIKECHINA 请输入S2 CHINA s1为ILIKECHINA ,长度为10 s2为CHINA ,长度为5 两个串的长度不一致无法比较 两个串的长度不一致无法比较 两个串的长度不一致无法比较 请输入你想插入的位置 4 插入后的串为ILICHINAKECHINA 连接后的子串为ILICHINAKECHINACHINA ,长度为20 截取子串 请输入截取子串的位置 4 请输出字串长度 4 该字串为CHIN 字串删除 首先,字串定位 字串位于第4 现在s1为ILIAKECHINACHINA 把S1的子串替换为 请重新输入 abc 替换为 abc 字串位于第7 插入后的串为ILIAKEabcCHINACHINA 现在s1为ILIAKEabcACHINA 字串位于第11 插入后的串为ILIAKEabcAabcCHINA 现在s1为ILIAKEabcAabcA 没有这个子串 */