一、串的基本概念
串(也称作字符串)是由n(n≥0)个字符组成的有限序列。
一个串中任意个连续的字符组成的子序列称为该串的子串。 包含子串的串称为该子串的主串。
一个字符在一个串中的位置序号(为大于等于0的正整数)称为该字符在串中的位置。当且仅当这两个串的值完全相等时,称这两个串相等。
二、串抽象数据类型
数据集合:串的数据集合可以表示为字符序列s0, s1,… , sn-1,每个数据元素的数据类型为字符类型。
操作集合:
(1)取字符charAt(index) :取index下标的字符返回。
(2)求长度length():返回串的长度。
(3)比较compareTo(anotherString):比较当前对象串和串anotherString的Unicode码值的大小。
(4)取子串substring(beginIndex, endIndex):取当前对象串中从beginIndex下标开始、至endIndex下标的前一下标止的子串。(5)连接concat(str):把串str连接到当前对象串的末尾。
(6)插入子串insert(str, pos):在当前对象串的第pos个字符前插入子串str。
(7)删除子串delete(beginIndex, endIndex):删除当前对象串中从beginIndex下标开始、至endIndex下标的前一下标止的子串
(8)输出串值myPrint():输出当前对象的串值。 //建议重写Object类的toString()方法。使用toString()代替
(9)查找子串index(subStr, start):在当前对象串的start下标开始,查找是否存在子串subStr。
三、串存储结构
串的顺序存储结构
串的顺序存储结构就是用字符类型数组存放串的所有字符。表示串的长度通常有两种方法:
(1)设置一个串的长度参数。
(2)在串值的末尾添加结束标记。串值长度的第一种表示方法下,串的成员变量应包括如下两项:
char[] value;
int count;
其中,value为存储串值的字符类型数组名,count表示串值的长度。串的链式存储结构
串的链式存储结构就是把串值分别存放在构成链表的若干个结点的数据元素域上。 有单字符结点链和块链两种。
单字符结点链就是每个结点的数据元素域只包括一个字符。
块链就是每个结点的数据元素域包括若干个字符。
四、MyString类的实现
五、MyStringBuffer以及MyStringBuffer的实现
public class MyString { //字符数组 char value[]; //字符串的长度 int count; /** * 实现字符的拷贝 * @param src 源字符数组 * @param srcPos 源字符数组的开始下标 * @param des 目标字符数组 * @param desPos 目标字符数组的开始下标 * @param length 拷贝的长度 */ public void arrayCopy(char src[],int srcPos,char des[],int desPos,int length) { if(srcPos+length>src.length||desPos+length>des.length) { throw new StringIndexOutOfBoundsException(length); } for(int i=0;i<length;i++) { des[desPos++]=src[srcPos++]; } } //构造方法一:构造一个空字符串 public MyString() { this.value=new char[0]; count=0; } /** * 构造方法二:从一个字符串中提取一个新的字符串 * @param value 已有的字符数组 * @param offset 起始下标 * @param count 拷贝的字符个数 */ public MyString(char value[],int offset,int count) { if(offset<0) { throw new StringIndexOutOfBoundsException(offset); } if(count<0) { throw new StringIndexOutOfBoundsException(count); } if(offset+count>value.length) { throw new StringIndexOutOfBoundsException(offset+count); } this.value=new char[count]; this.count=count; arrayCopy(value, offset, this.value, 0, count); } //构造方法三:根据已有的字符数组,构造字符串 public MyString(char value[]) { this.count=value.length; this.value=new char[count]; arrayCopy(value, 0, this.value, 0, count); } //构造方法四:根据jdk自带的String构造字符串 public MyString(String str) { char charArray[]=str.toCharArray(); this.value=charArray; this.count=charArray.length; } public String toString() { String str=""; for (int i = 0; i < count; i++) { str+=value[i]; } return str; } public int length() { return this.count; } public char charAt(int index) { if(index<0||index>=count) { throw new StringIndexOutOfBoundsException(index); } return this.value[index]; } //比较两个MyString对象是否相等,如果相等返回0,如果this>anotherStr 返回一个正数,否则返回一个复数 public int compareTo(MyString anotherStr) { int min=Math.min(this.count, anotherStr.length()); int i=0; while(i<min) { char c1=this.value[i]; char c2=anotherStr.value[i]; if(c1!=c2) { return c1-c2; } i++; } return this.count-anotherStr.length(); } //取子串 public MyString substring(int startIndex,int endIndex) { if(startIndex<0) { throw new StringIndexOutOfBoundsException(startIndex); } if(endIndex>count) { throw new StringIndexOutOfBoundsException(endIndex); } if(startIndex>endIndex) { throw new StringIndexOutOfBoundsException(endIndex-startIndex); } return (startIndex==0&&endIndex==count)?this:new MyString(value, startIndex, endIndex-startIndex); } public MyString substring(int startIndex) { return substring(startIndex, count); } public char[] toCharArray() { char buff[]=new char[count]; arrayCopy(value, 0, buff, 0, count); return buff; } //字符串的拼接 public MyString concat(MyString anotherStr) { int len=anotherStr.length(); char anotherArray[]=anotherStr.toCharArray(); if(len==0) return this; char buff[]=new char[count+len]; arrayCopy(value, 0, buff, 0, count); arrayCopy(anotherArray,0,buff,count,len); return new MyString(buff); } //字符串的插入 public MyString insert(MyString str,int postion) { if(postion<0||postion>count) { throw new StringIndexOutOfBoundsException(postion); } if(postion==0) { return str.concat(this); } MyString strBefore=this.substring(0, postion); MyString strAfter=this.substring(postion); MyString result=strBefore.concat(str).concat(strAfter); return result; } //字符串中删除子串 public MyString delete(int startIndex,int endIndex) { if(startIndex<0) { throw new StringIndexOutOfBoundsException(startIndex); } if(endIndex>count) { throw new StringIndexOutOfBoundsException(endIndex); } if(startIndex>endIndex) { throw new StringIndexOutOfBoundsException(endIndex-startIndex); } //删除全部 if(startIndex==0&&endIndex==count) { return new MyString(); } //获得删除节点的子串 MyString strStart=this.substring(0, startIndex); //获得删除节点后的子串 MyString strEnd=this.substring(endIndex); MyString result=strStart.concat(strEnd); return result; } }
MyStringBuffer与MyString的不同之处是:对于MyString类的连接,插入和删除子串成员函数都是不改变原对象的串值。但对于MyStringBuffer类,连接,插入和删除子串的成员函数都改变了原对象的串值。
public class MyStringBuffer { char value[]; int count; /** * 实现字符的拷贝 * @param src 源字符数组 * @param srcPos 源字符数组的开始下标 * @param des 目标字符数组 * @param desPos 目标字符数组的开始下标 * @param length 拷贝的长度 */ public void arrayCopy(char src[],int srcPos,char des[],int desPos,int length) { if(srcPos+length>src.length||desPos+length>des.length) { throw new StringIndexOutOfBoundsException(length); } for(int i=0;i<length;i++) { des[desPos++]=src[srcPos++]; } } public void expandCapacity(int newCapacity) { char newvalue[]=new char[newCapacity]; arrayCopy(value, 0, newvalue, 0, count); this.value=newvalue; } public MyStringBuffer(String str) { char newarray[]=str.toCharArray(); value=newarray; count=newarray.length; } public String toString() { String str=""; for (int i = 0; i < count; i++) { str+=value[i]; } return str; } public char[] toCharArray() { return value; } public int length() { return this.count; } //拼接字符串,改变内容,但不会改变变量 public MyStringBuffer concat(MyStringBuffer anotherBuffer) { int len=anotherBuffer.length(); if(len==0) { return this; } expandCapacity(count+len); arrayCopy(anotherBuffer.toCharArray(), 0, this.toCharArray(), this.length(), len); count+=len; return this; } }六、测试
public class Main { public static void main(String[] args) { char value[]= {'H','e','l','l','o'}; MyString str1=new MyString();//空 MyString str2=new MyString(value,0,4);//Hell MyString str3=new MyString(value); //Hello MyString str4=new MyString(" Welcome!"); //Welcome System.out.println(str1); System.out.println(str2); System.out.println(str3); System.out.println(str4); System.out.println(str2.compareTo(str3)); MyString str5=str3.concat(str4); System.out.println(str5);//Hello Welcome! System.out.println(str5.insert(new MyString("China"), 6));//Hello China Welcome! System.out.println(str5.delete(2, 5));//He Welcome! } }
public class MainStringBuffer { public static void main(String[] args) { MyStringBuffer str1=new MyStringBuffer("China "); MyStringBuffer str2=new MyStringBuffer("Hello"); System.out.println(str1); System.out.println(str1.hashCode()); str1.concat(str2); System.out.println(str1); System.out.println(str1.hashCode()); } }