數據結構字符串操作的Java實現,包括Brute-Force和KMP模式匹配算法

本篇博文用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(地址在文章開頭)或我的其他博文,感覺不錯的話,關注一下吧!

發佈了27 篇原創文章 · 獲贊 49 · 訪問量 2272
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章