串(數據結構)

前言:

串就是我們所說的字符串,計算機對數據的處理主要包括數值計算和非數值計算,在計算機發展的早期,數值計算比較普遍,然而隨着社會的發展和計算需求的發展,在計算機上做非數值處理的計算越來越多,而在計算機上非數值處理大部分是對字符串的處理,處理這些字符串數據比起處理整型、浮點型數據都要複雜很多,所以把串作爲一種獨立的數據結構進行研究。


一.串導學

1.課程結構

(概述)
第1章 數據結構、ADT、算法

(基礎)
第2章 線性表
第3章 棧和隊列
第4章 字符串
第5章 數組與廣義表
第6章 樹和二叉樹
第7章 圖

(應用)
第9章 查找
第10章 內部排序
第11章 外部排序

2.知識點搜索

字符串還是一種線性結構,它的存儲也有順序和鏈式兩種結構實現,它的操作和線性表的c操作也是相同的,但是它的這些操作是針對字符串所特有的一些操作,所以我們只是簡單的討論一下串特有的邏輯結構以及操作的實現。
在這裏插入圖片描述

3.串也是一種數據結構

在c/c++中我們也瞭解過字符串了,但是在那裏更像是一種數據類型,而在這我們是當做數據結構。

串是一種特殊的線性表,特殊在:
(1)數據元素都來自字符集!
也就是說串中每一個元素的數據類型都是字符型的,他的數據對象是字符集。
(2)由於數據元素特殊,它的操作有些不同於一般線性表。
例如:操作對象一般是子串(即一組數據元素),而不是單個數據元素

4.串的應用

串的應用是十分廣泛的
比如:搜索引擎中的字符串查找匹配、文字處理軟件wps office、生物信息處理等等,這些實際上都是對字符串進行處理。

在這裏插入圖片描述

5.帶着問題去學習

數據結構中的“串” 和C/C++中的“串” 有何區別?
串與線性表的關係?
“串” 這種數據結構的作用?
掌握:
1.串的特點(與線性表的區別)
2.模式匹配算法(BF,KMP)

二.串的基本概念

1.串的定義

由零個或多個字符組成的有限序列
在這裏插入圖片描述
還要了解幾個定義:
(1)空串:含零個字符的串稱爲空串,用Ф表示。
空串是可以存在的,一定要區分開空串和空格串,空格串是指一個字符串是空格的。
(2)串長:串中所含字符的個數稱爲該串的長度(n)
(2)串的表示:S=“a1a2…an” ,每個ai(1≤i≤n)代表一個字符。

例子:
在這裏插入圖片描述

2.串的操作

操作:(與線性表同的略。因爲字符串是一種特殊的線性結構,所以也有與線性表相同的操作,在此省略)

(1)串相等:當且僅當兩個串的長度相等並且各個對應位置上的字符都相同,稱兩個串相等。
例如,“abc”與“abc”相等,“abc”和“acb”不相等,“abc”和“a bc”不相等

(2)子串:一個串中任意個連續字符組成的子序列(含空串)稱爲該串的子串。
例如,“a”、“ab”、“abc”和“abcd”等都是“abcde”的子串

(3)真子串:是指不包含自身的所有子串。
(注意是 所有 並且不包含自身)
例:“abcde”有多少個真子串?
15個,(注意空串也算是一個子串)
推廣:n(n+1)/2個(利用數學上的等差數列求和即可得出)

(4)空串也是一個子串

3.串的基本操作

串的很多操作都是在子串的基礎上進行操作的

(1)串插入操作
StrInsert(S,pos,T):在串S的位置爲pos的字符之前插入串T

示例: S=“Beig”,
T = “jin”
則執行StrInsert(S,4,T)後
S=“Beijing”,

(2)串刪除操作
StrDelete(S,pos,len):從串S中刪除位置爲pos的字符起長度爲len的子串

示例: S=“Beijing”,
則執行StrDelete(S,4,3)後
S=“Beig”,

(3)串鏈接、求子串、串替換等

4.串與線性表的關係

(1)相同點:

數據元素都來自字符集
操作對象是子串
基本操作:模式匹配

(2)區別:

一般線性表
邏輯結構:一對一
存儲結構:順序表、鏈表
運算規則:隨機、順序存取
操作對象:單個元素


邏輯結構:一對一
存儲結構:順序串、鏈式串
運算規則:隨機、順序存取
(串相等、模式匹配)
操作對象:子串

三.模式匹配

(模式匹配是串的重要操作)

1.串的模式匹配

