写在前面
不知不觉的就放假将近十天了,回家的日子实在是太安逸,安逸到忘记了时间,忘记了学习,昨天一不小心看了下日历才知道又虚度了十天的光阴,哎!人的惰性,实在是没什么能说的了。
闲话少说,回归正题。前天上午开始看的串,一开始觉得串挺简单的,实现的基本上都是曾经见过的字符串的方法,就当是重新学习了一下。觉得当时就能看完,然后把博客写了,算是做个总结,赶紧看完数组然后去重点学习树,哪知道。。。。
文字介绍
所谓串,“字符串”也,即字符串在一起作为一个整体,当然串也是线性表的一种,当然也有顺序存储,链式存储两种。
很显然在学习了前面那么多的“特殊的”线性表之后,对常见的两种存储方式不难理解
首先来说顺序存储,在最开始构造时,要预先的创建一个“大”数组,然后将数据存储尽量,对应顺序存储,必须要有一个记录当前实际占用“大”数组长度、也就是串本身的实际长度的变量。
然后来说链式存储,首先链式存储肯定要用到结点对象(有指针域,有数据域),如果结点的数据域里存储的是单个字符,那么该链表称为单字符链表,否则,也就是结点的数据域内存储多个字符时,称为块链表。
很显然,对于单字符链表而言,插入、删除、查询等操作比较方便,但是存储效率太低(指针所占的存储比例较大);对于块链表而言,虽然存储效率高,但是对于一些基本的操作,实现起来比较麻烦
实际应用中串的链式存储也用的比较少,因此此处仅仅给出串的顺序存储的代码实现
代码实现
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; } }
后记
能细心看代码的就会发现,上面的串的顺序存储中,串匹配(检索)的函数没有实现,这就是我说的为什么到现在才总结的原因,因为这才是串的知识点中的难度,也是不容易理解的地方,我就卡在了这里,一直卡到了总结前才算是明白了七八分。此处不对匹配进行分析,因为匹配比较难,我会拿出来单独的分析