前言
堆分配順序串實際上就是動態分配內存的順序存儲結構。它與定長順序串的區別是:它的串長度可以任意變換,並且不需要預先分配內存。
我們這次額外使用一個變量來保存串的長度,使用char *類型來保存串的實際內容,因此設計出來一個結構體
typedef struct HString{
//空間
char *ch;
//長度
int length;
}HString;
堆分配順序串的初始化
堆分配順序串的初始化包括兩個部分,第一是把空間的指針初始化爲空,第二是把串長初始化爲0。
void InitString(HString *s){
//初始化指針爲空
s->ch = NULL;
//長度爲0
s->length = 0;
}
堆分配順序串的賦值
在給堆分配順序串賦值時,首先需要得到要賦值的串的長度,然後去申請對應長度的空間。假設這個串是已經賦過值的,就需要把舊空間釋放掉,換成新的空間。因爲這個步驟在多個方法中都存在,我們可以額外寫一個GetNewSpace方法專門進行如上操作。
void GetNewSpace(HString *s,int len){
//判斷原來的空間是否開闢過
if (s->ch != NULL) {
//先釋放掉原來的空間
free(s->ch);
}
//新開闢一個空間
s->ch = (char*)malloc(sizeof(char)*len);
assert(s->ch != NULL);
}
這樣在賦值時,直接調用方法獲得新空間,然後依次賦值即可。
//賦值
void StrAssign(HString *s,char *str){
//獲取要賦值的串的長度
int len = (int)strlen(str);
GetNewSpace(s, len);
//賦值
for (int i = 0; i < len; i ++) {
s->ch[i] = str[i];
}
//長度
s->length = len;
}
堆分配順序串的連接
假設要連接串s1和串s2,並用串t來保存,因爲是動態分配的空間,所以不需要考慮能否存得下的問題。只需要讓t申請長度爲 s1_len + s2_len 的空間,然後直接依次賦值即可。
//鏈接
void StrConcar(HString *t,HString *s1,HString *s2){
int len1 = StrLength(s1);
int len2 = StrLength(s2);
GetNewSpace(t, len1+len2);
//先拷貝s1
for(int i = 0; i < len1; i ++){
t->ch[i] = s1->ch[i];
}
for (int j = 0; j < len2; j ++) {
t->ch[len1 + j] = s2->ch[j];
}
t->length = len1+len2;
}
堆分配順序串的插入
假設有串s,需要在pos位置上插入一個子串t,因爲是對原有字符串進行的變化,所以不需要調用GetNewSpace方法,而是使用realloc方法,在原有的空間基礎上,去重新開闢一個 s_len + t_len 的空間。
void StrInsert(HString *s,int pos,HString *t){
if (pos<0 || pos>s->length) {
printf("要插入的位置非法\n");
return;
}
//需要增大空間
char *ch = (char*)realloc(s->ch, sizeof(char)*(s->length+t->length));
assert(ch != NULL);
s->ch = ch;
int index = 0;
for (int i = pos; i < pos+t->length; i ++) {
s->ch[i + t->length] = s->ch[i];
s->ch[i] = t->ch[index];
index ++;
}
s->length += t->length;
}
全部代碼
HString.h
#ifndef HString_h
#define HString_h
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
typedef struct HString{
//空間
char *ch;
//長度
int length;
}HString;
void InitString(HString *s);
//重新開闢空間
void GetNewSpace(HString *s,int len);
//賦值
void StrAssign(HString *s,char *str);
//展示
void PrintString(HString *s);
//拷貝(將t串拷貝到s串來
void StrCopy(HString *s,HString *t);
//判空:0->非空 !0->空
int StrEmpty(HString *s);
//比較(若s>t 返回值>0 s==t 返回值==0 s<t 返回值<0
//依次取出對應位置的字符,以ASCII碼值進行比較
int StrCompare(HString *s,HString *t);
//求長度
int StrLength(HString *s);
//鏈接
void StrConcar(HString *t,HString *s1,HString *s2);
//求子串(在s串中從pos位置開始求長度爲len的子串,並保存到sub串中
void SubString(HString *s,HString *sub,int pos,int len);
//插入(將t串從pos位置起插入到s串中
void StrInsert(HString *s,int pos,HString *t);
//刪除(在s串中從pos位置開始刪除長度爲len的子串
void StrDelete(HString *s,int pos,int len);
//清除
void StrClear(HString *s);
HString.c
#include "HString.h"
void InitString(HString *s){
//初始化指針爲空
s->ch = NULL;
s->length = 0;
}
//重新開闢空間
void GetNewSpace(HString *s,int len){
//判斷原來的空間是否開闢過
if (s->ch != NULL) {
//先釋放掉原來的空間
free(s->ch);
}
//新開闢一個空間
s->ch = (char*)malloc(sizeof(char)*len);
assert(s->ch != NULL);
}
//賦值
void StrAssign(HString *s,char *str){
//獲取要賦值的串的長度
int len = (int)strlen(str);
//判斷原來的空間是否開闢過
// if (s->ch != NULL) {
// //先釋放掉原來的空間
// free(s->ch);
// }
// //新開闢一個空間
// s->ch = (char*)malloc(sizeof(char)*len);
// assert(s->ch != NULL);
GetNewSpace(s, len);
for (int i = 0; i < len; i ++) {
s->ch[i] = str[i];
}
//長度
s->length = len;
}
//展示
void PrintString(HString *s){
for (int i = 0; i < s->length; i ++) {
printf("%c",s->ch[i]);
}
printf("\n");
}
//拷貝(將t串拷貝到s串來
void StrCopy(HString *s,HString *t){
int len = StrLength(t);
// //判斷原來的空間是否開闢過
// if (s->ch != NULL) {
// //先釋放掉原來的空間
// free(s->ch);
// }
// //新開闢一個空間
// s->ch = (char*)malloc(sizeof(char)*len);
// assert(s->ch != NULL);
GetNewSpace(t, len);
for (int i = 0; i < len; i ++) {
s->ch[i] = t->ch[i];
}
s->length = len;
}
//判空:0->非空 !0->空
int StrEmpty(HString *s){
return s->length==0;
}
//比較(若s>t 返回值>0 s==t 返回值==0 s<t 返回值<0
int StrCompare(HString *s,HString *t){
if (s->length == 0 && t->length == 0) {
return 0;
}
int i = 0;
int j = 0;
while (i < s->length && j < t->length) {
if (s->ch[i] > t->ch[j]) {
return 1;
}else if (s->ch[i] < t->ch[j]){
return -1;
}
i ++;
j ++;
}
if (i < s->length) {
return 1;
}
if (j < t->length) {
return -1;
}
return 0;
}
//求長度
int StrLength(HString *s){
return s->length;
}
//鏈接
void StrConcar(HString *t,HString *s1,HString *s2){
int len1 = StrLength(s1);
int len2 = StrLength(s2);
GetNewSpace(t, len1+len2);
//先拷貝s1
for(int i = 0; i < len1; i ++){
t->ch[i] = s1->ch[i];
}
for (int j = 0; j < len2; j ++) {
t->ch[len1 + j] = s2->ch[j];
}
t->length = len1+len2;
}
//求子串(在s串中從pos位置開始求長度爲len的子串,並保存到sub串中
void SubString(HString *s,HString *sub,int pos,int len){
if (pos<0 || pos>s->length || len<0 || len>s->length || pos+len>s->length) {
printf("要截取的位置或長度不合法\n");
return;
}
//獲取新的空間
GetNewSpace(sub, len);
//賦值
for (int i = 0; i < len; i ++) {
sub->ch[i] = s->ch[pos + i];
}
sub->length = len;
}
//插入(將t串從pos位置起插入到s串中
void StrInsert(HString *s,int pos,HString *t){
if (pos<0 || pos>s->length) {
printf("要插入的位置非法\n");
return;
}
//需要增大空間
char *ch = (char*)realloc(s->ch, sizeof(char)*(s->length+t->length));
assert(ch != NULL);
s->ch = ch;
int index = 0;
for (int i = pos; i < pos+t->length; i ++) {
s->ch[i + t->length] = s->ch[i];
s->ch[i] = t->ch[index];
index ++;
}
s->length += t->length;
}
//刪除(在s串中從pos位置開始刪除長度爲len的子串
void StrDelete(HString *s,int pos,int len){
if (pos<0 || pos>s->length || len<= 0 || len>s->length) {
printf("要刪除的位置或長度非法\n");
return;
}
for (int i = pos; i < s->length; i ++) {
s->ch[i] = s->ch[i+len];
}
s->length -= len;
}
//清除
void StrClear(HString *s){
s->length = 0;
if (s->ch != NULL) {
free(s->ch);
}
s->ch = NULL;
}
Main.c
#include "HString.h"
int main(int argc, const char * argv[]) {
HString s;
InitString(&s);
HString t;
InitString(&t);
StrAssign(&s, "abc");
StrAssign(&t, "xyz");
//拷貝
//StrCopy(&t,&s);
PrintString(&t);
//鏈接
HString y;
InitString(&y);
StrConcar(&y, &s, &t);
PrintString(&y);
//求子串
HString sub;
InitString(&sub);
SubString(&y, &sub, 0, 2);
PrintString(&sub);
//插入
StrInsert(&s, 1, &t);
PrintString(&s);
//刪除
StrDelete(&s, 1, 1);
PrintString(&s);
return 0;
}