数据结构-串

串,字符串是由零个或多个字符组成的有限序列。字符的数目称为串的长度。长度为零的串称为空串。串中任意个连续的字符组成的子序列称为该串的子串。包含子串的串称为主串。字符在串中的序号称为该字符在串中的位置。

串相等,只有长度相同,对应位置字符相同的串是相等串。

对于串的操作很多,在这里仅列出以下几种:

1、串比较

equals() 判断串是否相等。

compareTo() 比较串的大小。

compareToIgnoreCase(String int) 忽略字母大小写比较。

== 判断串与地址是否相同。

equalsIgnoreCase() 忽略字母大小写判断串是否相等。

reagionMatches() 对串中的部分内容是否相同进行比较。

2、串查找

charAt(int index) 返回指定位置上的字符,索引范围从0开始。

indexOf(String str) 从0开始检索str,并返回第一次出现的位置,未出现返回-1。

indexOf(String str,int fromIndex) 从指定位置开始检索str。

lastIndexOf(String str) 查找最后一次出现的位置。

lastIndexOf(String str,int fromIndex) 从指定位置查找最后一次出现的位置。

starWith(String prefix,int toffset) 测试从指定索引开始的子串是否以指定前缀开始。

starWith(String prefix) 测试是否以指定的前缀开始。

endsWith(String suffix) 测试是否以指定的后缀结束。

3、字符串截取

public String subString(int beginIndex) 返回一个子串(它是一个新串)。

public String subString(int beginIndex,int endIndex) 返回从beginIndex开始到endIndex-1的子串。

4、字符串替换

public String replace(char oldChar,char newChar)。

public String replace(CharSequence target,CharSequence replacement) 把原来的target子序列替换为replacement序列,返回新串。

public String replaceAll(String regex,String replacement) 用正则表达式实现对字符串的匹配。

5、其他

public String trim() 去除空格。

public String toLowerCase() 将串中的所有大写字符改写为小写字符。

public String toUpperCase() 将串中的字符小写字符改写为大写字符。

public String[] split(String regex) 把串按指定的分隔字符或字符串对内容进行分割,并将分割后的结果存放在字符串数组中。

接下来贴出个人认为有助于理解的部分Java1.8String.java的源代码,希望有助于理解。

public final class String

