c语言实现字符串

串的基本概念

串 ( 字符串 ) :是零个或多个字符组成的有限序列。 记作: S=” a1 a2 a3 a4 …” ,其中 S 是串名, ai (1 ≦ i ≦ n) 是 单个,可以是字母、数字或其它字符。
串值:双引号括起来的字符序列是串值。
串长:串中所包含的字符个数称为该串的长度。
空串 ( 空的字符串 ) :长度为零的串称为空串,它不 包含任何字符。
空格串 ( 空白串 ) :构成串的所有字符都是空格的串 称为空白串。
子串 (substring) :串中任意个连续字符组成的子序 列称为该串的子串,包含子串的串相应地称为主串。
子串的序号:将子串在主串中首次出现时的该子串 的首字符对应在主串中的序号,称为子串在主串中的序
号(或位置)。
串相等:如果两个串的串值相等 ( 相同 ) ,称这两 个串相等。换言之,只有当两个串的长度相等,且各 个对应位置的字符都相同时才相等。

串的基本操作

1.串赋值
2.串拷贝
3.串比较
4.串长度
5.清空串
6.返回第pos个字符起长度为len的字串
7.若存在和T相等的字串,返回其字串第一次出现的位置
8.替换字串
9.在串中的第pos个字符之前插入字串
10.删除第pos个字符起长度为len的字串
11.销毁串
12. 两个串相接

串的表示和实现

◆ 定长顺序存储表示:将串定义成字符数组,利用 串名可以直接访问串值。用这种表示方式,串的存 储空间在编译时确定,其大小不能改变。
特点:
1.操作时间的复杂度基本上基于字符序列的长度
2.如果在操作中出现串值序列的长度超过上界MAXSTRLEN时,约定用截尾法处理.
定长顺序存储结构定义为:

#define MAX_STRLEN 256
typedef struct
{ 
    char str[MAX_STRLEN] ;
    int length;
} StringType ;

◆ 堆分配存储方式:仍然用一组地址连续的存储单 元来依次存储串中的字符序列,但串的存储空间是 在程序运行时根据串的实际长度动态分配的。
实现方法:系统提供一个空间足够大且地址连续的存储空间 ( 称为“堆” ) 供串使用。可使用 C 语言的动态存储分配函数 malloc() 和 free() 来管理。
串的堆式存储结构的类型定义

typedef struct
{ 
    char *ch; /* 若非空,按长度分配,否则为 NULL */
    int length;
} HString ;

◆ 块链存储方式:是一种链式存储结构表示。
串的链式存储结构和线性表的串的链式存储结构类似,采用单链表来存储串,结点的构成是:

data 域:存放字符, data 域可存放的字符个数
称为结点的大小;
next 域:存放指向下一结点的指针。
若每个结点仅存放一个字符,则结点的指针域就非常多,造成系统空间浪费,为节省存储空间,考虑串结构的特殊性,使每个结点存放若干个字符,这种
结构称为块链结构。如图 4-1 是块大小为 3 的串的块链式存储结构示意图。

这里写图片描述

结点的大小直接影响着串的处理效率.
串的存储密度:

存储密度=

显然,存储密度小时(例如结点大小为1),运算处理非常方便,但是存储占用量大.而存储密度大时,存储占用量相对较小,但如果在串处理过程中需进行过多的内外存交换时,会影响处理的总效率.

堆分配存储方式C语言实现

接口定义头文件


#define true 1
#define false 0


#define S_g_T 1
#define S_e_T 0
#define S_s_T -1

/* 串的堆分配存储表示 */
typedef struct h_string{
    char *str;
    /* 串长度 */
    int length;
}h_string;



/* 生成一个值等于str的字符串常量 
 * 生成成功返回true
 * 否则返回false
*/


int string_assign(h_string *S, char *ch);


/* 复制串S并返回 */
h_string string_copy(h_string S);

/* 判断串S是否为空
 * 若为空则返回true
 * 否则返回false
*/

int string_empty(h_string S);

/* 比较串S和T
 * 若S>T返回S_g_T
 * 若S=T返回S_e_T
 * 若S<T返回S_s_T
*/

int string_compare(h_string S, h_string T);


