zoukankan      html  css  js  c++  java
  • 第四章:1.串 -- 串类型定义及串的表示和实现

    前言:

      计算机上的应用程序几乎都是以字符串数据作为处理对象,然而,现今我们使用的计算机的硬件结构主要是反映数值计算的需要的,因此,在处理字符串数据时比处理整数和浮点数要复杂得多。而且,在不同类型的应用中,所处理的字符串具有不同的特点,要有效地实现字符串的处理,就必须根据具体情况使用合适的存储结构。这一章,我们将讨论一些基本的串处理操作 和 几种不同的存储结构。

    目录:

      1.串类型的定义

      2.串的表示和实现

        2.1.定长顺序存储表示

        2.2.堆分配存储表示

        2.3.串的块链存储表示

      3.串的模式匹配算法

      4.串操作应用剧烈

    正文:

      串类型的定义

      串(string)(或字符串)是由 零个或多个字符 组成的有限序列,一般记为:

          s=' a1a2...an '

      注意:由一个或多个空格组成的串,称为空格串。而不是空串。

        

        串 和 字符序列(char * ='hello')的区别:

          串是一种数据结构,是字符的集合,实现并提供对这种集合操作的各种方法。

          char 是c 的一种基本数据类型,没有已实现的对字符序列的复杂操作。

      串的逻辑结构和线性表极为相似,区别在于:

        1.串的数据对象约束为字符集。

        2.在线性表的基本操作中,以“单个数据元素” 为操作对象。 在串中 以 “串的整体” 作为操作对象,例如:查找子串、插入及删除子串。

      串的表示及实现

        串有3种机内表示方法:

        1.定长顺序存储 表示

          类似于线性表的顺序存储结构,用一组地址连续的存储单元存储串值的字符序列。在串的定长顺序存储结构中,按照预定义的大小,为每个定义的串变量分配一个固定长度的存储区,则可用定长数组如下描述之。

          存储表示:

            #define MAXSTRLEN 255                 //定义最大串长

            typedef  unsigned char SString [MAXSTRLEN +1];    //0单元存放串的长度

          串的实际长度可在这预定义长度的范围内随意, 超出的部分被舍弃,称之为 “截断” 。

          弊端:当合并两个 串的时候,如果长度超过 预定义最大串长MAXSTRLEN ,其它部分将会丢失即 “截断”。

          解决方案:使用不限定串长的最大长度, 即动态分配串值的存储空间。

        2.堆分配存储表示

          特点:仍以一组地址连续的存储单元存放串值字符序列,但它们的存储空间是在程序执行过程中动态分配而得。

          在 C 语言中,存在一个称之为 “堆” 的自由存储区, 并由C 语言的动态分配函数 malloc() 和 free()来管理。利用malloc 函数为每个新产生的串分配一块实际串长所需的存储空间,若分配成功,则返回一个指向起始地址的指针,作为串的基址,同时,为了处理方便,约定串长也作为存储结构的一部分。

          堆分配存储表示:

            typedef struct {

              char *ch;          //若是非空串,则按串长分配存储区,否则 ch 为 NULL

              int  length;         // 串长度

            }HSring;

          代码实现:

    #include<stdio.h>
    #include<stdlib.h>
    
    #define TRUE 1
    #define FALSE 0
    #define OK 1
    #define ERROR 0
    #define INFEASIBLE -1
    #define OVERFLOW -2
    
    #define MAXQSIZE 5
    //Status是函数的类型,其值是函数结果状态码
    typedef int Status;
    
    typedef struct{
        char *ch;                    //若是非空串,则按串长分配存储区,否则 ch 为 NULL
        int length;                    //字符串长度
    }HString;
    
    //生成一个其值等于串常量 chars  的串T
    Status StrAssign(HString &S,char * chars){
        int i;
        for(i=0;chars[i];i++){}
        //if(S.ch){
        //    free(S.ch);
        //    S.ch=NULL;
        //}
        if(!i){
            S.ch=NULL;
            S.length=0;
        }else{
            S.ch=(char *)malloc(i*sizeof(char));
            if(!S.ch) exit(OVERFLOW);
            S.length=i;
            for(int j=0;j<i;j++)
                S.ch[j]=chars[j];
        }
        return OK;
    }
    
    //返回串长度
    int StrLength(HString &S){
        return S.length;
    }
    
    //比较大小,若 S>T 返回值>0。相等 返回0 ,否则返回 <0
    int StrCompare(HString S,HString T){
        for(int i=0;i<S.length&&i<T.length;i++){
            if(S.ch[i]!=T.ch[i])
                return S.ch[i]-T.ch[i];
        }
        return S.length-T.length;
    }
    
    //清空串S为空串,并释放所占空间
    Status ClearString(HString &S){
        if(S.ch){
            free(S.ch);
            S.ch=NULL;
        }
        S.length=0;
        return OK;
    }
    
    //连接两个字符串,生成一个新的字符串
    Status Concat(HString &T,HString S1,HString S2){
        //if(T.ch) free(T.ch);
        T.ch=(char *)malloc((S1.length+S2.length)*sizeof(char));
        if(!T.ch) exit(OVERFLOW);
        T.length=S1.length+S2.length;
        for(int i=0;i<S1.length;i++)
            T.ch[i]=S1.ch[i];
    
        for(i=0;i<S2.length;i++)
            T.ch[i+S1.length]=S2.ch[i];
    
        return OK;
    }
    
    //字符串截取,返回截取的串
    Status SubString(HString &sub,HString S,int pos,int len){
        if(pos<1||pos>S.length||len<0||(S.length-pos+1)<len)
            return ERROR;
        //if(sub.ch) free(sub.ch);
        sub.ch=(char *)malloc(len*sizeof(char));    
        if(!sub.ch) exit(OVERFLOW);
        for(int i=0;i<len;i++)
            sub.ch[i]=S.ch[i+pos-1];
        sub.length=len;
        return OK;
    }
    
    void printV(HString &S){
        for(int i=0;i<S.length;i++){
            printf("地址:%p,",&S.ch[i]);
            printf("值:%c
    ",S.ch[i]);    
        }    
    }
    
    void prints(HString &S){
        for(int i=0;i<S.length;i++){        
            printf("%c",S.ch[i]);    
        }    
        printf("%s
    "," ");
    }
    
    void main(){
        HString S1;
        char *c="hello";    
        StrAssign(S1,c);
        ClearString(S1);
        c="hello";    
        StrAssign(S1,c);
        printf("%s","S1:");
        prints(S1);
        printV(S1);
    
        HString S2;
        c="China";    
        StrAssign(S2,c);
        printf("%s","S2:");
        prints(S2);
        printV(S2);
    
        HString T;
        Concat(T,S1,S2);
        printf("%s","T:");
        prints(T);
        printV(T);
    
        HString sub;
        SubString(sub,T,6,5);
        printf("%s","sub:");
        prints(sub);
        printV(sub);
    }

          运行结果:

               

      串的表示和实现

        串的块链存储表示:

        和线性表的链式存储表示相似,串也可以采用链表方式存储串值。由于串结构的特殊性,存储时一个结点可以存放一个字符也可以存放多个字符。

        当结点大小大于1时,由于 串值可能不是结点大小的整数倍,则链表最后一个结点可能无法填满,此时通常补上 “#” 或其他非串值 字符。如下图:

        

        定义:

          为了便于进行串的操作,当以链表存储串值时,除头指针外还可附设一个尾指针指示链表中的最后 一个结点,并给出当前串的长度,称如此定义的串存储结构为块链结构。

         

        串的块链存储表示

        #define CHUNKSIZE  80;          //结点大小,用户自己随便定义

        typedef struct Chunk{           //结点定义

          char ch[CHUNKSIZE];

          struct Chunk *next;

        }Chunk;

        typedef struct{

          Chunk *head,*tail;      //串的头指针,和尾指针

          int  curlen;          //串的长度

        }

        注:设置尾指针的目的是 便于进行串的连接操作,但要注意连接时需处理第一个串尾的无效字符(#)。

       链式串中,结点的大小直接影响着串处理的效率。

          存储密度 = 串值所占的存储位 / 实际分配的存储位  

        对于固定的串a ,其串值存储位是固定的,而实际分配的存储位根据结点的大小而改变。

        显然当存储密度最小时,(即结点大小为1)串的运算处理最方便,但是其占用的存储量大。

      总结:

        串的链式存储,对链接操作等有一定的方便之处, 但总的来说不如另外两种结构灵活,它占用存储量大且操作复杂。

  • 相关阅读:
    Create C++ Windows Forms Application in Visual Studio 2017
    VS项目打包发布
    获取光标所在行索引
    拖拽生成控件副本
    MDI中的ToolStrip合并
    使用FFmpeg音视频格式转换
    获取项目中其他文件
    解决Winform大多数DPI问题
    《Pro Git》第3章 分支
    《Pro Git》第2章 Git基础
  • 原文地址:https://www.cnblogs.com/ahguSH/p/6218774.html
Copyright © 2011-2022 走看看