数据结构学习笔记 第四章 串

第四章 串

4.1串的基本概念

  • 字符串是零个或多个字符组成的有限序列。
  • 子串:串中任意个连续字符组成的子序列。
  • 主串:包含字串的串称为主串。
  • 字串在主串中的位置:以字串第一个字符所在的位置表示,即下标+1.
  • 串相等:两个串值相等,即长度内容一样。
ADT 串 (String)

Data
	串中的元素仅由一个字符组成,相邻元素具有前驱和后继关系.
	
Operation
StrAssign (&T, chars)
	初始条件:chars是字符串常量。
	操作结果:生成一个其值等于chars的串T。
StrCopy (&T, S)
	初始条件:串S存在。
	操作结果:由串S复制得串T。
StrEmpty(S)
	初始条件:串S存在。
	操作结果:若S为空串,则返回TRUE,否则返回FALSE。 
StrCompare(S, T)
	初始条件:串S和T存在。
	操作结果:若S>T,则返回值>0;若S=T,则返回值=0;若S < T,则返回值 < 0StrLength(S)
	初始条件:串S存在。
	操作结果:返回S的元素个数,称为串的长度。
ClearString (&S)
	初始条件:串S存在。
	操作结果:将S清为空串。
Concat (&T, S1, S2)
	初始条件:串S1和S2存在。
	操作结果:用T返回由S1和S2联接而成的新串。
SubString(&Sub, S, pos, len)
	初始条件:串S存在,1≤pos≤StrLength(S)0≤len≤StrLength(S)-pos+1
	操作结果:用Sub返回串S的第pos个字符长度为len的子串。
Index(S, T, pos)
	初始条件:串S和T存在,T是非空串,1≤pos≤StrLength(S)。
	操作结果:若主串S中存在和串T值相同的子串,则返回它在主串S中第pos个字符之后第一次出现的位置;否则函数值为0。
Replace (&S, T, V)
	初始条件:串S, T和V存在,T是非空串。
	操作结果:用V替换主串S中出现的所有与T相等的不重叠的子串。
StrInsert (&S, pos, T)
	初始条件:串S和T存在, 1≤pos≤StrLength(S)+1。
	操作结果:在串S的第pos个字符之前插入串T。
StrDelete (&S, pos, len)
	初始条件:串S存在, 1≤pos≤StrLength(S)-len+1。
	操作结果:从串S中删除第pos个字符起长度为len的子串。
DestroyString (&S)
	初始条件:串S存在。
	操作结果:串S被销毁。

endADT

4.2串的存储实现

4.2.1定长顺序串

1.定长顺序串储存结构
#define MAXLEN 40

typedef struct{
    char ch[MAXLEN];
    int len;
}SString;
2.定长顺序串基本操作的实现
(1)串比较函数
void StrCompare(SString s,SString t)
{
    int i;
    for (i = 0; (i < s.len) && (i<t.len); i++)
        if(s.ch[i] != t.ch[i])
            return(s.ch[i] - t.ch[i]);
    return(s.len - t.len);
}
(2)串删除函数
int StrDelete(SString *s, int pos, int len)
/*在串s中删除从下标pos起len个字符*/
{ 
	int i;
	if (pos<0 || pos>(s->len-len))/*删除参数不合法*/
		return(0); 
	for (i=pos+len;i<s->len;i++)
		s->ch[i-len]=s->ch[i]; /*从pos+len开始至串尾依次向前移动,实现删除len个字符*/
	s->len=s->len - len; /*s串长减len*/
	return(1);
}
(3)串插入函数
int StrInsert(SString *s, int pos, SString t)
/*在串s中下标为pos的字符之前插入串t */
{
	int i;
	if (pos<0 || pos>s->len) /*插入位置不合法*/
		return(0); 
	if (s->len + t.len<=MAXLEN) /*插入后串长≤MAXLEN*/
	{
		for (i=s->len + t.len-1;i>=t.len + pos;i--)
			s->ch[i]=s->ch[i-t.len];
		for (i=0;i<t.len;i++) 
			s->ch[i+pos]=t.ch[i];
		s->len=s->len+t.len;
	}
	else
	{
		if (pos+t.len<=MAXLEN) /*插入后串长>MAXLEN,但串t的字符序列可以全部插入*/
		{
			for (i=MAXLEN-1;i>t.len+pos-1;i--) 
				s->ch[i]=s->ch[i-t.len];
			for (i=0;i<t.len;i++)
				s->ch[i+pos]=t.ch[i];
			s->len=MAXLEN;
		}
		else /*插入后串长>MAXLEN,并且串t的部分字符也要舍弃*/
		{ 
			for (i=0;i<MAXLEN-pos;i++)
				s->ch[i+pos]=t.ch[i];
			s->len=MAXLEN;
		}
		return(1);
	}
}