/* 返回自字符串的长度 */

int string_length(h_string S);

/* 将S清空 */
void string_clear(h_string *S);

/* S1和S2连接,并由T返回连接的新串
 * 若连接成功,返回true
 * 否则返回false
*/

int string_contact(h_string *T, h_string S1, h_string S2);


/* 用sub返回串S第pos个字符起长度为len的子串 
 * 成功返回true
 * 否则返回false
*/
int string_substring(h_string S, h_string *sub, int pos, int len);

/* 若主串S中存在和串T值相等的字串,
 * 返回它在主串S中第pos个字符之后第一次出现的位置
 * 否则返回-1
*/

int string_index(h_string S, h_string T, int pos);


/* 用V替换主串S中出现所有的与T串值相等的不重叠的字串 */
h_string string_replace(h_string *S, h_string V, h_string T);

/* 在串S的第pos个字符之前插入串T */
h_string string_strinsert(h_string S, h_string T, int pos);


/* 从串S中删除第pos个字符起长度为len的字串 */
h_string string_strdelete(h_string S, int pos, int len);

/* 销毁串S */
void string_destroy(h_string *S);

/* 遍历打印字符 */
void string_traverse(h_string S);

接口实现文件

#include<stdio.h>
#include<stdlib.h>
#include"string.h"


int string_assign(h_string *S, char *ch)
{
    /* 释放S的原有空间 */
    if(S -> str)
        free(S -> str);

    /* 求串ch的长度 */
    int count = 0;
    char *c;
    for(count = 0, c = ch; *c; count++, c++);
    printf("count  = %d\n", count);

    /* 若*ch为空 */
    if(!count)
    {
        S -> length = 0;
        S -> str = NULL;
        return true;
    }
    else
    {
        /* 申请内存空间 */
        if(!(S -> str = (char *)malloc(sizeof(char)*count)))
            return false;
        S -> length = count;
        /* 赋值 */
        int i = 0;
        for(i = 0; i < count; i++)
        {
            S -> str[i] = ch[i];
        }
        return true;
    }

}

h_string string_copy(h_string S)
{
    /* 创建新串 */
    int len = S.length;
    h_string T;
    T.str = (char *)malloc(sizeof(char) * len);
    T.length = len;

    /* 复制 */
    int i = 0;
    for (i = 0; i < len; i++)
    {
        T.str[i] = S.str[i];
    }
    return T;
}


int string_empty(h_string S)
{
    if(S.length == 0)
        return false;
    else
        return true;
}

int string_length(h_string S)
{
    return S.length;
}

int string_compare(h_string S, h_string T)
{
    /* 相同索引号从小到大的字符比较 
     * 相同则继续比较,直至最后一个字符
     * 否则直接返回两字符的差值
    */
    int i = 0;
    for (i = 0;i < S.length && i < T.length; i++)
    {
        int value = S.str[i] - T.str[i];
        if(value > 0)
            return 1;
        if(value < 0)
            return -1;
    }
    /* 若两个字符串前面的字符都一致
     * 则比较长度
     * 长度一样说明相等
     * 长度短的字符串小
    */
    int value = S.length - T.length;
    if(value == 0)
        return 0;
    if(value > 0)
        return 1;
    if(value < 0)
        return -1;
}



void string_clear(h_string *S)
{
    if(S -> str)
    {
        free(S -> str);
        S -> str = NULL;
    }
    S -> length = 0;
}

int string_contact(h_string *T, h_string S1, h_string S2)
{
    /* 释放旧字符串(可直接调用string_empty()函数) */
    if(T -> str)
    {
        free(T -> str);
        T -> str = NULL;
    }
    /* 新字符串长度 */
    T -> length = S1.length + S2.length;
    T -> str = (char *)malloc(sizeof(char)*(T -> length));
    if(!T -> str)
        return false;
    /* 赋值 */
    int i = 0;
    for(i = 0; i < T -> length; i++)
    {
        if(i >= S1.length)
        {
            T -> str[i] = S2.str[i - S1.length];
        }
        else
        {
            T -> str[i] = S1.str[i];
        }
    }
    return true;

}