(1)定位:
(串的模式匹配又叫做定位,即在主串T中找是否存在子串P)
①設有主串T和子串P,
②在主串T中找到第一個與子串P相等的子串的位置(第一次出現的位置)
(這個位置當然是子串在主串中出現的第一個字符的位置,然後把這個位置返回)。

(2)目標串:主串 T
(3)模式串:子串 P
(在模式匹配中我們通常把目標串叫做主串,用T表示,同理,模式串爲子串,用P表示)

(4)結果:
①模式匹配成功:在目標串T中找到一個模式串P;
②模式匹配不成功:目標串T中不存在模式串P。

示例:
目標 T : “Beijing”
模式 P : “jin”
匹配結果 = 3
(3呢,就是子串在主串中的位置,當然在這裏是從下標爲0開始計算的,也可以從1開始計算,那就是4了,是比較靈活的)

2.模式匹配的應用

• 自然語言處理:信息檢索
• 生物信息處理:DNA匹配
• 語音識別:輸入的語音符號化
• 網絡安全:病毒入侵檢測

(以上幾塊領域在計算機數據處理中應用很大,可見模式匹配的重要性)
在這裏插入圖片描述

3.模式匹配的作用

(以我們此次的疫情生物病毒舉例)
(1)研究者將人的DNA和病毒DNA均表示成由一些字母組成的字符串序列。
(2)然後檢測某種病毒DNA序列是否在患者的DNA序列中出現過,如果出現過,則此人感染了該病毒,否則沒有感染。
(3)例如:
假設病毒的DNA序列爲baa,
患者1的DNA序列爲aaabbba,則感染,
患者2的DNA序列爲babbba,則未感染。
(注意,人的DNA序列是線性的,而病毒的DNA序列是環狀的)

四.BF算法

1.模式匹配算法

(模式匹配算法我們只學習BF算法和KMP算法,當然還有別的模式匹配算法)

(1)BF算法
①最簡單、最易理解 (我們通常又把它叫做簡單模式匹配算法)
②採用回溯法 (在學習c語言時其實用到過)
(2)KMP算法
(3)BM算法
(4)KR算法
(5)……

2.算法過程

(1)採用回溯法:
①從主串的第i個位置開始,與子串的每個字符逐個比較,若均相等,則找到,位置爲i;
②否則,即在某個位置出現了不等,則說明從該起點開始的子串不是模式串,換一個新起點(第i+1個位置),重新開始,繼續逐一比較,
③直到找到,或i>=Length(T)爲止。

(2)例子:
(在這個例子中起始位置從0開始計算的)
用指針i指向主串T,指針j指向子串P
在這裏插入圖片描述

(3)特點:回溯
每趟的:
①主串回溯到上次起點的下一個位置;
②子串(模式串)回到0

3.算法執行

(1)Index(T,P,pos)
①將主串的第pos個字符和模式的第一個字符比較,若相等,繼續逐個比較後續字符;若不等,從主串的下一字符起,重新與模式的第一個字符比較。
②直到主串的一個連續子串字符序列與模式相等 。返回值爲T中與P匹配的子序列第一個字符的序號,即匹配成功。
③否則,匹配失敗,返回值 0

(2)代碼實現

(這個算法不難,注意我們在這是用的下標從1開始的位置)

int Index(Sstring T,Sstring P,int pos) //T代表主串,p代表子串,pos代表從主串的哪個位置開始找 
{
	i=pos;  //i的初值是pos 
	j=1;    //j的初值是1 ,這裏是從下標爲1開始計算的 ,前面的例子是從0開始計的 
	while(i<=T.len&&j<=P.len)     //即主串沒到頭並且子串沒到頭就循環 
	{
		if(T.data[i]==P.data[j])   //如果兩個串開始有相等的 
		{
			++i;          //i++ 主串向後移 
			++j;          //j++  子串向後移 
		}
		else          //否則的話就是不等了 ,就要回溯 
		{               
			i=i-j+2;    //i-j+2代表i要回溯的那個位置 ,主串回溯到上次起點的下一個位置,如果從0開始計的話,那麼爲i=i-j+1 
			j=1;        //j回溯到1,如果從0開始計的話,j=0; 
		}
	}
	if(j>P.len)         // 如果j往後走的過程中超過了P子串的長度,即匹配全部成功的話 
		return i-P.len;     //代表i在這一次匹配過程中它最先出發的那個點 下標 位置 
	else
		return 0;
}

(3)爲什麼主串回溯的位置是i-j+2?
在這裏插入圖片描述

4.算法複雜度分析

若n爲主串長度,m爲子串長度

(1)最好情況複雜度:O(m)
目標串的前 m 個字符正好等於模式串的 m 個字符。

例:若n爲主串長度,m爲子串長度
S=‘0001000001’,
T=‘0001’,
pos=1

