数据结构---串

一、串的介绍

串型结构就是由若干个类型相同的元素组成的数据结构,末尾有一个结束标志,字符串就是由字符元素组成的串型结构,'\0'是它的结束标志,使用它可以存储单词、文章、汉字等文字信息。

随着计算机和编程语言的发展,字符串在程序中使用的越来越多,字符串就简称串,对它的操作都是对串里面所有字符整体操作,以'\0'为结束标志,如果字符串的末尾没有'\0',可能会产生乱码、段错误、脏数据等问题。

字符串结构应该具备的功能、算法有:

创建:定义字符串

销毁:释放字符串

清空:删除所有的字符

复制:就是strcpy函数

连接:就是strcat函数

比较:就是strcmp函数

长度:就是strlen函数

查询字串:就是strstr函数

字符串的表示与实现

字符串一般有两实现方式,这两种方式都是使用顺序表,只是内存不同而已:

1、用栈内存存储字符,定长方式,字符的数量一旦超出表的范围,为了防止内存越界要对字符串进行截取,了解一下即可。

2、使用堆内存破碎字符,在操作字符串时,自动扩展堆内存。

#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
​
typedef struct String
{
    char* ch;
    size_t size;
}String;
​
// 创建字符串
String* create_string(void)
{
    String* str = malloc(sizeof(String));
    str->ch = NULL;
    str->size = 0;
    return str;
}
​
// 计算长度
size_t len_string(String* str)
{
    return strlen(str->ch);
}
​
// 复制
void copy_string(String* str,const char* ch)
{
    size_t size = strlen(ch)+1;
    if(size > str->size)
    {
        str->ch = realloc(str->ch,size);
        str->size = size;
    }
    
    strcpy(str->ch,ch);
}
​
// 构建字符串
String* assign_string(const char* ch)
{
    String* str = create_string();
    copy_string(str,ch);
    return str;
}
​
// 判断是否是空串
bool empty_string(String* str)
{
    return NULL == str->ch;
}
​
// 赋值
void sav_string(String* str1,String* str2)
{
    if(str1->size < str2->size)
    {
        str1->ch = realloc(str1->ch,str2->size);
        str1->size = str2->size;
    }
​
    strcpy(str1->ch,str2->ch);
}
​
// 比较
int cmp_string(String* str1,String* str2)
{
    return strcmp(str1->ch,str2->ch);
}
​
// 连接
void cat_string(String* str1,String* str2)
{
    size_t size = strlen(str1->ch)+strlen(str2->ch)+1;
    if(size >= str1->size)
    {
        str1->ch = realloc(str1->ch,size);
        str1->size = size;
    }
    strcat(str1->ch,str2->ch);
}
​
// 清空字符串
void clear_string(String* str)
{
    free(str->ch);
    str->size = 0;
}
​
// 销毁字符串
void destroy_string(String* str)
{
    free(str->ch);
    free(str);
}
​
int main(int argc,const char* argv[])
{
    /*
    String* str1 = assign_string("hehe");
    String* str2 = create_string();
    // 浅拷贝,两个对象的ch指向了同一个字符串,当其它对象被销毁,另一个会受影响
    *str2 = *str1; // str2->ch = str1->ch; str2->len = str1->len;
    destroy_string(str1);
    puts(str2->ch);
    // 深拷贝,如果结构体中有成员是指针类型,且指向了堆内,这种结构变量不能直接赋值(浅拷贝),为了不出问题,我们需要实现深拷贝
    sav_string(str2,str1);
    destroy_string(str1);
    puts(str2->ch);
    */
    String* str1 = assign_string("hehe");
    String* str2 = assign_string("xixi12rfaspoikjrqw;elifkj;lasejkrf;oawlikeujf;olaeirjtfasldkjf;qlwiejfa;sldkjf;qwlsekjfa;sldkfj;l");
    cat_string(str1,str2);
    puts(str1->ch);
​
    return 0;
}

封装字符串的意义

1、字符串被封装成数据结构后,使用者不需要关心字符串的空间问题,但这种封装在C语言下没有太大意义,因为C语言语法的原因会使用字符串操作更麻烦。

2、我们在C++语言中重写该数据结构,因为C++的语法会让该数据结构使用起来更方便。

子串查询的算法

假定有两个字符串str1,str2,查询子串就是在字符串str1中查询是否存在str2,如果存在则返回str2首次出现的位置,这个操作叫子串查询。

char *str_str(const char *str1, const char *str2)
{
    assert(NULL != str1 && NULL != str2);
    for (int i = 0, j; '\0' != str1[i]; i++)
    {
        for (j = 0; '\0' != str2[j] && str2[j] == str1[i + j]; j++)
            ;
        if ('\0' == str2[j])
            return (char *)str1 + i;
    }
    return NULL;
}
​
char *str_str(const char *str1, const char *str2)
{
    assert(NULL != str1 && NULL != str2);
    int i = 0, j = 0;
    while ('\0' != str1[i] && '\0' != str2[j])
    {
        if (str1[i] == str2[j])
        {
            i++;
            j++;
        }
        else
        {
            i = i - j + 1;
            j = 0;
        }
    }
    return '\0' == str2[j] ? (char *)str1 + i - j : NULL;
}
​
char* str_str(const char* str1,const char* str2)
{
    assert(NULL != str1 && NULL != str2);
    int sum1 = 0 , sum2 = 0 , len = 0;
    while('\0'!=str2[len]&&'\0'!=str1[len])
    {
        sum1 += str1[len];
        sum2 += str2[len++];
    }
​
    for(int i=len; '\0' != str1[i]; i++)
    {
        printf("%d %d\n",sum1,sum2);
        if(sum1 == sum2 && 0 == strncmp(str1+i-len,str2,len))
        {
            return (char*)str1+i-len;
        }
        else
        {
            sum1 -= str1[i-len];
            sum1 += str1[i];
        }
    }
​
    return NULL;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值