数据结构——全篇1.1万字保姆级吃透串与数组(超详细)(一)

简介: 数据结构——全篇1.1万字保姆级吃透串与数组(超详细)(一)

1.串概述


串,也称为字符串,是一个种特殊的线性表,由n(n>=0)个字符组成的有序序列。


名词解释


长度:包含的字符个数n。


空串:n为0的串就是空串,不包含任何字符。


空白串:包含一个及以上(n>=1)空白字符的串,长度为空白字符的个数。


子串:串中任意连续的字符组成的子序列。


空串是任意串的子串。


任意串是其自身的子串。“ABC”


主串:包含子串的串。


序号值:在之前的学习过程中称为“索引值”,字符在串中的位置。


子串在主串中的位置:子串在主串中首次出现时的第一个字符在主串中的位置。


串相等:两个串的长度相同,且各个对应位置的字符相同。


串的抽象类型(接口)

public interface IString{
    public void clear();  //串的清空
    public boolean isEmpty(); //是否为空
    public int length();  //串的长度,串中字符的个数
    public char charAt(index);  //返回第index个字符值
    public IString substring(begin,end);  //*获得子串[begin,end)
    public IString insert(offset, str);  //在第offset个字符之前插入str串
    public IString delete(begin, end);  //删除子串[begin,end)
    public IString concat(IString str);  //*把str串连接到当前串的后面
    public int compareTo(IString str);  //串的比较,相同返回0,否则返回正/负
    public int indexOf(str, begin);  //从start开始,返回str在串中位置,不存在返回-1
}


/

2.串的存储


串的存储结构包括:顺序存储 和 链式存储。


顺序存储:使用数组存放字符。

public class SeqString implements IString{
    private char[] strvalue;  // 字符数组,用于存放字符串信息
    private int curlen;    // 串的长度 current length
}


/

链式存储:使用链表存储。


字符链表:每个结点只有一个字符的链表。微信图片_20220531133417.png

块链表:每个结点可以有多个字符。微信图片_20220531133423.png

3.顺序串


3.1算法:基本功能(了解)


public class SeqString implements IString{
    private char[] strvalue;    // 字符数组,用于存放字符串信息
    private int curlen;       // 串的长度 current length
    public void clear() {     //清空
        this.curlen = 0;
    }
    public boolean isEmpty() {    //是否有空
        return this.curlen == 0;
    }
    public int length() {     //串的长度
        return this.curlen;
    }
    public char charAt(int index) {
        if(index < 0 || index >= curlen) {
            throw new 字符串索引越界异常();  //String Index OutOfBounds Exception
        }
        return strvalue[index];
    }
}

3.2算法:扩容

微信图片_20220531133559.png

/**
* @param newCapacity 新容器大小
*/
public void allocate(int newCapacity) {
    char[] temp = strvalue;         // 存放原来的数据 ab数组
    strvalue = new char[newCapacity];   // 给strValue重新赋一个更大数组的值
    for(int i = 0; i < temp.length; i++) {  // 拷贝数据
        strvalue[i] = temp[i];
    }
}

3.3算法:求子串


需求:"abcd".substring(1,3) --> "bc"

微信图片_20220531133652.png

public IString substring(int begin , int end) {
    // 1 两个参数校验
    if(begin < 0) {     // 1.1 begin 不能小于0
        throw new StringIndexOutOfBoundsException("begin不能小于0");
    }
    if(end > curlen) {    // 1.2 end 不能大于当前长度
        throw new StringIndexOutOfBoundsException("end不能大于当前长度");
    }
    if(begin > end) {   // 1.3 
        throw new StringIndexOutOfBoundsException("begin不能大于end");
    }
    // 2 优化:当前串直接返回
    if(begin == 0 && end == curlen) {
        return this;
    } 
    // 3 核心算法
    char[] buffer = new char[end - begin];      // 构建新数组
    for(int i = 0 ; i < buffer.length ; i ++) {   // 依次循环遍历新数组,一个一个赋值
        buffer[i] = strvalue[i + begin];
    }
    return new SeqString(buffer);         // 使用字符数组构建一个新字符串
}

 3.4算法:插入

微信图片_20220531133823.png

/**  "abcdef".insert(2,"123").insert(...)
* @param offset 偏移量,插入的位置
* @param str 插入数据
*/
public IString insert (int offset, IString str) {
    //1 校验
    if(offset < 0 || offset > curlen) {
        throw new StringIndexOutOfBoundsException("插入位置不合法");
    }
    //2 兼容:如果容器不够,需要扩容   当前长度 + 新字符串 > 容器长度
    int newCount = curlen + str.length();
    if( newCount > strvalue.length ) {
        allocate(newCount);   //扩容结果就是刚刚好,没有额外空间
    }
    // 3 核心
    //3.1 核心1:从offset开始向后移动 str长度 个字符
    for(int i = curlen-1 ; i >= offset ; i --) {
        strvalue[i + str.length() ] = strvalue[i];
    }
    //3.2 核心2:依次插入
    for(int i = 0; i < str.length() ; i ++) {
        strvalue[i + offset] = str.charAt(i);
    }
    //3.3 设置数组长度
    this.curlen = newCount;
    return this;
}