int string_substring(h_string S, h_string *T, int pos, int len)
{
    /* pos,len与S.length间的关系
     * 1 <= pos <= S.length;
     * pos + len - 1 <= S.length
     * len >= 0
    */
    /* 判断子串起始索引号和长度是否满足要求 */
    if(pos < 1 || pos > S.length || len > S.length + pos - 1 || len < 0)
        return false;

    /* 清空旧串 */
    if(T -> str)
        free(T -> str);

    /* 空子串 */
    if (!len)
    {
        T -> str = NULL;
        T -> length  = 0;
        return false;
    }
    /* 申请内存空间 */
    T -> str = (char *)malloc(sizeof(char) * len);
    T -> length = len;
    /* 申请内存空间失败 */
    if(!(T -> str))
        return false;
    /* 赋值 */
    int i = 0;
    for (i = 0; i < len; i++)
    {
        T -> str[i] = S.str[pos - 1 + i];
    }
    return true;
}


int string_index(h_string S, h_string T, int pos)
{
    /* 若T为空串 */
    if(!(T.length))
        return -1;
    /* 比较 */
    /* 串S的起始位置 */
    int i = pos -1;
    /* 串T的起始位置 */
    int j = 0;
    while(i < S.length && j < T.length)
    {
        if(S.str[i] == T.str[j])
        {
            i += 1;
            j += 1;
        }
        else
        {
            i = i -j + 1;
            j = 0;
        }
    }
    if (j >= T.length)
        return (i - T.length);
    return -1;
}

h_string string_replace(h_string *S, h_string V, h_string T)
{
    /* 替换之后,下一轮替换的起始位置,初始化为1 */
    int pos = 1;
    while(pos <= S -> length)
    {
        int index = string_index(*S, T, pos);
        /* S中存在与T串值相等的子串 */
        if (index >= 0)
        {
            /* V.length = T.length */
            if (V.length == T.length)
            {
                int i = 0;
                for (i = 0; i < V.length; i++)
                {
                    S -> str[index + i] = V.str[i];
                }
                pos = index + V.length;
                continue;
            }
            /* V.length > T.length */
            if (V.length > T.length)
            {
                /* 复制字符串S,保存在临时字符串temp中 */
                h_string temp = string_copy(*S);
                /* 增加申请内存 */
                S -> str = (char *)malloc(sizeof(char) * S -> length + V.length - T.length);
                S -> length = S -> length + V.length - T.length;
                int i = 0;
                int j = 0;
                for (i = 0; i < index; i++)
                {
                    S -> str[i] = temp.str[i];
                }
                for (i = 0; i < V.length; i++)
                {
                    S -> str[index + i] = V.str[i];
                }
                for(i = index + V.length, j = index + T.length; j < temp.length; i++, j++)
                {
                    S -> str[i] = temp.str[j];
                    printf("temp.length =%d j=%d\n", temp.length, j);
                }
                pos = index + V.length;
                printf("部分\n");
                string_traverse(*S);
                continue;
            }
            /* V.length < T.length */
            if(V.length < T.length)
            {
               /* 复制字符串S,保存在临时字符串temp中 */
                h_string temp = string_copy(*S);
                /* 释放旧字符串 */
                free(S -> str);
                S -> str = NULL;
                /* 新申请内存 */
                int len = temp.length + V.length - T.length;
                S -> str = (char *)malloc(sizeof(char) * len);
                S -> length = len;
                int i = 0;
                int j = 0;
                for (i = 0; i < index; i++)
                {
                    S -> str[i] = temp.str[i];
                }
                for (i = 0; i < V.length; i++)
                {
                    S -> str[index + i] = V.str[i];
                }
                for(i = index + V.length, j = index + T.length; j < temp.length; i++, j++)
                {
                    S -> str[i] = temp.str[j];
                }
                pos = index + V.length;
                continue; 
            }
        }
        else
            return *S;
    }
}