implements java.io.Serializable, Comparable<String>, CharSequence {

/** The value is used for character storage. */

private final char value[];

/** Initializes a newly created {@code String} object so that it represents an empty character sequence.  Note that use of this constructor is unnecessary since Strings are immutable. */

public String() {

this.value = new char[0];

}

/** Allocates a new {@code String} so that it represents the sequence of characters currently contained in the character array argument. The contents of the character array are copied; subsequent modification of the character array does not affect the newly created string. */

public String(char value[]) {

this.value = Arrays.copyOf(value, value.length);

}

public String(byte bytes[], int offset, int length, Charset charset) {

if (charset == null)

throw new NullPointerException("charset");

checkBounds(bytes, offset, length);

this.value =  StringCoding.decode(charset, bytes, offset, length);

}

字符编码的部分很有意思,但不是数据结构的内容,先拿下。

/** Returns the length of this string. The length is equal to the number of Unicode code units in the string. */

public int length() {

return value.length;

}

/** Returns {@code true} if, and only if, {@link #length()} is {@code 0}. */

public boolean isEmpty() {

return value.length == 0;

}

/** Returns the {@code char} value at the specified index. An index ranges from {@code 0} to {@code length() - 1}. The first {@code char} value of the sequence is at index {@code 0}, the next at index {@code 1}, and so on, as for array indexing. */

public char charAt(int index) {

if ((index < 0) || (index >= value.length)) {

throw new StringIndexOutOfBoundsException(index);

}

return value[index];

}

/** Compares this string to the specified object.  The result is true if and only if the argument is not null and is a String object that represents the same sequence of characters as this object. @see  #compareTo(String) @see  #equalsIgnoreCase(String) */

public boolean equals(Object anObject) {

if (this == anObject) {

return true;

}

if (anObject instanceof String) {①

String anotherString = (String)anObject;

int n = value.length;

if (n == anotherString.value.length) {②

char v1[] = value;

char v2[] = anotherString.value;

int i = 0;

while (n-- != 0) {③

if (v1[i] != v2[i])

return false;

i++;

}

return true;

}

}

return false;

}

/** 注释比代码还长,省略 */

public int compareTo(String anotherString) {

int len1 = value.length;

int len2 = anotherString.value.length;

int lim = Math.min(len1, len2);

char v1[] = value;

char v2[] = anotherString.value;

int k = 0;

while (k < lim) {

char c1 = v1[k];

char c2 = v2[k];

if (c1 != c2) {

return c1 - c2;

}

k++;

}

return len1 - len2;

}

public int indexOf(int ch, int fromIndex) {

final int max = value.length;

if (fromIndex < 0) {

fromIndex = 0;

} else if (fromIndex >= max) {

// Note: fromIndex might be near -1>>>1.

return -1;

}

if (ch < Character.MIN_SUPPLEMENTARY_CODE_POINT) {

// handle most cases here (ch is a BMP code point or a

// negative value (invalid code point))

final char[] value = this.value;

for (int i = fromIndex; i < max; i++) {

if (value[i] == ch) {

return i;

}

}

return -1;

} else {

return indexOfSupplementary(ch, fromIndex);

}

}

public int lastIndexOf(int ch, int fromIndex) {

if (ch < Character.MIN_SUPPLEMENTARY_CODE_POINT) {

// handle most cases here (ch is a BMP code point or a

// negative value (invalid code point))

final char[] value = this.value;

int i = Math.min(fromIndex, value.length - 1);

for (; i >= 0; i--) {

if (value[i] == ch) {

return i;

}

}

return -1;

} else {

return lastIndexOfSupplementary(ch, fromIndex);

}

}

static int indexOf(char[] source, int sourceOffset, int sourceCount,

char[] target, int targetOffset, int targetCount,

int fromIndex) {

if (fromIndex >= sourceCount) {

return (targetCount == 0 ? sourceCount : -1);

}

if (fromIndex < 0) {

fromIndex = 0;

}

if (targetCount == 0) {

return fromIndex;

}

char first = target[targetOffset];

int max = sourceOffset + (sourceCount - targetCount);

for (int i = sourceOffset + fromIndex; i <= max; i++) {

/* Look for first character. */

if (source[i] != first) {

while (++i <= max && source[i] != first);

}

/* Found first character, now look at the rest of v2 */

if (i <= max) {

int j = i + 1;

int end = j + targetCount - 1;

for (int k = targetOffset + 1; j < end && source[j]

== target[k]; j++, k++);

if (j == end) {

/* Found whole string. */

return i - sourceOffset;

}

}

}

return -1;

}

static int lastIndexOf(char[] source, int sourceOffset, int sourceCount,

char[] target, int targetOffset, int targetCount,

int fromIndex) {

/*

* Check arguments; return immediately where possible. For

* consistency, don‘t check for null str.

*/

int rightIndex = sourceCount - targetCount;

if (fromIndex < 0) {

return -1;

}

if (fromIndex > rightIndex) {

fromIndex = rightIndex;

}

/* Empty string always matches. */

if (targetCount == 0) {

return fromIndex;

}

int strLastIndex = targetOffset + targetCount - 1;

char strLastChar = target[strLastIndex];

int min = sourceOffset + targetCount - 1;

int i = min + fromIndex;

startSearchForLastChar:

while (true) {

while (i >= min && source[i] != strLastChar) {

i--;

}

if (i < min) {

return -1;

}

int j = i - 1;

int start = j - (targetCount - 1);

int k = strLastIndex - 1;

while (j > start) {

if (source[j--] != target[k--]) {

i--;

continue startSearchForLastChar;

}

}

return start - sourceOffset + 1;

}

}

public String substring(int beginIndex, int endIndex) {

if (beginIndex < 0) {

throw new StringIndexOutOfBoundsException(beginIndex);

}

if (endIndex > value.length) {

throw new StringIndexOutOfBoundsException(endIndex);

}

int subLen = endIndex - beginIndex;

if (subLen < 0) {

throw new StringIndexOutOfBoundsException(subLen);

}

return ((beginIndex == 0) && (endIndex == value.length)) ? this

: new String(value, beginIndex, subLen);

}

public String concat(String str) {

int otherLen = str.length();

if (otherLen == 0) {

return this;

}

int len = value.length;

char buf[] = Arrays.copyOf(value, len + otherLen);

str.getChars(buf, len);

return new String(buf, true);

}

public String replace(char oldChar, char newChar) {

if (oldChar != newChar) {

int len = value.length;

int i = -1;

char[] val = value; /* avoid getfield opcode */

while (++i < len) {

if (val[i] == oldChar) {

break;

}

}

if (i < len) {

char buf[] = new char[len];

for (int j = 0; j < i; j++) {

buf[j] = val[j];

}

while (i < len) {

char c = val[i];

buf[i] = (c == oldChar) ? newChar : c;

i++;

}

return new String(buf, true);

}

}

return this;

}

public boolean contains(CharSequence s) {

return indexOf(s.toString()) > -1;

}

/**

* Returns a new String composed of copies of the

* {@code CharSequence elements} joined together with a copy of

* the specified {@code delimiter}.

*

* <blockquote>For example,

* <pre>{@code

*     String message = String.join("-", "Java", "is", "cool");

*     // message returned is: "Java-is-cool"

* }</pre></blockquote>

*

* Note that if an element is null, then {@code "null"} is added.

*

* @param  delimiter the delimiter that separates each element

* @param  elements the elements to join together.

*

* @return a new {@code String} that is composed of the {@code elements}

*         separated by the {@code delimiter}

*

* @throws NullPointerException If {@code delimiter} or {@code elements}

*         is {@code null}

*

* @see java.util.StringJoiner

* @since 1.8

*/

public static String join(CharSequence delimiter, CharSequence... elements) {

Objects.requireNonNull(delimiter);

Objects.requireNonNull(elements);

// Number of elements not likely worth Arrays.stream overhead.

StringJoiner joiner = new StringJoiner(delimiter);

for (CharSequence cs: elements) {

joiner.add(cs);

}

return joiner.toString();

}

/**

* Returns a new {@code String} composed of copies of the

* {@code CharSequence elements} joined together with a copy of the

* specified {@code delimiter}.

*

* <blockquote>For example,

* <pre>{@code

*     List<String> strings = new LinkedList<>();

*     strings.add("Java");strings.add("is");

*     strings.add("cool");

*     String message = String.join(" ", strings);

*     //message returned is: "Java is cool"

*

*     Set<String> strings = new LinkedHashSet<>();

*     strings.add("Java"); strings.add("is");

*     strings.add("very"); strings.add("cool");

*     String message = String.join("-", strings);

*     //message returned is: "Java-is-very-cool"

* }</pre></blockquote>

*

* Note that if an individual element is {@code null}, then {@code "null"} is added.

*

* @param  delimiter a sequence of characters that is used to separate each

*         of the {@code elements} in the resulting {@code String}

* @param  elements an {@code Iterable} that will have its {@code elements}

*         joined together.

*

* @return a new {@code String} that is composed from the {@code elements}

*         argument

*

* @throws NullPointerException If {@code delimiter} or {@code elements}

*         is {@code null}

*

* @see    #join(CharSequence,CharSequence...)

* @see    java.util.StringJoiner

* @since 1.8

*/

public static String join(CharSequence delimiter,

Iterable<? extends CharSequence> elements) {

Objects.requireNonNull(delimiter);

Objects.requireNonNull(elements);

StringJoiner joiner = new StringJoiner(delimiter);

for (CharSequence cs: elements) {

joiner.add(cs);

}

return joiner.toString();

}

public String trim() {

int len = value.length;

int st = 0;

char[] val = value;    /* avoid getfield opcode */

while ((st < len) && (val[st] <= ‘ ‘)) {

st++;

}

while ((st < len) && (val[len - 1] <= ‘ ‘)) {

len--;

}

return ((st > 0) || (len < value.length)) ? substring(st, len) : this;

}

}

