数据结构-串的定长顺序存储

串的定长顺序存储类似于线性表的顺序存储结构,用一组连续的存储单元存储串值的字符序列。

在串的定长顺序存储结构中,按照预定义的大小,为每个定义的串变量分配一个固定长度的存储区,则可以用定长数组表示:

1 /*串定长顺序存储表示*/
2 #define MAXSTRLEN 255        //串在MAXSTRLEN大小
3 typedef unsigned char SString[MAXSTRLEN + 1];    //所有串的0号单元存储串的长度

串的基本操做函数如下:

  1 /*生成一个其值等于chars的串T*/
  2 Status StrAssign(SString &T, char chars[])
  3 {
  4     if(strlen(chars) > MAXSTRLEN)
  5         return ERROR;
  6     T[0] = strlen(chars);
  7     for (int i = 0; i <= T[0]; i++)
  8         T[i+1] = chars[i];
  9     return OK;
 10 }
 11
 12 /*由串S赋值的到串T*/
 13 Status StrCopy(SString &T, SString S)
 14 {
 15     int i = 1;
 16     for (; i <= S[0]; i++)
 17         T[i] = S[i];
 18     T[0] = S[0];
 19     return OK;
 20 }
 21
 22 /*判断串S是否为空,若S为空串侧返回true,否则返回false*/
 23 bool StrEmpty(SString s)
 24 {
 25     if(s[0] == 0)
 26         return true;
 27     else
 28         return false;
 29 }
 30
 31 /*若S>T,则返回值大于0;若S=T,则返回值等于0;若S<T则返回值小于0*/
 32 Status StrCompare(SString S, SString T)
 33 {
 34     for (int i = 1; i <= S[0] && i <= T[0]; ++i)
 35         if(S[i] != T[i])
 36             return S[i] - T[i];
 37     return S[0] - T[0];
 38 }
 39
 40 /*返回串的长度*/
 41 int StrLength(SString S)
 42 {
 43     return S[0];    //串的第0个存储放的串的长度
 44 }
 45
 46 /*重置串为空串*/
 47 Status ClearString(SString &S)
 48 {
 49     S[0] = 0;    //因为是顺序存储,只要将长度标志设为0即是代表已经清空串
 50     return OK;
 51 }
 52
 53 /*用T返回由串S1和串S2连接成的新串。若未截断,则返回true,否则返回false*/
 54 bool Concat(SString &T, SString S1, SString S2)
 55 {
 56     bool uncut = true;
 57     if(S1[0] + S2[0] <= MAXSTRLEN)    //未截断
 58     {
 59         for (int i = 1; i <= S1[0]; i++)
 60             T[i] = S1[i];
 61         for (int i = 1; i <= S2[0]; i++)
 62             T[i + S1[0]] = S2[i];
 63         T[0] = S1[0] + S2[0];
 64         uncut = true;
 65     }
 66     else if(S1[0] < MAXSTRLEN)    //截断;只取S2的一部分
 67     {
 68         int i = 1;
 69         for ( ; i <= S1[0]; i++)
 70             T[i] = S1[i];
 71         for (i = 1; i <= MAXSTRLEN-S1[0]; i++)
 72             T[i + S1[0]] = S2[i];
 73         T[0] = MAXSTRLEN;
 74         uncut = false;
 75     }
 76     else                    //截断;仅取S1
 77     {
 78         for (int i = 0; i <= MAXSTRLEN; i++)
 79             T[i] = S1[i];
 80         uncut = false;
 81     }
 82     return uncut;
 83 }
 84
 85 /*用sub返回串S的第pos个字符起的长度为len的子串*/
 86 Status SubString(SString &Sub, SString S, int pos, int len)
 87 {
 88     if(pos < 1 || pos > S[0] || len < 0 || len > S[0]-pos+1)
 89         return ERROR;
 90     for (int i = 1; i <= len; i++)
 91         Sub[i] = S[pos+i-1];
 92     Sub[0] = len;
 93     return OK;
 94 }
 95 /*用串V替换主串中出现的所有*/
 96 Status Replace(SString &S, SString T, SString V)
 97 {
 98     if(StrEmpty(T))
 99         return ERROR;
100     int i = 1, j = 1;
101     int m = StrLength(T), n = StrLength(V);
102     while(i <= S[0])
103     {
104         j = Index(S,T,i);
105         StrDelete(S,j,m);
106         StrInsert(S,j,V);
107         i+=n+1;
108     }
109     return OK;
110 }
111
112 /*在串S的pos位置之前插入串T*/
113 Status StrInsert(SString &S, int pos, SString T)
114 {
115     if(pos < 1 || pos > S[0]+1)
116         return ERROR;
117     if(S[0]+T[0] <= MAXSTRLEN)    //完全插入
118     {
119         for (int i = S[0]; i >= pos; i--)
120             S[i+T[0]] = S[i];
121         for (int i = pos; i < pos+T[0]; i++)
122             S[i] = T[i-pos+1];
123         S[0] = S[0]+T[0];
124         return OK;
125     }
126     else    //不完全插入
127     {
128         for (int i = MAXSTRLEN; i >= pos; i--)
129             S[i] = S[i-T[0]];
130         for (int i = pos; i < pos+T[0]; i++)
131             S[i] = T[i-pos+1];
132         S[0] = MAXSTRLEN;
133         return ERROR;
134     }
135 }
136
137 /*从串S中删除第pos个字符起的长度为len的子串*/
138 Status StrDelete(SString &S, int pos, int len)
139 {
140     if(pos < 1 || pos > S[0]-len+1 || len < 0)
141         return ERROR;
142     for (int i = pos+len; i <= S[0]; i++)
143         S[i-len] = S[i];
144     S[0] -= len;
145     return OK;
146 }
147
148 /*销毁串S*/
149 Status DestroyString(SString &S)
150 {
151     free(S);
152     return OK;
153 }
154
155 /*输出串*/
156 void StrPrint(SString T)
157 {
158     for (int i = 1; i <= T[0]; i++)
159         printf("%c",T[i]);
160     printf("\n");
161 }