3.5算法:删除

微信图片_20220531133936.png

/**
* @param begin 删除开始位置(含)
* @param end 删除结果位置(不含)
*/
public IString delete(int begin , int end) {
    // 1 校验
    // 1.1 begin 范围
    if(begin < 0) {
        throw new StringIndexOutOfBoundsException("begin不能小于0");
    }
    // 1.2 end 范围
    if(end > curlen) {
        throw new StringIndexOutOfBoundsException("end不能大于串长");
    }
    // 1.3 关系
    if(begin > end) {
        throw new StringIndexOutOfBoundsException("begin不能大于end");
    }
    // 2 核心:将后面内容移动到签名
    // 2.1 移动
    for(int i = 0 ; i < curlen - end ; i ++) {
        strvalue[i + begin] = strvalue[i + end];
    }
    // 2.2 重新统计长度  (end-begin 需要删除串的长度)
    curlen = curlen - (end-begin)
    return this;
}

 3.6算法:比较

微信图片_20220531134031.png

/**
* @param str 需要比较的串
* return 
*   >0 : 前面串值的值大于后面串
*   =0 : 前面串值的值等于后面串
*   <0 : 前面串值的值小于后面串
*/
public int compareTo(SeqString str) {
    int n = Math.min(curlen, str.curnlen) ;   // 获得最短串的长度
    int k = 0 ;                 // 循环遍历k
    char[] s1 = strvalue;
    char[] s2 = str.strvalue;
    while(k < n) {
        if(s1[k] != s2[k]) {          // 处理前缀不一致
            return s1[k] - s2[k];
        }
        k++;
    }
    return curlen - str.curlen;         // 两个串的前缀相等
}


相关文章
|
1月前
|
存储 Java 程序员
数据结构之 - 深入了解数组数据结构
数据结构之 - 深入了解数组数据结构
36 6
|
1月前
|
存储 算法 搜索推荐
探索常见数据结构:数组、链表、栈、队列、树和图
探索常见数据结构:数组、链表、栈、队列、树和图
95 64
|
1月前
|
算法 程序员 索引
数据结构与算法学习七:栈、数组模拟栈、单链表模拟栈、栈应用实例 实现 综合计算器
栈的基本概念、应用场景以及如何使用数组和单链表模拟栈,并展示了如何利用栈和中缀表达式实现一个综合计算器。
27 1
数据结构与算法学习七:栈、数组模拟栈、单链表模拟栈、栈应用实例 实现 综合计算器
|
1月前
|
存储 算法 定位技术
数据结构与算法学习二、稀疏数组与队列,数组模拟队列,模拟环形队列
这篇文章主要介绍了稀疏数组和队列的概念、应用实例以及如何使用数组模拟队列和环形队列的实现方法。
20 0
数据结构与算法学习二、稀疏数组与队列,数组模拟队列,模拟环形队列
|
2月前
|
存储 Java
java数据结构,线性表顺序存储(数组)的实现
文章介绍了Java中线性表顺序存储(数组)的实现。线性表是数据结构的一种,它使用数组来实现。文章详细描述了线性表的基本操作,如增加、查找、删除、修改元素,以及其他操作如遍历、清空、求长度等。同时,提供了完整的Java代码实现,包括MyList接口和MyLinearList实现类。通过main函数的测试代码,展示了如何使用这些方法操作线性表。
|
4月前
|
存储
【数据结构OJ题】轮转数组
力扣题目——轮转数组
42 2
【数据结构OJ题】轮转数组
|
3月前
|
存储 Java 程序员
"揭秘HashMap底层实现:从数组到链表,再到红黑树,掌握高效数据结构的秘密武器!"
【8月更文挑战第21天】HashMap是Java中重要的数据结构,采用数组+链表/红黑树实现,确保高效查询与更新。构造方法初始化数组,默认容量16,负载因子0.75触发扩容。`put`操作通过计算`hashCode`定位元素,利用链表或红黑树处理冲突。`get`和`remove`操作类似地定位并返回或移除元素。JDK 1.8优化了链表转红黑树机制,提升性能。理解这些原理能帮助我们更高效地应用HashMap。
42 0
|
5月前
|
存储 算法 调度
【数据结构与算法】详解循环队列:基于数组实现高效存储与访问
【数据结构与算法】详解循环队列:基于数组实现高效存储与访问
|
4月前
|
机器学习/深度学习 存储 算法
数据结构与算法:数组的操作
数据结构与算法:数组的操作
下一篇
无影云桌面