文字描述:

串,就是字符串的意思。在数据结构中,串的存储方式有三种:定长顺序存储表示、堆分配存储表示和块链存储表示:

定长顺序存储表示:  以一组地址连续的存储单元存放字符序列,按照预定义的大小,为每个定义的串变量分配一个固定长度的存储区。超出预定义的串值会被舍弃,成为“截断”。

堆分配存储表示: 以一组地址连续的存储单元存放字符序列,但它们的存储空间是在执行时动态分配而得。

块链存储表示: 和线性表的链式存储结构类似,如下图,一个是结点大小为1的链表,一个是结点大小为4的链表;在链式存储方式中,结点大小的选择很重要,太小的话,虽然运算方便但是存储占用量大;如果太大的话,会太浪费空间。另外,它除了连接字串方便外,其他也不如前面两种存储方式灵活,一般都不用。

串->串的表示和实现

 

 

串的求子串的定位函数:返回子串在主串中的位置。

方法一,通用做法,如下图主串位置在匹配过程中可能会后退

串->串的表示和实现

 

方法二:模式匹配的一种改进算法KMP。主串匹配的下标一直前进,没有后退。关于这个算法,虽然KMP实现的代码很短,还是并不容易理解,可以参考下https://www.cnblogs.com/ZuoAndFutureGirl/p/9028287.html

串->串的表示和实现

 

方法三:优化后的KMP。按照方法二的KMP算法,在某些情况下是有缺陷的,比如主串为“aaabaaaab”, 子串为”aaaab”的时候,匹配时,当i=4、j=3时,S.ch[4] != T.ch[4],有next[j]指示还需进行i=4,j=3; i=4,j=2; i=4,j=1这3次比较。显然j=3、2、1都为’a’,和主串中i=4的比较结果都是一样的,可以将模式一气向右滑动4个字读的位置直接进行i=5、j=1的字符比较。

串->串的表示和实现

 

算法分析:

一般方法求子串在主串中的位置下标的时间复杂度为n*m

而KMP算法求子串在主串中的位置下标的时间复杂度为n+m, 另外在KMP中求串的next函数值的算法的时间复杂度为m。

 

代码实现:

串的定长顺序表示

 1 //
 2 // Created by Zhenjie Yu on 2019-04-14.
 3 //
 4 
 5 #include <stdio.h>
 6 #include <stdlib.h>
 7 #include <string.h>
 8 
 9 #define DEBUG
10 #ifdef DEBUG
11 #include <stdarg.h>
12 #define LOG(args...) _log_(__FILE__, __FUNCTION__, __LINE__, ##args);
13 static void _log_(const char *file, const char *function, int line, const char * format, ...)
14 {
15     char buf[1024] = {0};
16     va_list list;
17     va_start(list, format);
18     vsprintf(buf+strlen(buf), format, list);
19     sprintf(buf+strlen(buf), "\n");
20     va_end(list);
21     printf(buf);
22 }
23 #else
24 #define LOG
25 #endif // DEBUG
26 
27 #define MAX_STRING 255
28 typedef unsigned char SString[MAX_STRING+1]; //第一位表示串长
29 
30 static int Concat(SString T, SString S1, SString S2){
31     int uncut = -1;
32     if(S1[0]+S2[0] <= MAX_STRING){
33         snprintf(T+1, S1[0]+1, "%s", S1+1);
34         snprintf(T+1+S1[0], S2[0]+1, "%s", S2+1);
35         T[0] = S1[0] + S2[0];
36         uncut = 1;
37     }else if(S1[0] < MAX_STRING){
38         snprintf(T+1, S1[0]+1, "%s", S1+1);
39         snprintf(T+1+S1[0], MAX_STRING-S1[0]+1, "%s", S2+1);
40         T[0] = MAX_STRING;
41         uncut = 0;
42     }else{
43         snprintf(T+1, MAX_STRING+1, "%s", S1+1);
44         T[0] = MAX_STRING;
45         uncut = 0;
46     }
47     return uncut;
48 }
49 
50 static int StrAssign(SString T, const char chars[]){
51     memset(T, 0, MAX_STRING+1);
52     int len = strlen(chars);
53     if(len > MAX_STRING){
54         return -1;
55     }
56     T[0] = len;
57     snprintf(T+1, len+1, "%s", chars);
58     return 0;
59 }
60 
61 static int SubString(SString Sub, SString S, int pos, int len)
62 {
63     if(pos<1 || pos>S[0] || len<0 || len>(S[0]-pos+1)){
64         return -1;
65     }
66     snprintf(Sub+1, len+1, S+pos);
67     Sub[0] = len;
68     return 0;
69 }
70 
71 int main(int argc, char *arg)
72 {
73     SString S1, S2, T, Sub;
74     int ret = -1;
75 
76     StrAssign(S1, "test123");
77     LOG("设置串S1的值为%s, 长度为%d", S1+1, S1[0]);
78 
79     StrAssign(S2, "abcdef");
80     LOG("设置串S2的值为%s, 长度为%d", S2+1, S2[0]);
81 
82     ret = Concat(T, S1, S2);
83     LOG("连接串S1和S2,并保存到变量T中,连接后T为%s, T的长度为%d", T+1, T[0]);
84 
85     ret = SubString(Sub, T, 4, 6);
86     LOG("求主串T中,起始地址为4,长度为6的子串,子串结果保存咋变量Sub中; Sub的值为%s,长度为%d", Sub+1, Sub[0]);
87     return 0;
88 }
串的定长顺序表示

相关文章:

  • 2022-12-23
  • 2021-12-05
  • 2022-12-23
  • 2022-02-02
猜你喜欢
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2021-06-21
  • 2022-12-23
相关资源
相似解决方案