資料結構Java實現——③串
寫在前面
不知不覺的就放假將近十天了,回家的日子實在是太安逸,安逸到忘記了時間,忘記了學習,昨天一不小心看了下日曆才知道又虛度了十天的光陰,哎!人的惰性,實在是沒什麼能說的了。
閒話少說,迴歸正題。前天上午開始看的串,一開始覺得串挺簡單的,實現的基本上都是曾經見過的字串的方法,就當是重新學習了一下。覺得當時就能看完,然後把部落格寫了,算是做個總結,趕緊看完陣列然後去重點學習樹,哪知道。。。。
文字介紹
所謂串,“字串”也,即字串在一起作為一個整體,當然串也是線性表的一種,當然也有順序儲存,鏈式儲存兩種。
很顯然在學習了前面那麼多的“特殊的”線性表之後,對常見的兩種儲存方式不難理解
首先來說順序儲存,在最開始構造時,要預先的建立一個“大”陣列,然後將資料儲存儘量,對應順序儲存,必須要有一個記錄當前實際佔用“大”陣列長度、也就是串本身的實際長度的變數。
然後來說鏈式儲存,首先鏈式儲存肯定要用到結點物件(有指標域,有資料域),如果結點的資料域裡儲存的是單個字元,那麼該連結串列稱為單字元連結串列,否則,也就是結點的資料域記憶體儲多個字元時,稱為塊連結串列。
很顯然,對於單字元連結串列而言,插入、刪除、查詢等操作比較方便,但是儲存效率太低(指標所佔的儲存比例較大);對於塊連結串列而言,雖然儲存效率高,但是對於一些基本的操作,實現起來比較麻煩
實際應用中串的鏈式儲存也用的比較少,因此此處僅僅給出串的順序儲存的程式碼實現
程式碼實現
1、串的抽象介面
package org.Stone6762.MString; /** * @MString * @Stone6762 * @Description */ public interface MString { /** * @Title: clear * @Description: TODO(將字串清空) */ public void clear(); /** * @Title: isEmpty * @Description: TODO(判斷是否為空) * @return */ public boolean isEmpty(); /** * @Title: length * @Description: TODO(求字串的長度) * @return */ public int length(); /** * @Title: charAt * @Description: TODO(取出字串中的某一個下標下的字元) * @param index * @return */ public char charAt(int index); /** * @Title: subString * @Description: TODO(根據起始和結束的下標來擷取某一個子串) * @param begin要擷取部分的起始部分,包括起始部分 * @param end截止到end,不包括end * @return */ public MString subString(int begin, int end); /** * @Title: insert * @Description: TODO(根據下標將一個字串插入到指定的位置) * @param offset要插入的字串的第一個位置 * @param str * @return */ public MString insert(int offset, MString str); /** * @Title: delete * @Description: TODO(刪除掉串中的某一部分) * @param begin * @param end * @return */ public MString delete(int begin, int end); /** * @Title: concat * @Description: TODO(將一個字串連線到該字串的末尾) * @param str * @return */ public MString concat(MString str); /** * @Title: compareTo * @Description: TODO(兩個字串進行比較) * @param str * @return */ public int compareTo(MString str); /** * @Title: indexOf * @Description: TODO(在本字串中,從begin位置開始,檢索某一個字串第一次出現的位置) * @param str * @param begin * @return */ public int indexOf(MString str, int begin); }
2、串的順序儲存實現
package org.Stone6762.MString.imple; import org.Stone6762.MString.MString; /** * @SeqString * @Stone6762 * @Description */ public class SeqString implements MString { /** * @Fields strvalue : TODO(儲存串中的每一個元素) */ private char[] strvalue; /** * @Fields curlen : TODO(記錄當前的串的長度) */ private int curlen; /** * @Description: TODO(構造方法一,預設的) * */ public SeqString() { this.strvalue = new char[0]; this.curlen = 0; } /** * @Description: TODO(構造方法二,設定順序儲存的串的最大長度) * * @param maxSize */ public SeqString(int maxSize) { this.strvalue = new char[maxSize]; this.curlen = 0; } /** * @Description: TODO(構造方法三、以一個字串構造串物件) * * @param str */ public SeqString(String str) { strvalue = str.toCharArray(); curlen = strvalue.length; } /** * @Description: TODO(構造方法四,以一個字元陣列構造串物件) * * @param value */ public SeqString(char[] value) { this.strvalue = new char[value.length]; for (int i = 0; i < value.length; i++) { strvalue[i] = value[i]; } curlen = value.length; } public char[] getStrvalue() { return strvalue; } public int getCurlen() { return curlen; } @Override public void clear() { this.curlen = 0; } @Override public boolean isEmpty() { return this.curlen == 0; } @Override public int length() { return this.curlen; } @Override public char charAt(int index) { if (index < 0 || index >= this.curlen) { throw new StringIndexOutOfBoundsException(); } return strvalue[index]; } /** * @Description: TODO( 擴充串儲存空間容量,引數指定容量 ) * @param newCapacity */ public void allocate(int newCapacity) { /* * 先將原來的資料進行儲存,然後根據引數建立一個目標大小的儲存空間 最後將儲存的資料儲存到新的空間中 */ char[] tempCArry = this.strvalue; strvalue = new char[newCapacity]; for (int i = 0; i < tempCArry.length; i++) { strvalue[i] = tempCArry[i]; } } @Override public MString 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[] buffer = new char[end - begin]; for (int i = 0; i < buffer.length; i++) { buffer[i] = this.strvalue[i + begin]; } return new SeqString(buffer); } } @Override public MString insert(int offset, MString str) { /* * 首先判斷插入位置的合法性(小於0或大於原本串的長度) 然後判斷是否能夠儲存,不能就擴充 * 最後,先將要插入部分的字元向後移,再將要插入的字元插入即可 */ if (offset < 0 || offset > curlen) { throw new StringIndexOutOfBoundsException(""); } int strlen = str.length(); int newlength = strlen + curlen; if (newlength > this.strvalue.length) { allocate(newlength); } // 將offset後的元素都後移strlen位 for (int i = curlen - 1; i >= offset; i--) { strvalue[strlen + i] = strvalue[i]; } // 插入 for (int i = 0; i < strlen; i++) { strvalue[offset + i] = str.charAt(i); } this.curlen = newlength; return this; } @Override public MString delete(int begin, int end) { /* * 首先將判斷下標的合法性,起始不能小於0,結束不能超出當前串的長度,起始不能大於結束 * 然後將end以後(包括end)的字元都向前移動到起始的位置。 */ if (begin < 0) { throw new StringIndexOutOfBoundsException("起始位置不能小於0"); } if (end > curlen) { throw new StringIndexOutOfBoundsException("結束位置不能大於串本身的長度" + curlen); } if (begin > end) { throw new StringIndexOutOfBoundsException("起始位置不能大於中止位置"); } for (int i = end; i < curlen; i++) { this.strvalue[begin + i] = this.strvalue[i]; } curlen = curlen - (end - begin); return this; } @Override public MString concat(MString str) { /* * 首先判斷是否能夠儲存 */ int newlen = str.length() + curlen; if (newlen > strvalue.length) { allocate(newlen); } for (int i = 0; i < str.length(); i++) { strvalue[curlen + i] = str.charAt(i); } return this; } @Override public int compareTo(MString str) { /* * 首先以一個長度小的為基準,遍歷比較,一旦出現不相等,返回比較值。 如果長度相同的部分都相等,返回長度比較值 */ int len1 = curlen; int len2 = str.length(); int n = Math.min(len1, len2); char[] cArry1 = strvalue; char[] cArry2 = ((SeqString) str).strvalue; int i = 0; char c1, c2; while (i < n) { c1 = cArry1[i]; c2 = cArry2[i]; if (c1 != c2) { return c1 - c2; } i++; } return len1 - len2; } @Override public int indexOf(MString str, int begin) { return 0; } }
後記
能細心看程式碼的就會發現,上面的串的順序儲存中,串匹配(檢索)的函式沒有實現,這就是我說的為什麼到現在才總結的原因,因為這才是串的知識點中的難度,也是不容易理解的地方,我就卡在了這裡,一直卡到了總結前才算是明白了七八分。此處不對匹配進行分析,因為匹配比較難,我會拿出來單獨的分析