关于串有很多细节是需要注意的,给个小例子:

public static void main(String[] args) {

long start_01 = System.currentTimeMillis();

String a = "a";

for(int i = 0 ; i < 100000 ; i++){

a += "b";

}

long end_01 = System.currentTimeMillis();

System.out.println("  +   所消耗的时间:" + (end_01 - start_01) + "毫秒");

System.out.println(a.length());a = null;

//concat()

long start_02 = System.currentTimeMillis();

String c = "c";

for(int i = 0 ; i < 100000 ; i++){

c = c.concat("d");

}

long end_02 = System.currentTimeMillis();

System.out.println("concat所消耗的时间:" + (end_02 - start_02) + "毫秒");

System.out.println(c.length());c = null;

//append

long start_03 = System.currentTimeMillis();

StringBuffer e = new StringBuffer("e");

for(int i = 0 ; i < 100000 ; i++){

e.append("d");

}

long end_03 = System.currentTimeMillis();

System.out.println("append所消耗的时间:" + (end_03 - start_03) + "毫秒");

long start_04 = System.currentTimeMillis();

String f = new String(e);

long end_04 = System.currentTimeMillis();

System.out.println("appnew所消耗的时间:" + (end_04 - start_04) + "毫秒");

System.out.println(f.length());f = null;

long start_05 = System.currentTimeMillis();

String g = e.toString();

long end_05 = System.currentTimeMillis();

System.out.println("apptsr所消耗的时间:" + (end_05 - start_05) + "毫秒");

System.out.println(g.length());

}