还有一个函数Index函数。做字符串匹配用,这里拿出来单独讨论

 1 /*若主串S中存在和串T值相同的子串;
 2 /*则返回他在主串S中第pos个字符之后第一次出现的位置;
 3 /*否则函数值为0*/
 4 int Index(SString S, SString T, int pos)
 5 {
 6     /*调用串基本操作的方法,也是Index函数的思想步骤*/
 7     //if(pos > 0)
 8     //{
 9     //    int n = StrLength(S);    //获取串的长度
10     //    int m = StrLength(T);
11     //    int i = pos;
12     //    SString sub;
13     //    while(i <= n-m+1)        //循环值从pos到串S的最后一个T长度位置
14     //    {
15     //        SubString(sub,S,i,m);    //获取子串,S的第i个位置开始长度m-1的子串
16     //        if(StrCompare(sub,T) != 0)    //判断获取的子串与串T是否不等;如果相等返回i的值也就是第一次出现的位置
17     //            ++i;
18     //        else
19     //            return i;
20     //    }
21     //}
22     //return 0;    //没有出现返回0
23
24     /*定位函数Index的模式匹配算法
25     /*算法的基本思想:
26     /*从主串S的第pos个字符起和模式的第一个字符比较之,
27     /*若相等,则继续逐个比较后续字符;
28     /*否则从主串的下一个字符起再重新和模式的字符比较之。
29     /*以此类推,直至模式T中的每个字符依次和主串S中的一个连续的字符序列相等,则匹配成功;
30     /*函数值为和模式T中的第一个字符相等的字符在主串S中的序号。
31     /*否则匹配不成功,函数值为零。*/
32     int i = pos,j = 1;
33     while(i <= S[0] && j <= T[0])
34     {
35         if(S[i] == T[j])    //继续比较后续字符
36         {
37             i++;
38             j++;
39         }
40         else    //指针后退重新开始匹配
41         {
42             i = i-j+2;
43             j = 1;
44         }
45     }
46     if(j > T[0])
47         return i - T[0];    //匹配成功
48     return 0;                //匹配失败
49 }

