`

串的块链存储表示

阅读更多
 /* c4-3.h 串的块链存储表示 */
 #define CHUNKSIZE 4 /* 可由用户定义的块大小 */
 typedef struct Chunk
 {
   char ch[CHUNKSIZE];
   struct Chunk *next;
 }Chunk;
 typedef struct
 {
   Chunk *head,*tail; /* 串的头和尾指针 */
   int curlen; /* 串的当前长度 */
 }LString;

 

 /* bo4-3.c 串采用块链存储结构(由c4-3.h定义)的基本操作(16个) */
 void InitString(LString *T)
 { /* 初始化(产生空串)字符串T。另加 */
   (*T).curlen=0;
   (*T).head=NULL;
   (*T).tail=NULL;
 }

 Status StrAssign(LString *T,char *chars)
 { /* 生成一个其值等于chars的串T(要求chars中不包含填补空余的字符) */
   /* 成功返回OK,否则返回ERROR */
   int i,j,k,l;
   Chunk *p,*q;
   i=strlen(chars); /* i为串的长度 */
   if(!i||strchr(chars,blank)) /* 串长为0或chars中包含填补空余的字符 */
     return ERROR;
   (*T).curlen=i;
   j=i/CHUNKSIZE; /* j为块链的结点数 */
   if(i%CHUNKSIZE)
     j++;
   for(k=0;k<j;k++)
   {
     p=(Chunk*)malloc(sizeof(Chunk));
     if(!p)
       return ERROR;
     if(k==0) /* 第一个链块 */
       (*T).head=q=p;
     else
     {
       q->next=p;
       q=p;
     }
     for(l=0;l<CHUNKSIZE&&*chars;l++)
       *(q->ch+l)=*chars++;
     if(!*chars) /* 最后一个链块 */
     {
       (*T).tail=q;
       q->next=NULL;
       for(;l<CHUNKSIZE;l++) /* 用填补空余的字符填满链表 */
         *(q->ch+l)=blank;
     }
   }
   return OK;
 }

 Status StrCopy(LString *T,LString S)
 { /* 初始条件:串S存在。操作结果:由串S复制得串T(连填补空余的字符一块拷贝) */
   Chunk *h=S.head,*p,*q;
   (*T).curlen=S.curlen;
   if(h)
   {
     p=(*T).head=(Chunk*)malloc(sizeof(Chunk));
     *p=*h; /* 复制1个结点 */
     h=h->next;
     while(h)
     {
       q=p;
       p=(Chunk*)malloc(sizeof(Chunk));
       q->next=p;
       *p=*h;
       h=h->next;
     }
     p->next=NULL;
     (*T).tail=p;
     return OK;
   }
   else
    return ERROR;
 }

 Status StrEmpty(LString S)
 { /* 初始条件:串S存在。操作结果:若S为空串,则返回TRUE,否则返回FALSE */
   if(S.curlen) /* 非空 */
     return FALSE;
   else
     return TRUE;
 }

 int StrCompare(LString S,LString T)
 { /* 若S>T,则返回值>0;若S=T,则返回值=0;若S<T,则返回值<0 */
   int i=0; /* i为当前待比较字符在S,T串中的位置 */
   Chunk *ps=S.head,*pt=T.head; /* ps,pt分别指向S和T的待比较块 */
   int js=0,jt=0; /* js,jt分别指示S和T的待比较字符在块中的位序 */
   while(i<S.curlen&&i<T.curlen)
   {
     i++; /* 分别找S和T的第i个字符 */
     while(*(ps->ch+js)==blank) /* 跳过填补空余的字符 */
     {
       js++;
       if(js==CHUNKSIZE)
       {
         ps=ps->next;
         js=0;
       }
     }; /* *(ps->ch+js)为S的第i个有效字符 */
     while(*(pt->ch+jt)==blank) /* 跳过填补空余的字符 */
     {
       jt++;
       if(jt==CHUNKSIZE)
       {
         pt=pt->next;
         jt=0;
       }
     }; /* *(pt->ch+jt)为T的第i个有效字符 */
     if(*(ps->ch+js)!=*(pt->ch+jt))
       return *(ps->ch+js)-*(pt->ch+jt);
     else /* 继续比较下一个字符 */
     {
       js++;
       if(js==CHUNKSIZE)
       {
         ps=ps->next;
         js=0;
       }
       jt++;
       if(jt==CHUNKSIZE)
       {
         pt=pt->next;
         jt=0;
       }
     }
   }
   return S.curlen-T.curlen;
 }

 int StrLength(LString S)
 { /* 返回S的元素个数,称为串的长度 */
   return S.curlen;
 }

 Status ClearString(LString *S)
 { /* 初始条件: 串S存在。操作结果: 将S清为空串 */
   Chunk *p,*q;
   p=(*S).head;
   while(p)
   {
     q=p->next;
     free(p);
     p=q;
   }
   (*S).head=NULL;
   (*S).tail=NULL;
   (*S).curlen=0;
   return OK;
 }

 Status Concat(LString *T,LString S1,LString S2)
 { /* 用T返回由S1和S2联接而成的新串 */
   LString a1,a2;
   InitString(&a1);
   InitString(&a2);
   StrCopy(&a1,S1);
   StrCopy(&a2,S2);
   (*T).curlen=S1.curlen+S2.curlen;
   (*T).head=a1.head;
   a1.tail->next=a2.head;
   (*T).tail=a2.tail;
   return OK;
 }

 Status SubString(LString *Sub, LString S,int pos,int len)
 { /* 用Sub返回串S的第pos个字符起长度为len的子串。 */
   /* 其中,1≤pos≤StrLength(S)且0≤len≤StrLength(S)-pos+1 */
   Chunk *p,*q;
   int i,k,n,flag=1;
   if(pos<1||pos>S.curlen||len<0||len>S.curlen-pos+1)
     return ERROR;
   n=len/CHUNKSIZE; /* 生成空的Sub串 */
   if(len%CHUNKSIZE)
     n++; /* n为块的个数 */
   p=(Chunk*)malloc(sizeof(Chunk));
   (*Sub).head=p;
   for(i=1;i<n;i++)
   {
     q=(Chunk*)malloc(sizeof(Chunk));
     p->next=q;
     p=q;
   }
   p->next=NULL;
   (*Sub).tail=p;
   (*Sub).curlen=len;
   for(i=len%CHUNKSIZE;i<CHUNKSIZE;i++)
     *(p->ch+i)=blank; /* 填充Sub尾部的多余空间 */
   q=(*Sub).head; /* q指向Sub串即将复制的块 */
   i=0; /* i指示即将复制的字符在块中的位置 */
   p=S.head; /* p指向S串的当前块 */
   n=0; /* n指示当前字符在串中的序号 */
   while(flag)
   {
     for(k=0;k<CHUNKSIZE;k++) /* k指示当前字符在块中的位置 */
       if(*(p->ch+k)!=blank)
       {
         n++;
         if(n>=pos&&n<=pos+len-1) /* 复制 */
         {
           if(i==CHUNKSIZE)
           { /* 到下一块 */
             q=q->next;
             i=0;
           }
           *(q->ch+i)=*(p->ch+k);
           i++;
           if(n==pos+len-1) /* 复制结束 */
           {
             flag=0;
             break;
           }
         }
       }
     p=p->next;
   }
   return OK;
 }

 int Index(LString S,LString T,int pos)
 { /* T为非空串。若主串S中第pos个字符之后存在与T相等的子串, */
   /* 则返回第一个这样的子串在S中的位置,否则返回0 */
   int i,n,m;
   LString sub;
   if(pos>=1&&pos<=StrLength(S)) /* pos满足条件 */
   {
     n=StrLength(S); /* 主串长度 */
     m=StrLength(T); /* T串长度 */
     i=pos;
     while(i<=n-m+1)
     {
       SubString(&sub,S,i,m); /* sub为从S的第i个字符起,长度为m的子串 */
       if(StrCompare(sub,T)!=0) /* sub不等于T */
         ++i;
       else
         return i;
     }
   }
   return 0;
 }

 void Zip(LString *S)
 { /* 压缩串(清除块中不必要的填补空余的字符)。加 */
   int j,n=0;
   Chunk *h=(*S).head;
   char *q;
   q=(char*)malloc(((*S).curlen+1)*sizeof(char));
   while(h) /* 将LString类型的字符串转换为char[]类型的字符串 */
   {
     for(j=0;j<CHUNKSIZE;j++)
       if(*(h->ch+j)!=blank)
       {
         *(q+n)=*(h->ch+j);
         n++;
       }
     h=h->next;
   }
   *(q+n)=0; /* 串结束符 */
   ClearString(S); /* 清空S */
   StrAssign(S,q); /* 重新生成S */
 }

 Status StrInsert(LString *S,int pos,LString T)
 { /* 1≤pos≤StrLength(S)+1。在串S的第pos个字符之前插入串T */
   int i,j,k;
   Chunk *p,*q;
   LString t;
   if(pos<1||pos>StrLength(*S)+1) /* pos超出范围 */
     return ERROR;
   StrCopy(&t,T); /* 复制T为t */
   Zip(S); /* 去掉S中多余的填补空余的字符 */
   i=(pos-1)/CHUNKSIZE; /* 到达插入点要移动的块数 */
   j=(pos-1)%CHUNKSIZE; /* 到达插入点在最后一块上要移动的字符数 */
   p=(*S).head;
   if(pos==1) /* 插在S串前 */
   {
     t.tail->next=(*S).head;
     (*S).head=t.head;
   }
   else if(j==0) /* 插在块之间 */
   {
     for(k=1;k<i;k++)
       p=p->next; /* p指向插入点的左块 */
     q=p->next; /* q指向插入点的右块 */
     p->next=t.head; /* 插入t */
     t.tail->next=q;
     if(q==NULL) /* 插在S串后 */
       (*S).tail=t.tail; /* 改变尾指针 */
   }
   else /* 插在一块内的两个字符之间 */
   {
     for(k=1;k<=i;k++)
       p=p->next; /* p指向插入点所在块 */
     q=(Chunk*)malloc(sizeof(Chunk)); /* 生成新块 */
     for(i=0;i<j;i++)
       *(q->ch+i)=blank; /* 块q的前j个字符为填补空余的字符 */
     for(i=j;i<CHUNKSIZE;i++)
     {
       *(q->ch+i)=*(p->ch+i); /* 复制插入点后的字符到q */
       *(p->ch+i)=blank; /* p的该字符为填补空余的字符 */
     }
     q->next=p->next;
     p->next=t.head;
     t.tail->next=q;
   }
   (*S).curlen+=t.curlen;
   Zip(S);
   return OK;
 }

 Status StrDelete(LString *S,int pos,int len)
 { /* 从串S中删除第pos个字符起长度为len的子串 */
   int i=1; /* 当前字符是S串的第i个字符(1~S.curlen) */
   Chunk *p=(*S).head; /* p指向S的当前块 */
   int j=0; /* 当前字符在当前块中的位序(0~CHUNKSIZE-1) */
   if(pos<1||pos>(*S).curlen-len+1||len<0) /* pos,len的值超出范围 */
     return ERROR;
   while(i<pos) /* 找第pos个字符 */
   {
     while(*(p->ch+j)==blank) /* 跳过填补空余的字符 */
     {
       j++;
       if(j==CHUNKSIZE) /* 应转向下一块 */
       {
         p=p->next;
         j=0;
       }
     }
     i++; /* 当前字符是S的第i个字符 */
     j++;
     if(j==CHUNKSIZE) /* 应转向下一块 */
     {
       p=p->next;
       j=0;
     }
   }; /* i=pos,*(p->ch+j)为S的第pos个有效字符 */
   while(i<pos+len) /* 删除从第pos个字符起到第pos+len-1个字符 */
   {
     while(*(p->ch+j)==blank) /* 跳过填补空余的字符 */
     {
       j++;
       if(j==CHUNKSIZE) /* 应转向下一块 */
       {
         p=p->next;
         j=0;
       }
     }
     *(p->ch+j)=blank; /* 把字符改成填补空余的字符来"删除"第i个字符 */
     i++; /* 到下一个字符 */
     j++;
     if(j==CHUNKSIZE) /* 应转向下一块 */
     {
       p=p->next;
       j=0;
     }
   };
   (*S).curlen-=len; /* 串的当前长度 */
   return OK;
 }

 Status Replace(LString *S,LString T,LString V)
 { /* 初始条件: 串S,T和V存在,T是非空串(此函数与串的存储结构无关) */
   /* 操作结果: 用V替换主串S中出现的所有与T相等的不重叠的子串 */
   int i=1; /* 从串S的第一个字符起查找串T */
   if(StrEmpty(T)) /* T是空串 */
     return ERROR;
   do
   {
     i=Index(*S,T,i); /* 结果i为从上一个i之后找到的子串T的位置 */
     if(i) /* 串S中存在串T */
     {
       StrDelete(S,i,StrLength(T)); /* 删除该串T */
       StrInsert(S,i,V); /* 在原串T的位置插入串V */
       i+=StrLength(V); /* 在插入的串V后面继续查找串T */
     }
   }while(i);
   return OK;
 }

 void StrPrint(LString T)
 { /* 输出字符串T。另加 */
   int i=0,j;
   Chunk *h;
   h=T.head;
   while(i<T.curlen)
   {
     for(j=0;j<CHUNKSIZE;j++)
       if(*(h->ch+j)!=blank) /* 不是填补空余的字符 */
       {
         printf("%c",*(h->ch+j));
         i++;
       }
     h=h->next;
   }
   printf("\n");
 }

 void DestroyString()
 { /* 块链类型的字符串无法销毁 */
 }

 

 /* main4-3.c 检验bo4-3.c的主程序 */
 char blank='#'; /* 全局变量,用于填补空余 */
 #include"c1.h"
 #include"c4-3.h"
 #include"bo4-3.c"
 void main()
 {
   char *s1="ABCDEFGHI",*s2="12345",*s3="",*s4="asd#tr",*s5="ABCD";
   Status k;
   int pos,len;
   LString t1,t2,t3,t4;
   InitString(&t1);
   InitString(&t2);
   printf("初始化串t1后,串t1空否?%d(1:空 0:否) 串长=%d\n",StrEmpty(t1),StrLength(t1));
   k=StrAssign(&t1,s3);
   if(k==OK)
   {
     printf("串t1为: ");
     StrPrint(t1);
   }
   else
     printf("出错\n"); /* 不能生成空串 */
   k=StrAssign(&t1,s4);
   if(k==OK)
   {
     printf("串t1为: ");
     StrPrint(t1);
   }
   else
     printf("出错\n"); /* 不能生成含有变量blank所代表的字符的串 */
   k=StrAssign(&t1,s1);
   if(k==OK)
   {
     printf("串t1为: ");
     StrPrint(t1);
   }
   else
     printf("出错\n");
   printf("串t1空否?%d(1:空 0:否) 串长=%d\n",StrEmpty(t1),StrLength(t1));
   StrAssign(&t2,s2);
   printf("串t2为: ");
   StrPrint(t2);
   StrCopy(&t3,t1);
   printf("由串t1拷贝得到串t3,串t3为: ");
   StrPrint(t3);
   InitString(&t4);
   StrAssign(&t4,s5);
   printf("串t4为: ");
   StrPrint(t4);
   Replace(&t3,t4,t2);
   printf("用t2取代串t3中的t4串后,串t3为: ");
   StrPrint(t3);
   ClearString(&t1);
   printf("清空串t1后,串t1空否?%d(1:空 0:否) 串长=%d\n",StrEmpty(t1),StrLength(t1));
   Concat(&t1,t2,t3);
   printf("串t1(=t2+t3)为: ");
   StrPrint(t1);
   Zip(&t1);
   printf("去除不必要的占位符后,串t1为: ");
   StrPrint(t1);
   pos=Index(t1,t3,1);
   printf("pos=%d\n",pos);
   printf("在串t1的第pos个字符之前插入串t2,请输入pos: ");
   scanf("%d",&pos);
   k=StrInsert(&t1,pos,t2);
   if(k)
   {
     printf("插入串t2后,串t1为: ");
     StrPrint(t1);
   }
   else
     printf("插入失败!\n");
   printf("求从t1的第pos个字符起,长度为len的子串t2,请输入pos,len: ");
   scanf("%d,%d",&pos,&len);
   SubString(&t2,t1,pos,len);
   printf("串t2为: ");
   StrPrint(t2);
   printf("StrCompare(t1,t2)=%d\n",StrCompare(t1,t2));
   printf("删除串t1中的子字符串:从第pos个字符起删除len个字符。请输入pos,len:");
   scanf("%d,%d",&pos,&len);
   k=StrDelete(&t1,pos,len);
   if(k)
   {
     printf("从第%d位置起删除%d个元素后串t1为:",pos,len);
     StrPrint(t1);
   }
 }

 

分享到:
评论

相关推荐

    数据结构C语言版 串的块链存储表示和实现.pdf

    数据结构 C 语言版 串的块链存储表示和实现 本文档主要讲解了数据结构中的串的块链存储表示和实现,使用 C 语言编写。该文档提供了详细的实现代码和注释,供读者学习和参考。 1. 串的块链存储表示 在本文档中,串...

    数据结构C语言版 串的块链存储表示和实现.docx

    数据结构C语言版串的块链存储表示和实现 数据结构是计算机科学中的一门基础课程,研究的是数据的存储、表示和操作。串是一种常见的数据结构,指的是一个字符序列。串的存储有多种方法,本文将介绍一种块链存储表示...

    掌握串的基本处理操作和几种不同的存储结构(定长顺序存储表示、堆分配存储表示和块链存储表示)

    掌握串的基本处理操作和几种不同的存储结构(定长顺序存储表示、堆分配存储表示和块链存储表示)。 二、 实验要求 1、 实现串赋值、串比较、求串长、串联接以及求子串这5种基本操作。 2、 能利用上述实现的基本操作...

    掌握串的基本处理操作和几种不同的存储结构(定长顺序存储表示、堆分配存储表示和块链存储表示)。

    1、 实现串赋值、串比较、求串长、串联接以及求子串这5种基本操作。 2、 能利用上述实现的基本操作完成置换Replace (&S, T, V)以及从串中删除一段子串StrDelete(&S,pos,len)的操作。 3、 以上要求实现的操作不能直接...

    串思维导图(字符串).pdf

    字符串的存储结构可以分为顺序存储表示、链式存储表示和块链存储表示三种。 顺序存储表示 顺序存储表示是指将字符串存储在一块连续的内存空间中,例如,可以使用数组来存储字符串,例如`typedef unsigned char S...

    数据结构C语言版第四章课件严蔚敏PPT学习教案.pptx

    串的实现方式有三种:定长顺序存储表示、堆分配存储表示、块链存储表示。 1. 定长顺序存储表示:使用一组地址连续的存储单元存储串的字符序列,超出预定义长度的串值被舍去,称之为“截断”。 2. 堆分配存储表示:...

    数据结构c语言班 PPT 串 第四章

    - **串的块链存储表示**:在块链存储中,串被分为若干块,每一块存储一部分字符,通过指针连接这些块,这样可以适应串长度的变化。 **4.3 串的模式匹配算法** 模式匹配是串处理中的一个重要问题,比如查找一个子串...

    数据结构课件:第四章 串.ppt

    数据结构:串 本节内容主要介绍了串的基本概念、存储结构、操作和模式匹配算法。串是由零个或多个字符组成的有限序列,也称字符串。...4. 了解串的块链存储结构。 重难点内容 * 串的存储结构 * KMP 算法思想

    数据结构串部分内容PPT

    3. **块链存储表示**:使用链表结构,每个结点存储一部分字符,这种方式适用于处理长串,便于插入和删除操作,但访问速度相对较慢。 串操作包括但不限于以下几种基本操作: - **StrAssign**: 初始化或赋值操作,...

    数据结构:第4章 串.ppt

    串的表示和实现有多种方法,常见的有定长顺序存储表示、堆分配存储表示和块链存储表示等。其中,定长顺序存储表示是最常用的方法,它将串的字符序列存储在一块连续的存储单元中,串的长度信息通常存储在数组的第一个...

    串类型的定义串的表示和实现串的模式匹配算法PPT学习教案.pptx

    3. 块链存储:将字符串分成若干块,每块存储在一个链表节点中,便于动态扩展和管理。 【串的模式匹配算法】 串的模式匹配算法主要用于在主串中查找是否存在某个特定的子串。常见的模式匹配算法有朴素匹配算法和KMP...

    数据结构中的串PPT学习教案.pptx

    串的表示方式有多种,其中包括定长顺序存储、堆分配存储和块链存储。定长顺序存储是最简单的形式,通常在内存中分配固定大小的数组来存储串,适合于处理长度确定或变化不大的串。堆分配存储则更灵活,可以根据需要...

    数据结构:第4章串B.ppt

    3. 串的块链存储表示:类似于链表,采用链式结构存储串,每个节点包含一个字符和指向下一个节点的指针。这种方式允许串的长度动态增长,但不如顺序存储方式访问速度快。 4.8、4.10、4.30、4.31 这些题目可能涉及到...

    数据结构 串的介绍,对数据结构初学者很有用的

    - **串的块链存储表示**:使用链表结构,每个节点存储一部分字符,适用于大串处理,便于插入和删除。 在处理大规模文本数据时,模式匹配算法是重要的工具,如KMP算法、Boyer-Moore算法等,它们能在较短的时间内找出...

    数据结构课件——串(C/C++)

    3. **串的块链存储表示**:采用链表结构,每个结点包含一个或多个字符,存储密度是串值所占的存储位与实际分配存储位的比例。 串的基本操作包括: - **串插入**:在指定位置插入一个子串,如`StrInsert`函数。 - **...

    数据结构与算法基础课程 C语言C++程序语言设计教程 4_1串 共18页.pptx

    3. **串的块链存储表示**:通过链表的形式存储串,适用于长度不确定的情况。 #### 四、模式匹配算法 模式匹配是串处理中的一个重要内容,主要包括: 1. **定义**:在串中寻找子串(第一个字符)在串中的位置。 2....

    数据结构课件第四章PPT学习教案.pptx

    - **串的块链存储表示**:适用于大串处理,通过链表结构将串的各个部分链接起来,方便插入和删除操作。 **串的操作** 1. **StrAssign(&T, chars)**:用于赋值,创建一个值为chars的新串T。 2. **StrCompare(S, T)...

    第4章 串.ppt

    3. **块链存储**:在链表中存储串,每个节点包含一部分串,适用于处理长度不固定的大型串。 这些不同的存储方式各有优缺点,定长顺序存储节省空间,但可能受限于最大长度;堆分配存储灵活,但涉及内存管理;块链...

    数据结构第4章串PPT学习教案.pptx

    3. 块链存储表示:也称为链式存储,适用于大字符串处理。每个串元素存储在一个单独的节点中,节点之间通过指针链接,形成一个链表。这种方式可以更有效地处理大小不一的串,但增加了访问速度上的开销。 串的模式...

Global site tag (gtag.js) - Google Analytics