【練習】塊鏈串的實現

Time-space發表於2017-10-22

  為了方便串的操作,當以連結串列儲存串值時,除表頭指標外,還可附設一個尾指標來指示連結串列中的最後一個結點,並給出當前串的長度。這樣的串儲存結構稱為塊鏈結構。

  • 串的儲存結構型別
#define ChunkSize 4
#define stuff '#'
/*串的結點型別定義*/
typedef struct Chunk
{
    char ch[ChunkSize];
    struct Chunk *next;
}Chunk;
/*鏈串的型別定義*/
typedef struct
{
    Chunk *head;
    Chunk *tail;
    int length;
}LinkString;
  • 初始化串
void InitString(LinkString *S)
/*初始化字串S*/
{
    S->length=0;            /*將串的長度置為0*/
    S->head=S->tail=NULL;   /*將串的頭指標和尾指標置為空*/
}
  • 串的賦值
int StrAssign(LinkString *S,char *cstr)
/*生成一個其值等於cstr的串S。成功返回1,否則返回0*/
{
    int i,j,k,len;
    Chunk *p,*q;
    len=strlen(cstr);                   /*len為鏈串的長度 */
    if(!len)
        return 0;
    S->length=len;
        j=len/ChunkSize;                /*j為鏈串的結點數 */
    if(len%ChunkSize)
        j++;
    for(i=0;i<j;i++)
    {
        p=(Chunk*)malloc(sizeof(Chunk));    /*動態生成一個結點*/
        if(!p)
            return 0;
        for(k=0;k<ChunkSize&&*cstr;k++) /*將字串ctrs中的字元賦值給鏈串的資料域*/
            *(p->ch+k)=*cstr++;
        if(i==0)                        /*如果是第一個結點*/
            S->head=q=p;                /*頭指標指向第一個結點*/
        else
        {
            q->next=p;
            q=p;
        }
        if(!*cstr)                      /*如果是最後一個鏈結點*/
        {
            S->tail=q;                  /*將尾指標指向最後一個結點*/
            q->next=NULL;               /*將尾指標的指標域置為空*/
            for(;k<ChunkSize;k++)       /*將最後一個結點用'#'填充*/
            *(q->ch+k)=stuff;
        }
    }
    return 1;
}
  • 串的狀態
int StrEmpty(LinkString S)
/*判斷串是否為空。如果S為空串,則返回1,否則返回0*/
{
   if(S.length==0)                      /*如果串為空,返回1 */
     return 1;
   else                             /*如果串非空,返回0 */
     return 0;
 }
int StrLength(LinkString S)
/*求串的長度 */
{
    return S.length;
}
  • 串的複製
int StrCopy(LinkString *T,LinkString S)
/*串的複製操作*/
{
    char *str;
    int flag;
    if(!ToChars(S,&str))        /*將串S中的字元拷貝到字串str中*/
        return 0;
    flag=StrAssign(T,str);      /*將字串str的字元賦值到串T中*/
    free(str);              /*釋放str的空間 */
    return flag;
 }
  • 串的轉換
int ToChars(LinkString S,char **cstr)
/*串的轉換操作。將串S的內容轉換為字串,將串S中的字元拷貝到cstr。成功返回1,否則返回0*/
{
    Chunk *p=S.head;            /*將p指向串S中的第1個結點*/
    int i;
    char *q;
    *cstr=(char*)malloc((S.length+1)*sizeof(char));
    if(!cstr||!S.length)
        return 0;
        q=*cstr;                    /*將q指向cstr */
    while(p) /*塊鏈沒結束 */
    {
        for(i=0;i<ChunkSize;i++)
        if(p->ch[i]!=stuff)     /*如果當前字元不是填充的特殊字元'#',則將S中字元賦值給q*/
        *q++=(p->ch[i]);
        p=p->next;
    }
    (*cstr)[S.length]=0;             /*在字串的末尾新增結束標誌*/
    return 1;
}
  • 串的比較
int StrCompare(LinkString S,LinkString T)
/*串的比較操作。若S的值大於T,則返回正值;若S的值等於T,則返回0;若S的值小於T,則返回負值*/
{
    char *p,*q;
    int flag;
    if(!ToChars(S,&p))          /*將串S轉換為字串p*/
        return 0;
    if(!ToChars(T,&q))          /*將串T轉換為字串q*/
        return 0;
    for(;*p!='\0'&&*q!='\0';)
        if(*p==*q)
        {
            p++;
            q++;
        }
        else
            flag=*p-*q;
    free(p);                    /*釋放p的空間 */
    free(q);                    /*釋放q的空間*/
    if(*p=='\0'||*q=='\0')
        return S.length-T.length;
    else
        return flag;
}
  • 串的連線
int StrConcat(LinkString *T,LinkString S)
/*串的連結操作。將串S連線在串T的尾部*/
{
    int flag1,flag2;
    LinkString S1,S2;
    InitString(&S1);
    InitString(&S2);
    flag1=StrCopy(&S1,*T);          /*將串T的內容拷貝到S1中*/
    flag2=StrCopy(&S2,S);               /*將串S的內容拷貝到S2中*/
    if(flag1==0||flag2==0)          /*如果有一個串拷貝不成功,則返回0*/
        return 0;
    T->head=S1.head;                /*修改串T的頭指標*/
    S1.tail->next=S2.head;          /*將串S1和S2首尾相連*/
    T->tail=S2.tail;                    /*修改串T的尾指標*/
    T->length=S.length+T->length;       /*修改串T的長度*/
    return 1;
}
  • 串的插入