h_string string_strinsert(h_string S, h_string T, int pos)
{
    /* 插入字符串为空 */
    if(!T.length)
        return S;
    /* 存储字符串S的临时字符串 */
    h_string temp = S;
    /* 增加申请内存 */
    int len = S.length + T.length;
    S.length = len;
    S.str = (char *)malloc(sizeof(char) * len);
    /* 插入字符串 */
    int i = 0;
    int j = 0;
    for (i = 0; i < pos - 1; i++)
    {
        S.str[i] = temp.str[i];
    }
    for (i = 0; i < T.length; i++)
    {
        S.str[pos - 1 + i] = T.str[i];
    }
    for (i = pos -1 + T.length, j = pos - 1; j < temp.length; i++, j++)
    {
        S.str[i] = temp.str[j];
        printf("S.str[%d]=%c j=%d\n", i, S.str[i], j);
    }
    return S;
}
h_string string_strdelete(h_string S, int pos, int len)
{
    /* pos,len与S.length间的关系
     * 1 <= pos <= S.length;
     * pos + len - 1 <= S.length
     * len > 0
    */
    /* 判断子串起始索引号和长度是否满足要求 */
    if(pos < 1 || pos > S.length || len > S.length + pos - 1 || len <= 0)
        return S;
    /* S删除子串之后的长度 */
    int length = S.length - len;
    if (!length)
    {
        free(S.str);
        S.str = NULL;
        S.length = 0;
        return S;
    }
    else
    {
        h_string temp;
        temp.str = (char *)malloc(sizeof(char) * length);
        temp.length = length;
        int i = 0;
        int j = 0;
        for (i = 0; i < pos - 1; i++)
        {
            temp.str[i] = S.str[i];
        }
        for (i = pos - 1, j = pos -1 + len; j < S.length; i++, j++)
        {
            temp.str[i] = S.str[j];
        }
        return temp;
    }
}


void string_destroy(h_string *S)
{
    free(S -> str);
    S -> str = NULL;
    S -> length = 0;
}


void string_traverse(h_string S)
{
    if(!(S.length))
        printf("字符串为空\n");
    else
    {
        int i = 0;
        for(i = 0; i < S.length; i++)
        {
            printf("%c",S.str[i]);
        }
        printf("\n");
    }
}

其中的int string_index()函数的采用的是暴力比较法,该算法最好情况的时间复杂度是O(n+m),最差情况时的时间复杂度为O(n*m),可以采用KMP算法改进,使得其时间复杂度为O(n+m),详细情况见下篇博文.

测试文件

int main()
{
    char *ch = "jiang";
    h_string S;
    S.length = 7; 
    S.str = (char *)malloc(sizeof(char) * S.length);
    /* 赋值 */
    string_assign(&S, ch);
    string_traverse(S);
    /* 复制  */
    h_string T = string_copy(S);
    string_traverse(T);
    /* 判空 */
    int value = string_empty(S);
    printf("字符串判空=%d\n",value);
    /* 字符串比较 */
    char *str = "linyijiang";
    string_assign(&T, str);
    value = string_compare(S, T);
    printf("字符串比较=%d\n",value);
    /* 字符串长度 */
    value = string_length(T);
    printf("字符串长度=%d\n", value);
    /* 清空字符串 */
    //string_clear(&S);
    //printf("字符串清空:");
    //string_traverse(S);\
    /* 字符串连接 */
    h_string ST ;
    ST.str = NULL;
    string_contact(&ST, S, T);
    string_traverse(ST);
    /* 字串位置 */
    string_traverse(T);
    string_traverse(S);
    value = string_index(T, S, 1);
    printf("index=%d\n", value);
    /* 返回长度为len的字符串 */
    printf("返回长度为len的字符串\n");
    string_traverse(T);
    string_traverse(S);
    value = string_substring(T, &S, 2, 9);
    string_traverse(S);
    /* 替换 */
    //string_traverse(T);
    //h_string V;
    //V.str = "brother";
    //V.length = 7;
    //S.str = "i";
    //S.length = 1;
    //S = string_replace(&T, V, S);
    //string_traverse(S);
    /* 插入字符串 */
    //printf("插入字符串\n");
    //string_traverse(T);
    //S = string_strinsert(T, V, 2);
    //string_traverse(S);
    /* 删除 */
    //printf("删除\n");
    //string_traverse(T);
    //S = string_strdelete(T, 2, 6);
    //string_traverse(S);

}

运行结果

这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值