數據結構學習筆記 第四章 串

第四章 串

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;
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章