int StrInsert(LinkString *S, int pos,LinkString T)
/*串的插入操作。在串S的第pos個位置插入串T*/
{
    char *t1,*s1;
    int i,j;
    int flag;
    if(pos<1||pos>S->length+1)      /*如果插入位置不合法*/
        return 0;
    if(!ToChars(*S,&s1))                /*將串S轉換為字串s1*/
        return 0;
    if(!ToChars(T,&t1))             /*將串T轉換為字串t1*/
        return 0;
    j=strlen(s1);                   /*j為字串s1的長度*/
    s1=(char*)realloc(s1,(j+strlen(t1)+1)*sizeof(char));     /*為s1重新分配空間*/
    for(i=j;i>=pos-1;i--)
        s1[i+strlen(t1)]=s1[i];             /*將字串s1中的第pos以後的字元向後移動strlen(t1)個位置*/
    for(i=0;i<(int)strlen(t1);i++)      /*在字串s1中插入t1*/
        s1[pos+i-1]=t1[i];
    InitString(S);                  /*釋放S的原有儲存空間*/
    flag=StrAssign(S,s1);           /*由s1生成串S*/
    free(t1);
    free(s1);
    return flag;
}
  • 串的刪除
int StrDelete(LinkString *S,int pos,int len)
/*串的刪除操作。將串S中的第pos個字元起長度為len的子串刪除*/
{
    char *str;
    int i;
    int flag;
    if(pos<1||pos>S->length-len+1||len<0)   /*引數不合法*/
        return 0;
    if(!ToChars(*S,&str))                   /*將串S轉換為字串str*/
        return 0;
    for(i=pos+len-1;i<=(int)strlen(str);i++)        /*將字串中第pos個字元起的長度為len的子串刪除*/
        str[i-len]=str[i];
    InitString(S);                      /*釋放S的原有儲存空間*/
    flag=StrAssign(S,str);                   /*將字串str轉換為串S*/
    free(str);
    return flag;
}
  • 取子串操作
int SubString(LinkString *Sub, LinkString S,int pos,int len)
/*取子串操作。用Sub返回串S的第pos個字元起長度為len的子串。*/
{
    char *t,*str;
    int flag;
    if(pos<1||pos>S.length||len<0||len>S.length-pos+1)  /*引數不合法*/
        return 0;
    if(!ToChars(S,&str))            /*將串S轉換為字串str*/
        return 0;
    t=str+pos-1;                /*t指向字串str中的pos個字元*/
    t[len]='\0';                    /* 將Sub結束處置為'\0'*/
    flag=StrAssign(Sub,t);      /*將字串t轉換為Sub */
    free(str);
    return flag;
}
  • 清空串
void ClearString(LinkString *S)
/*清空串操作。將串的空間釋放*/
{
    Chunk *p,*q;
    p=S->head;
    while(p)
    {
        q=p->next;
        free(p);
        p=q;
    }
    S->head=S->tail=NULL;
    S->length=0;
}
  • 測試示例
/*包含標頭檔案及鏈串的基本操作實現檔案*/
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include"LinkString.h"
void StrPrint(LinkString S);
void main()
{
    int i,j;
    int flag;
    LinkString S1,S2,S3,Sub;
    char *str1="Welcome to";
    char *str2=" Data Structure";
    char *str3="Computer Architecture";
    printf("串的初始化和賦值操作:\n");
    InitString(&S1);                    /*串S1,S2,S3的初始化*/
    InitString(&S2);
    InitString(&S3);
    InitString(&Sub);
    StrAssign(&S1,str1);                /*串S1,S2,S3的賦值操作*/
    StrAssign(&S2,str2);
    StrAssign(&S3,str3);
    printf("串S1的值是:");
    StrPrint(S1);
    printf("串S2的值是:");
    StrPrint(S2);
    printf("串S3的值是:");
    StrPrint(S3);
    printf("將串S2連線在串S1的末尾:\n");
    StrConcat(&S1,S2);                  /*將串S2連線在串S1的末尾*/
    printf("S1是:");
    StrPrint(S1);
    printf("將串S1的第12個位置後的14個字元刪除:\n");
    StrDelete(&S1,12,14);               /*將串S1中的第12個位置後的14個字元刪除*/
    printf("S1是:");
    StrPrint(S1);
    printf("將串S2插入到串S1中的第12個字元後:\n");
    StrInsert(&S1,12,S3);               /*將串S3插入到串S1的第12個字元後*/
    printf("S1是:");
    StrPrint(S1);
    printf("將串S1中的第12個字元後的8個字元取出並賦值給串Sub:\n");
    SubString(&Sub,S1,12,8);            /*將串S1中的第12個位置後的8個字元取出賦值給Sub*/
    printf("Sub是:");
    StrPrint(Sub);
}

void StrPrint(LinkString S)
/*鏈串的輸出*/
{
    int i=0,j;
    Chunk *h;
    h=S.head;                       /*h指向第一個結點*/
    while(i<S.length)
    {
        for(j=0;j<ChunkSize;j++)    /*輸出塊中的每一個字元*/
            if(*(h->ch+j)!=stuff)   
            {
                printf("%c",*(h->ch+j));
                i++;
            }
            h=h->next;              /*h指向下一個結點*/
    }
    printf("\n");
}
  • 測試結果

這裡寫圖片描述

相關文章