數據結構(12.3)串之堆分配順序串

前言

堆分配順序串實際上就是動態分配內存的順序存儲結構。它與定長順序串的區別是:它的串長度可以任意變換,並且不需要預先分配內存。

我們這次額外使用一個變量來保存串的長度,使用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;
}
發佈了36 篇原創文章 · 獲贊 18 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章