数据结构之串

什么是串?

其实串就是我们日常所说的字符串,它是一系列结点组成的一个线性表,每一个结点存储一个字符。我们知道C语言里并没有字符串这种数据类型,而是利用字符数组加以特殊处理(末尾加'\0')来表示一个字符串,事实上数据结构里的串就是一个存储了字符的链表,并且封装实现了各种字符串的常用操作。

关于Java String 的一些问题

    public static void main(String[] args) {
        System.out.println(substring("张三"));
    }

    public static String substring(String str){
        //剪切字符串
        str.substring(1, str.length());
        return str;
    }

上图输出结果是什么?
String StringBuilder StringBuffer 又有什么区别?
为什么字符串拼接的时候推荐使用StringBuilder?

不要慌,我们现在来了解数据结构之串

String、StringBuilder、StringBuffer类源码分析

String
public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence {
    /** The value is used for character storage. */
    private final char value[];

比较重要的两个部分,String是一个终态类,不允许继承,value字段也是常量,不允许改变,从这一点就已经可以看出我们对字符串的插入、截取等功能其实不是在原有的字符串上操作的。

比如字符串A+字符串B,用String实现其实是,先创建一个字符串C,然后再吧字符串A和B放到C

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++) {
        if (source[i] != first) {
            //匹配第一个字符是否相等
            while (++i <= max && source[i] != first);
        }

        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) {
                return i - sourceOffset;
            }
        }
    }
    //不存在返回-1
    return -1;
}

以上是对indexOf方法做的一些简单说明,解释的话上面注释已经写清楚了

StringBuilder

我们进入StringBuilder的继承类AbstractStringBuilder

abstract class AbstractStringBuilder implements Appendable, CharSequence {
    //跟String不一样的就是这里不是常量的
    char[] value;
    //多了一个count
    int count;
    AbstractStringBuilder() {
    }

    AbstractStringBuilder(int capacity) {
        value = new char[capacity];
    }

    @Override
    public int length() {
      return count;
    }

从上面的代码上,我们可以大致了解到,StringBuilder是由一个非常量字符数组成的
接下来我们再看看StringBuilder的append方法

public AbstractStringBuilder append(String str) {
    if (str == null)
        return appendNull();
    //获取追加字符的长度
    int len = str.length();
    //确保追加的字符串有足够的空间
    ensureCapacityInternal(count + len);
    str.getChars(0, len, value, count);
    count += len;
    return this;
}
StringBuffer

StringBuffer和StringBuilder非常相似,唯一不一样的在于,StringBuffer是线程安全的,因为它每个方法都加了synchronized,比如

public synchronized int length() {
    return count;
}

总结

做Java经常会听说多字符串拼接的时候用StringBuilder能提高效率,从上面的分析可以看出,String进行字符串拼接的时候,首先需要生成一个两个字符串相加之和大小的字符串,然后再把这两个字符串写入的新的字符串中,这种方式的优点是操作简单,但是内存消耗严重,StringBuilder就不一样了,初始化的字符数组是可变的,拼接的时候发现存储空间不够的情况会自动扩容,拼接操作在原有的字符串上进行的。

字符搜索KMP算法

S1: A B C D E F A B C
S2: E F A
搜索S1中是否包含S2

朴素匹配算法

算法复杂度O(n*m)

KMP算法
这文章里面已经有比较完全的解答了
https://segmentfault.com/a/1190000008575379

总结的一些关键信息
最核心的其实就是匹配开头的字符串
next数组存储的其实就是第一个字符开头
KMP算法的根本其实就是不需要想暴力匹配一样全部回退,只需要回退到跟搜索字符相同开头的字符就可以了

ABCDABCEABCA
ABCA

当我们匹配到了ABC之后,发现D不对,其实这种情况下,不用回退到第一个重新匹配,只要找到刚刚匹配的ABC中找到A开头的开始就可以了,next数组就是帮我们实现这一点的
算法复杂度O(n+m)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 前言 最先接触编程的知识是在大学里面,大学里面学了一些基础的知识,c语言,java语言,单片机的汇编语言等;大学毕...
    oceanfive阅读 3,130评论 0 7
  • 引言 当今计算机的硬件结构主要是反映数值计算的需要,在处理字符串的数据时比处理整数和浮点数要复杂,不同类型的应用对...
    冰鑫925阅读 820评论 0 0
  • 一、Java 简介 Java是由Sun Microsystems公司于1995年5月推出的Java面向对象程序设计...
    子非鱼_t_阅读 4,262评论 1 44
  • 在Western实验中,蛋白Marker可以监控蛋白质在SDS-PAGE中的迁移,监控蛋白的转膜效率,确定蛋白分子...
    toneker阅读 18,549评论 0 1
  • 漂浪过的旅程才更懂得安稳生活的可贵 放肆过的青春才明白不曾表达过的热爱 手牵手的玩伴崇尚冒险 分开是为了各自 走一...
    陌上宁秋阅读 165评论 0 1