结果

+   所消耗的时间:11739毫秒

100001

concat所消耗的时间:5008毫秒

100001

append所消耗的时间:1毫秒

appnew所消耗的时间:0毫秒

100001

apptsr所消耗的时间:0毫秒

100001

时间: 2024-10-06 21:06:53

数据结构-串的相关文章

javascript实现数据结构: 串的块链存储表示

和线性表的链式存储结构相类似,也可采用链式方式存储串值.由于串结构的特殊性--结构中的每个数据元素是一个字符,则用链表存储串值时,存在一个"结点大小"的问题,即每个结点可以存放一个字符,也可以存放多个字符. 下面是结点大小为4(即每个结点存放4个字符)的链表: head --> (a) --> (b) --> (c) --> ... --> (i) 当结点大小大于1时,由于串长不一定是结点大小的整倍数,则链表中的最后一个结点不一定全被串值占满,此时通常补上

数据结构—串的堆分配

#include<stdio.h> #include<stdlib.h> typedef struct { char *ch; int length; }HString; void StrAssign(HString &T,char *chars); void StrLength(HString S); void StrCompare(HString S,HString T); void ClearString(HString &S); void Concat(HS

数据结构——串的相关算法实现

数据结构--串的相关算法实现 顺序串的插入函数实现 在进行顺序串的插入时,插入pos将串分为两个部分(假设为A.B,长度为LA.LB)及待插入部分(假设为C,长度为LC),则串由插入前的AB变为ACB,由于是顺序串,插入会引起元素的移动.可能会出现以下的三种情况: ①插入后串长度(LA+LC+LB)<=MAXLEN,则将B后移LC个元素位置,再将C插入: ②插入后串长度 >=MAXLEN 且 pos+LC <=MAXLEN,则 B 后移时会有部分字符被舍弃; ③插入后串长度>MAX