其中这个函数内写了两种方法:第一种调用基本函数的方法,第二种模式匹配算法。

但模式匹配算法还有一个很是经典的算法模式匹配的改进算法-KMP算法;

其改进在于:每当一趟匹配过程中出现字符比较不等时,不需回溯i指针,而是利用已经得到的“部分匹配”的结果将模式向右滑动尽可能远的一段距离后,继续进行比较。

KMP算法的基本思想就是这样,剩下的百度搜索全是我就不再细说,还是按我的习惯直接上代码。

 1 void get_next(SString T, int *next) {
 2   int i=1;
 3   next[1]=0;
 4   int j=0;
 5   while (i<T[0]) {
 6     if(j==0 || T[i]== T[j]) {
 7       ++i;  ++j;  next[i] = j;
 8     } else j= next[j];
 9   }
10 }
11
12 int Index_KMP(SString S, SString T, int pos) {
13   // 利用模式串T的next函数求T在主串S中第pos个字符之后的位置的
14   // KMP算法。其中,T非空,1≤pos≤StrLength(S)。
15   int next[255];
16   int i = pos;
17   int j = 1;
18   get_next(T, next);
19   while (i <= S[0] && j <= T[0]) {
20     if (j == 0 || S[i] == T[j]) {  // 继续比较后继字符
21       ++i;  ++j;
22     } else j = next[j]; // 模式串向右移动
23   }
24   if (j > T[0]) return  i-T[0];   // 匹配成功
25   else return 0;
26 }

KMP算法时间复杂度O(m)。通常,模式串的长度m比主串的长度n要小的多,因此对整个匹配算法来说,所增加的这点时间是值得的。

但是,虽然模式匹配算法时间复杂度是O(n*m),但是一般情况下,其实际的实行时间近似于O(n+m),因此至今仍被采用。

KMP算法仅当模式与主串之间存在许多“部分匹配”的情况下才显得比模式匹配算法快得多。但是KMP算法的最大特点是指主串的指针不需回溯,整个匹配过程中,对主串仅需从头至尾扫描一遍,这对处理从外设输入的庞大文件很有效,可以边读入边匹配,而无需回溯重读。

但对于next函数前面所写的在某些情况下有一个缺陷,例如在模式aaaab,主串aaabaaaab匹配时,当i=4,j=4时ch[4]!=t.ch[4]。由next[j]的指示还需要进行i=4,j=3;i=4,j=2;i=4,j=1这三次比较。实际上,因为模式中第1,2,3个字符和第4个字符都相等,因此不必要在和主串中第4个字符相比较,而可以将模式一下子滑动4个位置。直接进行i=5,j=1时的字符比较。

j 1 2 3 4 5
    模式 a a a a b
   next[j] 0 1 2 3 4
nextval[j] 0 0 0 0 4

改进的next函数如下:此时匹配算法不变;

void get_nextval(SString T, int *nextval) {
  // 求模式串T的next函数修正值并存入数组nextval。
  int i = 1;
  int j = 0;
  nextval[1] = 0;
  while (i<T[0]) {
    if (j==0 || T[i]==T[j]) {
      ++i;  ++j;
      if (T[i]!=T[j]) nextval[i] = j;
      else nextval[i] = nextval[j];
    }
    else j = nextval[j];
  }
}
时间: 2024-08-25 14:15:12

数据结构-串的定长顺序存储的相关文章

C语言实现数据结构串(定长顺序存储表示法)

-------------------------------------------- 定长顺序存储表示法 -------------------------------------------- 存储结构: 使用字符串数组作为存储,定义字符串数组长度为MAXSTRLEN+1(0位置用来存放字符串长度) -------------------------------------------- 操作方法: 字符串赋值 通过将控制台输入的字符串赋值给串S1(从1开始存储),如果字符串长度超过限制,