(2)最壞情況複雜度:O(nm)
每次到最後一個字符才發現不匹配,這時再“倒回去”進行比較
比較次數:m
(n-m)(n-m個各比較了m次)

例:若n爲主串長度,m爲子串長度
S=‘0000000001’,
T=‘0001’,
pos=1

(3)算法評價
算法簡單,易於理解,但效率不高。

五.KMP算法

BF算法雖然簡單好理解,但是效率卻不高,接下來的是改進的模式匹配算法,叫做kMP算法。

1.來源

由以下三人同時發明的算法,因此給它起名字爲KMP算法,
D.E.Knuth
J.H.Morris
V.R.Pratt
其中D.E.Knuth(唐納德·克努特)被人們成爲算法和程序設計的先驅者,他有一套經典的著作是計算機程序設計藝術,這套藝術被譽爲算法中真正的聖經。
《計算機程序設計藝術 第1卷 基本算法》
《計算機程序設計藝術 第2卷 半數值算法》
《計算機程序設計藝術 第3卷 排序與查找》
他曾經說過:B-F算法中,匹配失敗後不必完全從頭再來(不必回溯),找到可以利用的信息,跳躍性匹配……
那麼kmp算法就是他所說的改進的模式匹配算法。

2.發現BF算法的改進點

(1)BF算法:
當比較到某個位置不匹配時,不管什麼情況,都進行回溯!回溯到該次比較的起始點的下一個位置,算法效率低。
在這裏插入圖片描述
在這裏插入圖片描述
(2)KMP算法改進:
在匹配失敗時,主串中的指針i需要回溯,而是在模式中找出適當的字符繼續比較,以此提高效率
在這裏插入圖片描述
在這裏插入圖片描述

在這裏插入圖片描述
利用已經部分匹配這個有效信息,保持i指針不回溯,通過修改j指針,讓模式串儘量地移動到有效的位置。
(已經部分匹配是指子串前面已經有幾個字符匹配好了)

(3)有效i不回溯,j要從哪裏開始?

通過next函數找到j要移動的位置k
(通過一個自己編寫的函數找到下一次要移動的位置)

3.KMP算法要解決的兩個問題

(1)如何根據失敗函數進行比較?

失敗函數:匹配失敗時,通過next函數求得當前匹配失敗點的位置 j 所對應的移動位置 k

例:假設:失敗函數已經建立
在這裏插入圖片描述

總結KMP算法:
模式 P 的第 j 位失配時:
①若 j > 0,下一趟比較時模式串 P的起始比較位置是P[next(j)],目標串 T 的指針不回溯
(j>0時,j=next(j); i不動)
②若 j = 0,則目標串 T指針進一,模式串P 指針回到 0
(j=0時,j=0; i++)

(2)next函數如何求得?

匹配不成功的那一刻,T[i]!=P[j],但: ‘P0P1…Pj-1’=‘Ti-j+1,Ti-j+2…Ti-1’
假設下一步與模式中第k(k<j)個字符比較,則模式中前k-1個字符必須滿足: ‘P0P1…Pk-1’=‘Pi-k+1,Pi-k+2…Pi-1’
於是得出:
‘P0P1…Pk-1’=‘Pj-k+1,Pj-k+2…Pj-1

4.KMP算法的時間複雜度

(1)設主串T的長度爲 n,模式串P長度爲 m;
(2)求next數組的時間複雜度爲 O(m);
(3)匹配中因主串T不回溯,比較次數可記爲n,
(4)所以KMP算法總的時間複雜度爲 O(n+m)。

5.模式匹配算法比較

(1)BF算法
①最簡單、最易理解
②採用回溯法
(2)KMP算法
①效率較高,可提速到O(n+m)
②主串指針不回溯

6.next函數的改進

例子:
在這裏插入圖片描述
在這裏插入圖片描述

(1)提出問題:
next[j]=k 即 Ti 與 Pj 比較不相等時,繼續與 pk 比較,但是若 pk=pj 顯然肯定還要失敗,所以 next[j] 可以改進。

(2)改進:
next[j] = k,如果Pj=Pk,則 主串中Ti和Pj不等,不需再和pk進行比較,而直接和pnext[k]進行比較。

(3)如何求nextnal:
比較P[j]和P[k],
若不等,則 nextval[j]=k(next[j]);
若相等,nextval[j]=nextval[k];

六.總結

1. 串數據結構的特點:

 重點掌握:數據對象限定了字符集,操作對象是一組數據元素

2. 模式匹配算法:BF、KMP

 重點掌握:熟悉next[j]函數的定義,會算next[j]和改進的nextval[j]。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章