本篇博文用java實現了數據結構中的字符串操作,包括Brute-Force和KMP模式匹配算法
源碼分享在github:數據結構,當然你也可以從下面的代碼片中獲取
1.字符串的接口定義 IString .java
package code.string;
/*
* 串的接口定義
*
* */
public interface IString {
public void clear();//置空操作
public boolean isEmpty();//判空操作
public int length();//求字符串長度
public char charAt(int index);//讀取並返回串中第index個字符的值,範圍 0 <= index < length()
public IString substring(int begin,int end);//截取字符串,返回當前串從 begin 到 end-1的值
public IString insert(int offset,IString str);//插入字符串你,在第offset之前插入串str
public IString delete(int begin,int end);//刪除,從begin 到 end-1
public IString concat(IString str);//連接操作,把str串連接到當前串的後面
public int compareTo(IString str);//將當前串與目標串進行比較,若當前串大於str,則返回一個整數,等於返回0,小於,返回-1
public int indexOf(IString str,int begin);//子串定位操作,搜索與str相等的子串,成功則返回str在當前位置
}
2.字符串的順序存儲實現 SeqString .java
package code.string;
/*
* 串的順序存儲結構
* */
public class SeqString implements IString{
private char [] strValue;//字符數組,存放串值
private int curLen;//串中字符個數,即串的長度
//構造方法
public SeqString(){
strValue = new char[0];
curLen = 0;
}
//以一段字符串構造
public SeqString(String str){
char [] tempCharArray = str.toCharArray();
strValue = tempCharArray;
curLen = tempCharArray.length;
}
//以字符數組構造串對象
public SeqString(char [] value){
this.strValue = new char[value.length];
for (int i = 0;i<value.length;i++){
this.strValue[i] = value[i];
}
curLen = value.length;
}
//擴充字符串存儲空間,參數指定容量,後面的插入字符串需要調用
public void allocate(int newCapacity){
char [] temp = strValue;
strValue = new char[newCapacity];
//複製數組
for (int i = 0;i<temp.length;i++){
strValue[i] = temp[i];
}
}
@Override
public void clear() {
this.curLen = 0;
}
@Override
public boolean isEmpty() {
return curLen == 0;
}
@Override
public int length() {
return curLen;
}
//返回字符串中序號爲index的字符
@Override
public char charAt(int index) {
if ((index < 0)|| (index >= curLen)){
throw new StringIndexOutOfBoundsException(index);
}
return strValue[index];
}
//截取字符串,返回當前串從 begin 到 end-1的值
@Override
public IString substring(int begin, int end) {
if (begin < 0){
throw new StringIndexOutOfBoundsException("起始位置不能小於0");
}
if (end > curLen){
throw new StringIndexOutOfBoundsException("結束位置不能大於串的當前長度:"+curLen);
}
if (begin >= end){
throw new StringIndexOutOfBoundsException("開始位置不能大於等於結束位置");
}
//截取全部字符串
if (begin == 0 && end == curLen){
return this;
} else {
char [] buff = new char[end - begin];
for (int i = 0;i<buff.length;i++){
buff[i] = this.strValue[i+begin];
}
return new SeqString(buff);
}
}
//插入字符串你,在第offset之前插入串str,offset有效值 0 <= offset <= curLen
@Override
public IString insert(int offset, IString str) {
if ((offset < 0)||(offset > this.curLen)){
throw new StringIndexOutOfBoundsException("插入位置不合法");
}
int len = str.length();
int newCount = this.curLen+len;
if (newCount > strValue.length) {//如果添加新的字符串進去容量不夠
allocate(newCount);
}
for (int i = this.curLen - 1;i >= offset;i--){
strValue[len+i] = strValue[i];//從offset開始向後移動len個字符
}
for (int i = 0;i < len;i++){
strValue[offset+i] = str.charAt(i);
}
this.curLen = newCount;
return this;
}
//刪除,從begin 到 end-1
@Override
public IString delete(int begin, int end) {
if (begin < 0){
throw new StringIndexOutOfBoundsException("起始位置不能小於0");
}
if (end > curLen){
throw new StringIndexOutOfBoundsException("結束位置不能大於串當前長度"+curLen);
}
if (begin >= end){
throw new StringIndexOutOfBoundsException("開始位置不能大於等於結束位置");
}
//從end開始的串向前移動到從begin開始的位置
for (int i = 0;i < curLen-end;i++){
strValue[begin+i] = strValue[end+i];
}
curLen = curLen-(end - begin);
return this;
}
//連接操作,把str串連接到當前串的後面
@Override
public IString concat(IString str) {
return insert(curLen,str);
}
//將當前串與目標串進行比較,若當前串大於str,則返回一個整數,等於返回0,小於,返回-1
@Override
public int compareTo(IString str) {
//求出當前串與帶比較串的長度,並把較小值賦值到n
int len1 = curLen;
int len2 = ((SeqString) str).curLen;
int n = Math.min(len1,len2);
char[] s1 = strValue;
char[] s2 = ((SeqString) str).strValue;
int k = 0;
while (k<n){
char ch1 = s1[k];
char ch2 = s2[k];
if (ch1 != ch2){
return ch1 - ch2;//返回不相等字符的數值差
}
k++;
}
return len1 - len2;
}
/*
* Brute-Force模式匹配算法
*
* */
//返回模式串t在主串中從start開始的第一次匹配位置,匹配失敗時返回-1
public int indexOf_BF(IString t,int start){
//當主串比模式串長時進行比較
if (this != null && t!=null && t.length()>0&&this.length()>=t.length()){
//i表示主串中某個子串的序號
int sLen,tLen,i = start,j = 0;
sLen = this.length();
tLen = t.length();
while ((i<sLen)&&(j<tLen)){
if (this.charAt(i)==t.charAt(j)){//如果一切安好,繼續比較後面的字符
i++;
j++;
}else {
i = i-j+1;//繼續比較主串中的下一個子串,這邊i其實只是加了1,昂,you know,細品
j = 0;//模式串下標歸0
}
}
if (j>=t.length()) {//此時從循環殺出來的時候,如果j>=t.length,說明匹配成功了
return i - tLen;//匹配成功,返回子串序號,這裏返回的是字符串首個的index
}else {
return -1;//匹配失敗,返回負一
}
}
return -1;//匹配失敗,返回負一
}
/*
* KMP算法
*
* */
private int[] getNextVal(IString T){
int [] nextVal = new int[T.length()];
int j = 0;
int k = -1;
nextVal[0] = -1;
while (j<T.length()-1){
if (k == -1||T.charAt(j) == T.charAt(k)){
j++;
k++;
if (T.charAt(j) != T.charAt(k))
nextVal[j] = k;
else
nextVal[j] = nextVal[k];
}else
k = nextVal[k];
}
return nextVal;
}
public int index_KPM(IString T,int start){
int [] next = getNextVal(T);//計算模式串next[]函數值
int i = start;//主串指針
int j = 0;//模式串指針
//對兩串從左到右逐個比較字符
while (i<this.length()&& j<T.length()){
if (j == -1||this.charAt(i)==T.charAt(j)){
i++;
j++;
}else {
j = next[j];//模式串右移
}
}
if (j<T.length()){
return -1;
}else {
return (i-T.length());//匹配成功
}
}
//子串定位操作,搜索與str相等的子串,成功則返回str在當前位置
@Override
public int indexOf(IString str, int begin) {
return index_KPM(str,begin);
}
}
數據結構這個系列是我學習時做的筆記,會持續更新,詳見我的github(地址在文章開頭)或我的其他博文,感覺不錯的話,關注一下吧!