1. 程式人生 > >資料結構Java實現——③串

資料結構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;
	}	
}


後記

        能細心看程式碼的就會發現,上面的串的順序儲存中,串匹配(檢索)的函式沒有實現,這就是我說的為什麼到現在才總結的原因,因為這才是串的知識點中的難度,也是不容易理解的地方,我就卡在了這裡,一直卡到了總結前才算是明白了七八分。此處不對匹配進行分析,因為匹配比較難,我會拿出來單獨的分析