串的定长顺序存储表示

串的定长顺序存储表示是一种类似于线性表的顺序存储结构,用一组地址连续的存储单元存储串值的字符序列. 在实现时主要实现以下功能: int Length(SString s);                               //串长 bool StringConcat(SString T, SString s1, SString s2);//用T返回s1和s2连接的串 void PrintString(char T[]);                          //输出 b

“串”的定长顺序存储表示的实现

串--数据结构的实现--定长存储顺序. //头文件sstring.h #pragma once #include<iostream> using namespace std; #define STRING_SIZE 20 typedef char Sstring[STRING_SIZE+1]; int length(Sstring S) { return strlen(S); } void StrAssign(Sstring T, char *str) { int i=0; while(*st

字符串定长顺序存储表示模板

1 ///page71 2 ///测试样例:nihao 3 ///output 4 /*5 5 5 nihao 6 0 7 10 nihaonihao 8 4 aoni 9 4 10 14 nihaoaoninihao 11 9 noninihao 12 13 nombxzmbxzhao*/ 13 #include <stdio.h> 14 #include <stdlib.h> 15 #include<string.h> 16 #include <malloc.

数据结构 - 串的存储表示和实现

串的基本概念 字符串:应用在非数值处理.事务处理等领域. 计算机的硬件:主要是反映数值计算的要求. 字符串的处理比具体数值处理复杂. 串(字符串):是零个或多个字符组成的有限序列.记作: S="a1a2a3-",其中S是串名,ai(1≦i≦n)是 单个字符,可以是字母.数字或其它字符. 串值:双引号括起来的字符序列,引号不属于串的内容. 串长:串中所包含的字符个数. 空串(空的字符串):长度为零的串,它不包含任何字符. 空格串(空白串):构成串的所有字符都是空格. 注意:空串和空白串的

数据结构串

串的逻辑结构和线性表相似,区别仅为串的数据对象约束为字符集串的基本操作和线性表有很大差别,线性表的基本操作中大多以的“单个元素”作为操作对象:而串的基本操作中通常以“串的整体”作为 操作对象 串的表示:1.定长顺序存储表示: 超过预定义长度的串值则被舍弃,称为“截断” 对串长的表示方法:在下标为0的数组分量存放串的实际长度:在串值后面加一个结束标记字符“\0”2.堆分配存储表示: 仍以一组地址连续的存储单元存放,但存储空间是在程序执行过程中动态分配的 C中动态分配函数:malloc(),free

C语言实现数据结构串(堆分配存储表示法)

-------------------------------------------- 堆分配存储表示法 -------------------------------------------- 存储结构: 构建堆来存储字符串,本质上是顺序表 -------------------------------------------- 实现代码: 1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <string.h>

数据结构 - 串的性质和基本操作(二)

串的顺序存储结构 ①定长顺序存储 结构类型: #define MAXSTRLEN 255 // 用户可在255以内定义最大串长 typedef unsigned char SString[MAXSTRLEN+1]; // 0号单元存放串的长度 分析: (1) 串的实际长度可在这个预定义长度的范围内随意设定,超过预定义长度的串值则被舍去,称之为"截断" (2) 按这种串的表示方法实现串的运算时,其基本操作为"字符序列的复制" 串的联接算法中需分三种情况处理 (第一种情

180607-手写定长数组

文章链接:https://liuyueyi.github.io/hexblog/2018/06/07/180607-手写定长数组/ 手写定长数组 有个背景场景如下: 一天划分为1440分钟,每分钟记录一个数据块,然后用一个数据结构存储着1440个数据块,随着时间的推移,每过一分钟,向这个数据结构中添加一块,并移除最前的那个:其次就是我希望根据当前的时间,可以获取往前n分钟的数据块 简单来说,上面的需求解析如下: 一个数组,容量为1440 频繁的新增和删除 随机的访问 后面两个就限制了ArrayL