数据结构-串操作应用之词索引表

为书库创建查询索引表 建立词索引表基本步骤: 1.从书目文件中读入一个书目单. 2.从书目单中提取所有关键字插入词表. 3.对词表中的每一个关键字在索引表中进行查找并作相应的插入操作. 详细操作: 1.为识别从书名串中分离出来的单词是否是关键字,需要一张常用词表.顺序扫描书目单,首先分离单词,然后查找常用词表,若不和表中任一词相等,则为关键字,插入临时存放关键字的词表中. 2.在索引表中查询关键字时可能出现两种情况:其中一种是索引表上已经有此关键词的索引项,只要在该项中插入书号索引即可:其二是需

数据结构 - 串的性质和基本操作(一)

串的概念 什么是串呢? 串(String):由零个或多个字符组成的有限序列.记为:s='a1a2-an'(n≥0) s为串名, 'a1a2-an'为串值,n为串的长度. 子串在主串中的位置:以子串的第一个字符在主串中的位置来表示 串相等:当且仅当两个串的串值相等(两个串的长度相等,并且各个对应的字符也都相等 串的数据类型 ADT String { D={ ai |ai∈CharacterSet, i=1,2,...,n, n≥0 } R={ < ai-1, ai > | ai-1, ai ∈D

数据结构- 串的模式匹配算法:BF和 KMP算法

Brute-Force算法的思想 1.BF(Brute-Force)算法 Brute-Force算法的基本思想是: 1) 从目标串s 的第一个字符起和模式串t的第一个字符进行比较,若相等,则继续逐个比较后续字符,否则从串s 的第二个字符起再重新和串t进行比较. 2) 依此类推,直至串t 中的每个字符依次和串s的一个连续的字符序列相等,则称模式匹配成功,此时串t的第一个字符在串s 中的位置就是t 在s中的位置,否则模式匹配不成功. Brute-Force算法的实现 c语言实现: [cpp] vie

数据结构串

串的逻辑结构和线性表相似,区别仅为串的数据对象约束为字符集串的基本操作和线性表有很大差别,线性表的基本操作中大多以的“单个元素”作为操作对象:而串的基本操作中通常以“串的整体”作为 操作对象 串的表示:1.定长顺序存储表示: 超过预定义长度的串值则被舍弃,称为“截断” 对串长的表示方法:在下标为0的数组分量存放串的实际长度:在串值后面加一个结束标记字符“\0”2.堆分配存储表示: 仍以一组地址连续的存储单元存放,但存储空间是在程序执行过程中动态分配的 C中动态分配函数:malloc(),free

转载 数据结构 串的模式匹配

转载自http://www.cnblogs.com/dolphin0520/ 十分感谢作者大大 KMP算法 KMP算法 在介绍KMP算法之前,先介绍一下BF算法. 一.BF算法 BF算法是普通的模式匹配算法,BF算法的思想就是将目标串S的第一个字符与模式串P的第一个字符进行匹配,若相等,则继续比较S的第二个字符和P的第二个字符:若不相等,则比较S的第二个字符和P的第一个字符,依次比较下去,直到得出最后的匹配结果. 举例说明: S:  ababcababa P:  ababa  BF算法匹配的步骤

数据结构-串的堆分配存储

串的堆分配存储表示的特点是,仍以一组地址连续的存储单元存放串值字符序列,但它们的存储空间是在程序执行过程中动态分配的.使用动态分配函数malloc()和函数free()来管理存储空间的大小. 串的堆分配存储方法具有顺序存储的特点,又弥补了定长存储的大小限制,多以多被采用. 1 #include <stdio.h> 2 #include <string.h> 3 #include <stdlib.h> 4 5 typedef int Status; 6 #define O