(4)定位函数
Brute_Force(暴力查找) O(n*m)
int StrIndex(SString s,int pos, SString t) 
/*求从主串s的下标pos起,串t第一次出现的位置,成功返回位置序号,不成功返回-1*/
{ 
	int i, j, start;
	if (t.len==0)  
		return(0);   /* 模式串为空串时,是任意串的匹配串 */
	start=pos; 
	i=start; 
	j=0;  /* 主串从pos开始,模式串从头(0)开始 */
	while (i<s.len && j<t.len)
		if (s.ch[i]==t.ch[j]) 
		{
			i++;
			j++;
		}   /* 当前对应字符相等时推进 */
		else 
		{ 
			start++;        /* 当前对应字符不等时回溯 */
			i=start; 
			j=0;   /* 主串从start+1开始,模式串从头(0)开始*/
		} 
		if (j>=t.len) 
			return(start);    /* 匹配成功时,返回匹配起始位置 */
		else 
			return(-1);    /* 匹配不成功时,返回-1 */
}

Kmp算法

这里有个视频教程,讲的很好。

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

void prefix_table(char pattern[], int prefix[], int n)
{
    prefix[0] = 0;
    int len = 0;
    int i = 1;
    while(i<n)
    {
        if(pattern[i] == pattern[len]){
            len++;
            prefix[i] = len;
            i++;
        }else{
            if(len > 0)
            len = prefix[len -1];  
        }else{
            prefix[i] = 0;
        }
    }
}

void move_prefix_table(int prefix[], int n){
    int i;
    for(i = n-1; i > 0; i--){
        prefix[i] = prefix[i - 1];
    }
    prefix[0] = -1;
}

void kmp_search(char text[], char patern[])
{
    int n = strlen(pattern);
    int m = strlen(text);
    int *prefix = malloc(sizeof(int) *n);
    prefix_table(pattern, prefix, n);
    move_prefix_table(prefix,n);
    
    //text[i]     len(text) = m
    //patern[j]   len(patern) = n
    
    int i = 0;
    int j = 0;
    while(i < m){
        if (j == n-1 &&text [i] == pattern[j]){
            printf("Found pattern at %d\n", i-j);
            j = prefix[j];
        }
        if(text[i] == patern[j]){
            i++; j++;
        }else{
            j = prefix[j];
            if(j == -1){
                i++;j++;
            }
        }
    }
}

4.2.2堆串

堆串存储方法:以一组地址连续的存储单元存储,空间是动态分配的。

串名符号表:串名,串值之间建立一个对应关系。

堆串存储表示:

typedef struct
{
    char* ch;
    int len;
}HString;

int	StrInsert(HString *s,int pos,HString *t)
/*在串s中下标为pos的字符之前插入串t */
{ 
	int i;
	char *temp;
	if (pos<0 || pos>s->len || s->len==0) 
		return(0);/*插入位置不合法*/
	temp=(char *)malloc(s->len + t->len);
	if (temp==NULL) 
		return(0);/*动态空间申请失败*/
	for (i=0;i<pos;i++) 
		temp[i]=s->ch[i];
	for (i=0;i<t->len;i++) 
		temp[i+pos]=t->ch[i];
	for (i=pos;i<s->len;i++) 
		temp[i + t->len]=s->ch[i];
	s->len+=t->len;
	free(s->ch);
	s->ch=temp;
	return(1);
}

int StrAssign(HString *s, char *tval)
/*将字符串常量tval的值赋给堆串s */
{
	int len, i=0;
	if (s->ch!=NULL) 
		free(s->ch);
	while (tval[i]!='\0')
		i++;
	len=i;
	if (len) 
	{
		s->ch=(char *)malloc(len);
		if (s->ch==NULL) 
			return(0);
		for (i=0;i<len;i++) 
			s->ch[i]=tval[i];
	}
	else
		s->ch=NULL;
	s->len=len;
	return(1);
}

int	StrDelete(HString *s, int pos,int len)
/*在串s中删除从下标pos起len个字符 */
{ 
	int i;
	char *temp;
	if (pos<0 || pos>(s->len - len)) 
		return(0);/*插入位置不合法*/
	temp=(char *)malloc(s->len - len);
	if (temp==NULL) 
		return(0);
	for (i=0;i<pos;i++)
		temp[i]=s->ch[i];
	for (i=pos;i<s->len - len;i++)
		temp[i]=s->ch[i+len];
	s->len=s->len-len;
	free(s->ch);
	s->ch=temp;
	return(1);
}

4.2.3块链串

​ 由于串是一种线性表,可采用链式存储。一个结点可以放一个或者多个字符。每个结点称为块,整个链表称为快链结构。

#define BLOCK_SIZE 4/*每结点存放字符个数为4*/

typedef struct Block{
    char ch [BLOCK_SIZE];
    struct Block *next;
} Block;

typedef struct{
    Block *head;
    Block *tail;
    int len;
}BLString;
  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值