当前位置: 首页 > news >正文

数据结构-串

   串是数据结构中一种重要的数据类型,广泛应用于文本处理、信息检索等领域。本文将从串的基本概念、存储实现、应用举例以及总结核心知识点四个方面进行详细讲解,帮助大家更好地理解和掌握串这一数据结构。

一、串的基本概念及其抽象数据类型

1.1 串的定义

    串(String)是由零个或多个字符组成的有限序列,又名字符串。一般记为:S=′a1​a2​...an′​(n≥0)。其中,S是串名,单引号括起来的字符序列是串的值;an​可以是字母、数字或其他字符;串中字符的个数n称为串的长度。当n=0时,称为空串。例如,"Hello, World!" 是一个长度为13的串。

1.2 串的重要术语

  • 子串与主串:串中任意个连续的字符组成的子序列称为该串的子串,相应地,包含子串的串称为主串。

  • 空串与空格串:长度为零的字符串称为空串由一个或多个空格组成的串称为空格串

  • 串相等:当且仅当两个串的值相等时,称这两个串是相等的。

1.3 串的抽象数据类型

串的抽象数据类型定义如下:

  • 数据对象:D={ai​∣ai​∈CharacterSet,i=1,2,…,n;n≥0}

  • 数据关系:R={<ai−1​,ai​>∣ai−1​,ai​∈D,i=2,…,n;n≥0}

  • 串的ADT包括以下基本操作:

  • 获取长度:返回串的长度

  • 获取字符:返回指定位置的字符

  • 插入字符:在指定位置插入一个字符。

  • 删除字符删除指定位置的字符。

  • 查找子串:在串中查找子串的位置

  • 替换子串:将串中的子串替换为另一个子串

ADT String {数据对象:D = {a_i | a_i ∈ CharacterSet, i=1,2,...,n}数据关系:R = {<a_i,a_i+1> | a_i,a_i+1 ∈ D}基本操作:StrAssign(&T, chars)    # 字符串赋值StrCompare(S, T)        # 比较操作StrLength(S)            # 求长度Concat(&T, S1, S2)      # 连接操作SubString(&Sub, S, pos, len) # 求子串Index(S, T, pos)        # 模式匹配Replace(&S, T, V)       # 替换操作StrInsert(&S, pos, T)   # 插入操作StrDelete(&S, pos, len) # 删除操作
}

二、串的存储实现

2.1 定长顺序串

定长顺序串是将串设计成一种静态结构类型,串的存储分配是在编译时完成的。其结构体定义如下:

#define MAXLEN 255
typedef struct{char ch[MAXLEN];    //每个分量存储一个字符int length;         //串的实际长度
}SString;

基本操作实现:

  • 初始化:将串的长度置为0,所有字符位置初始化为空字符

  • 赋值:将一个字符串常量赋值给串,同时更新串的长度

  • 求子串:根据给定的位置和长度,从主串中取出相应的子串。

  • 连接:将两个串连接起来,形成一个新的串。如果连接后的长度超过预定义的最大长度,则进行截断。

  • 插入:在指定位置插入一个子串。如果插入后长度超过最大长度,则进行截断。

  • 删除:从指定位置删除一定长度的子串。

C语言实现

#define MAX_LEN 100  // 定义最大长度为100// 定义串的结构体
typedef struct {char data[MAX_LEN];  // 使用数组存储字符int length;          // 当前串的长度
} String;// 初始化串
void initString(String *s) {s->length = 0;  // 初始长度为0
}// 在指定位置插入字符
void insertChar(String *s, int pos, char c) {if (pos >= 0 && pos <= s->length && s->length < MAX_LEN) {  // 检查位置是否合法且未超出容量for (int i = s->length; i > pos; i--) {  // 从后往前移动字符s->data[i] = s->data[i-1];}s->data[pos] = c;  // 插入新字符s->length++;       // 长度加1}
}// 删除指定位置的字符
void deleteChar(String *s, int pos) {if (pos >= 0 && pos < s->length) {  // 检查位置是否合法for (int i = pos; i < s->length - 1; i++) {  // 从前往后移动字符s->data[i] = s->data[i+1];}s->length--;  // 长度减1}
}// 查找子串
int findSubstring(String *s, const char *sub) {int subLen = strlen(sub);  // 获取子串长度for (int i = 0; i <= s->length - subLen; i++) {  // 遍历串int j;for (j = 0; j < subLen; j++) {  // 比较子串if (s->data[i + j] != sub[j]) {break;  // 如果不匹配,跳出循环}}if (j == subLen) {  // 如果完全匹配return i;  // 返回子串起始位置}}return -1;  // 未找到返回-1
}// 替换子串
void replaceSubstring(String *s, const char *oldSub, const char *newSub) {int pos = findSubstring(s, oldSub);  // 查找旧子串位置if (pos != -1) {int oldLen = strlen(oldSub);  // 旧子串长度int newLen = strlen(newSub);  // 新子串长度if (newLen > oldLen) {  // 如果新子串更长if (s->length + newLen - oldLen > MAX_LEN) {  // 检查是否超出容量printf("Replacement exceeds maximum length.\n");return;}for (int i = s->length - 1; i >= pos + oldLen; i--) {  // 移动字符为新子串腾位置s->data[i + newLen - oldLen] = s->data[i];}} else if (newLen < oldLen) {  // 如果新子串更短for (int i = pos + oldLen - 1; i >= pos + newLen; i--) {  // 移动字符填补空缺s->data[i] = s->data[i + oldLen - newLen];}}for (int i = 0; i < newLen; i++) {  // 插入新子串s->data[pos + i] = newSub[i];}s->length += newLen - oldLen;  // 更新长度}
}

C++实现

#include <iostream>
#include <cstring>
using namespace std;class String {
private:char *data;  // 指针指向动态分配的内存int length;  // 当前长度int capacity;  // 容量public:String() : length(0), capacity(100) {  // 构造函数data = new char[capacity];  // 动态分配内存}// 在指定位置插入字符void insertChar(int pos, char c) {if (pos >= 0 && pos <= length) {  // 检查位置是否合法if (length == capacity) {  // 如果当前长度等于容量capacity *= 2;  // 扩容char *newData = new char[capacity];  // 新分配内存for (int i = 0; i < length; i++) {  // 复制原有数据newData[i] = data[i];}delete[] data;  // 释放旧内存data = newData;  // 指向新内存}for (int i = length; i > pos; i--) {  // 从后往前移动字符data[i] = data[i-1];}data[pos] = c;  // 插入新字符length++;  // 长度加1}}// 删除指定位置的字符void deleteChar(int pos) {if (pos >= 0 && pos < length) {  // 检查位置是否合法for (int i = pos; i < length - 1; i++) {  // 从前往后移动字符data[i] = data[i+1];}length--;  // 长度减1}}// 查找子串int findSubstring(const char *sub) {int subLen = strlen(sub);  // 获取子串长度for (int i = 0; i <= length - subLen; i++) {  // 遍历串int j;for (j = 0; j < subLen; j++) {  // 比较子串if (data[i + j] != sub[j]) {break;  // 如果不匹配,跳出循环}}if (j == subLen) {  // 如果完全匹配return i;  // 返回子串起始位置}}return -1;  // 未找到返回-1}// 替换子串void replaceSubstring(const char *oldSub, const char *newSub) {int pos = findSubstring(oldSub);  // 查找旧子串位置if (pos != -1) {int oldLen = strlen(oldSub);  // 旧子串长度int newLen = strlen(newSub);  // 新子串长度if (newLen > oldLen) {  // 如果新子串更长if (length + newLen - oldLen > capacity) {  // 检查是否超出容量capacity = length + newLen - oldLen + 100;  // 扩容char *newData = new char[capacity];  // 新分配内存for (int i = 0; i < length; i++) {  // 复制原有数据newData[i] = data[i];}delete[] data;  // 释放旧内存data = newData;  // 指向新内存}for (int i = length - 1; i >= pos + oldLen; i--) {  // 移动字符为新子串腾位置data[i + newLen - oldLen] = data[i];}} else if (newLen < oldLen) {  // 如果新子串更短for (int i = pos + oldLen - 1; i >= pos + newLen; i--) {  // 移动字符填补空缺data[i] = data[i + oldLen - newLen];}}for (int i = 0; i < newLen; i++) {  // 插入新子串data[pos + i] = newSub[i];}length += newLen - oldLen;  // 更新长度}}// 析构函数,释放内存~String() {delete[] data;}
};

Java实现

public class String {private char[] data;  // 使用字符数组存储串private int length;  // 当前长度// 构造函数public String() {data = new char[100];  // 初始容量为100length = 0;  // 初始长度为0}// 在指定位置插入字符public void insertChar(int pos, char c) {if (pos >= 0 && pos <= length) {  // 检查位置是否合法if (length == data.length) {  // 如果当前长度等于容量char[] newData = new char[data.length * 2];  // 扩容System.arraycopy(data, 0, newData, 0, data.length);  // 复制原有数据data = newData;  // 指向新数组}for (int i = length; i > pos; i--) {  // 从后往前移动字符data[i] = data[i-1];}data[pos] = c;  // 插入新字符length++;  // 长度加1}}// 删除指定位置的字符public void deleteChar(int pos) {if (pos >= 0 && pos < length) {  // 检查位置是否合法for (int i = pos; i < length - 1; i++) {  // 从前往后移动字符data[i] = data[i+1];}length--;  // 长度减1}}// 查找子串public int findSubstring(String sub) {int subLen = sub.length();  // 获取子串长度for (int i = 0; i <= length - subLen; i++) {  // 遍历串int j;for (j = 0; j < subLen; j++) {  // 比较子串if (data[i + j] != sub.charAt(j)) {break;  // 如果不匹配,跳出循环}}if (j == subLen) {  // 如果完全匹配return i;  // 返回子串起始位置}}return -1;  // 未找到返回-1}// 替换子串public void replaceSubstring(String oldSub, String newSub) {int pos = findSubstring(oldSub);  // 查找旧子串位置if (pos != -1) {int oldLen = oldSub.length();  // 旧子串长度int newLen = newSub.length();  // 新子串长度if (newLen > oldLen) {  // 如果新子串更长if (length + newLen - oldLen > data.length) {  // 检查是否超出容量char[] newData = new char[data.length + newLen - oldLen + 100];  // 扩容System.arraycopy(data, 0, newData, 0, data.length);  // 复制原有数据data = newData;  // 指向新数组}for (int i = length - 1; i >= pos + oldLen; i--) {  // 移动字符为新子串腾位置data[i + newLen - oldLen] = data[i];}} else if (newLen < oldLen) {  // 如果新子串更短for (int i = pos + oldLen - 1; i >= pos + newLen; i--) {  // 移动字符填补空缺data[i] = data[i + oldLen - newLen];}}for (int i = 0; i < newLen; i++) {  // 插入新子串data[pos + i] = newSub.charAt(i);}length += newLen - oldLen;  // 更新长度}}// 转换为字符串表示@Overridepublic String toString() {return new String(data, 0, length);}
}

Python实现

class String:def __init__(self):self.data = []  # 使用列表存储字符self.length = 0  # 当前长度# 在指定位置插入字符def insert_char(self, pos, c):if 0 <= pos <= self.length:  # 检查位置是否合法self.data.insert(pos, c)  # 使用列表的insert方法插入字符self.length += 1  # 长度加1# 删除指定位置的字符def delete_char(self, pos):if 0 <= pos < self.length:  # 检查位置是否合法del self.data[pos]  # 使用del删除字符self.length -= 1  # 长度减1# 查找子串def find_substring(self, sub):return ''.join(self.data).find(sub)  # 将列表转换为字符串后查找子串# 替换子串def replace_substring(self, old_sub, new_sub):pos = self.find_substring(old_sub)  # 查找旧子串位置if pos != -1:self.data = self.data[:pos] + list(new_sub) + self.data[pos + len(old_sub):]  # 替换子串self.length = len(self.data)  # 更新长度# 转换为字符串表示def __str__(self):return ''.join(self.data)

2.2 堆串

堆串的存储空间是在程序执行过程中动态分配的。其结构体定义如下:

typedef struct{char *ch;   //按串长分配存储区,ch指向串的基地址int length; //串的长度
}HString;

基本操作实现:

  • 初始化:将ch指针置为NULL,长度置为0。

  • 赋值先释放原有的存储空间,然后根据字符串常量的长度动态分配存储空间,并将字符串复制到分配的空间中。

  • 求子串:动态分配存储空间来存储子串。

  • 连接:动态分配足够大的存储空间来存储连接后的串。

  • 插入:动态分配新的存储空间,将原串和插入的子串拼接起来

  • 删除:通过调整指针和长度来实现删除操作,不需要移动字符。

C语言实现

#include <stdlib.h>
#include <string.h>// 定义串的结构体
typedef struct {char *data;  // 指针指向动态分配的内存int length;  // 当前长度int capacity;  // 容量
} String;// 初始化串
void initString(String *s, int capacity) {s->data = (char*)malloc(capacity * sizeof(char));  // 动态分配内存s->length = 0;  // 初始长度为0s->capacity = capacity;  // 设置初始容量
}// 在指定位置插入字符
void insertChar(String *s, int pos, char c) {if (pos >= 0 && pos <= s->length) {  // 检查位置是否合法if (s->length == s->capacity) {  // 如果当前长度等于容量s->capacity *= 2;  // 扩容s->data = (char*)realloc(s->data, s->capacity * sizeof(char));  // 重新分配内存}for (int i = s->length; i > pos; i--) {  // 从后往前移动字符s->data[i] = s->data[i-1];}s->data[pos] = c;  // 插入新字符s->length++;  // 长度加1}
}// 删除指定位置的字符
void deleteChar(String *s, int pos) {if (pos >= 0 && pos < s->length) {  // 检查位置是否合法for (int i = pos; i < s->length - 1; i++) {  // 从前往后移动字符s->data[i] = s->data[i+1];}s->length--;  // 长度减1}
}// 查找子串
int findSubstring(String *s, const char *sub) {int subLen = strlen(sub);  // 获取子串长度for (int i = 0; i <= s->length - subLen; i++) {  // 遍历串int j;for (j = 0; j < subLen; j++) {  // 比较子串if (s->data[i + j] != sub[j]) {break;  // 如果不匹配,跳出循环}}if (j == subLen) {  // 如果完全匹配return i;  // 返回子串起始位置}}return -1;  // 未找到返回-1
}// 替换子串
void replaceSubstring(String *s, const char *oldSub, const char *newSub) {int pos = findSubstring(s, oldSub);  // 查找旧子串位置if (pos != -1) {int oldLen = strlen(oldSub);  // 旧子串长度int newLen = strlen(newSub);  // 新子串长度if (newLen > oldLen) {  // 如果新子串更长if (s->length + newLen - oldLen > s->capacity) {  // 检查是否超出容量s->capacity = s->length + newLen - oldLen;  // 扩容s->data = (char*)realloc(s->data, s->capacity * sizeof(char));  // 重新分配内存}for (int i = s->length - 1; i >= pos + oldLen; i--) {  // 移动字符为新子串腾位置s->data[i + newLen - oldLen] = s->data[i];}} else if (newLen < oldLen) {  // 如果新子串更短for (int i = pos + oldLen - 1; i >= pos + newLen; i--) {  // 移动字符填补空缺s->data[i] = s->data[i + oldLen - newLen];}}for (int i = 0; i < newLen; i++) {  // 插入新子串s->data[pos + i] = newSub[i];}s->length += newLen - oldLen;  // 更新长度}
}// 释放内存
void freeString(String *s) {free(s->data);  // 释放动态分配的内存
}

C++实现

#include <iostream>
#include <cstring>
using namespace std;// 定义节点结构
struct Node {char data;  // 存储字符Node *next;  // 指向下一个节点
};// 定义串的类
class String {
private:Node *head;  // 指向头节点int length;  // 当前长度public:// 构造函数String() : head(NULL), length(0) {}// 在指定位置插入字符void insertChar(int pos, char c) {if (pos >= 0 && pos <= length) {  // 检查位置是否合法Node *newNode = new Node();  // 创建新节点newNode->data = c;  // 设置节点数据if (pos == 0) {  // 如果插入到头部newNode->next = head;head = newNode;} else {  // 插入到指定位置Node *current = head;for (int i = 0; i < pos - 1; i++) {  // 遍历到前一个节点current = current->next;}newNode->next = current->next;current->next = newNode;}length++;  // 长度加1}}// 删除指定位置的字符void deleteChar(int pos) {if (pos >= 0 && pos < length) {  // 检查位置是否合法if (pos == 0) {  // 如果删除头部Node *temp = head;head = head->next;delete temp;  // 释放内存} else {  // 删除指定位置Node *current = head;for (int i = 0; i < pos - 1; i++) {  // 遍历到前一个节点current = current->next;}Node *temp = current->next;current->next = temp->next;delete temp;  // 释放内存}length--;  // 长度减1}}// 查找子串int findSubstring(const char *sub) {Node *current = head;StringBuilder sb;  // 构建当前串while (current != NULL) {sb.append(current->data);current = current->next;}return sb.toString().find(sub);  // 查找子串}// 替换子串void replaceSubstring(const char *oldSub, const char *newSub) {int pos = findSubstring(oldSub);  // 查找旧子串位置if (pos != -1) {deleteSubstring(pos, strlen(oldSub));  // 删除旧子串for (int i = strlen(newSub) - 1; i >= 0; i--) {  // 插入新子串insertChar(pos, newSub[i]);}}}// 删除子串void deleteSubstring(int pos, int len) {for (int i = 0; i < len; i++) {deleteChar(pos);  // 逐个删除字符}}// 转换为字符串表示string toString() {Node *current = head;string result;while (current != NULL) {result += current->data;current = current->next;}return result;}// 析构函数,释放内存~String() {while (head != NULL) {Node *temp = head;head = head->next;delete temp;}}
};

Java实现

public class String {private class Node {char data;  // 存储字符Node next;  // 指向下一个节点}private Node head;  // 指向头节点private int length;  // 当前长度// 构造函数public String() {head = null;  // 初始头节点为nulllength = 0;  // 初始长度为0}// 在指定位置插入字符public void insertChar(int pos, char c) {if (pos >= 0 && pos <= length) {  // 检查位置是否合法Node newNode = new Node();  // 创建新节点newNode.data = c;  // 设置节点数据if (pos == 0) {  // 如果插入到头部newNode.next = head;head = newNode;} else {  // 插入到指定位置Node current = head;for (int i = 0; i < pos - 1; i++) {  // 遍历到前一个节点current = current.next;}newNode.next = current.next;current.next = newNode;}length++;  // 长度加1}}// 删除指定位置的字符public void deleteChar(int pos) {if (pos >= 0 && pos < length) {  // 检查位置是否合法if (pos == 0) {  // 如果删除头部head = head.next;} else {  // 删除指定位置Node current = head;for (int i = 0; i < pos - 1; i++) {  // 遍历到前一个节点current = current.next;}current.next = current.next.next;}length--;  // 长度减1}}// 查找子串public int findSubstring(String sub) {Node current = head;StringBuilder sb = new StringBuilder();  // 构建当前串while (current != null) {sb.append(current.data);current = current.next;}return sb.toString().indexOf(sub);  // 查找子串}// 替换子串public void replaceSubstring(String oldSub, String newSub) {int pos = findSubstring(oldSub);  // 查找旧子串位置if (pos != -1) {deleteSubstring(pos, oldSub.length());  // 删除旧子串for (int i = newSub.length() - 1; i >= 0; i--) {  // 插入新子串insertChar(pos, newSub.charAt(i));}}}// 删除子串private void deleteSubstring(int pos, int len) {for (int i = 0; i < len; i++) {deleteChar(pos);  // 逐个删除字符}}// 转换为字符串表示@Overridepublic String toString() {Node current = head;StringBuilder sb = new StringBuilder();while (current != null) {sb.append(current.data);current = current.next;}return sb.toString();}
}

Python实现

class Node:def __init__(self, data):self.data = data  # 存储字符self.next = None  # 指向下一个节点class String:def __init__(self):self.head = None  # 指向头节点self.length = 0  # 当前长度# 在指定位置插入字符def insert_char(self, pos, c):if 0 <= pos <= self.length:  # 检查位置是否合法new_node = Node(c)  # 创建新节点if pos == 0:  # 如果插入到头部new_node.next = self.headself.head = new_nodeelse:  # 插入到指定位置current = self.headfor _ in range(pos - 1):  # 遍历到前一个节点current = current.nextnew_node.next = current.nextcurrent.next = new_nodeself.length += 1  # 长度加1# 删除指定位置的字符def delete_char(self, pos):if 0 <= pos < self.length:  # 检查位置是否合法if pos == 0:  # 如果删除头部self.head = self.head.nextelse:  # 删除指定位置current = self.headfor _ in range(pos - 1):  # 遍历到前一个节点current = current.nextcurrent.next = current.next.nextself.length -= 1  # 长度减1# 查找子串def find_substring(self, sub):current = self.headsb = []  # 构建当前串while current is not None:sb.append(current.data)current = current.nextreturn ''.join(sb).find(sub)  # 查找子串# 替换子串def replace_substring(self, old_sub, new_sub):pos = self.find_substring(old_sub)  # 查找旧子串位置if pos != -1:self.delete_substring(pos, len(old_sub))  # 删除旧子串for i in reversed(new_sub):  # 插入新子串self.insert_char(pos, i)# 删除子串def delete_substring(self, pos, length):for _ in range(length):self.delete_char(pos)  # 逐个删除字符# 转换为字符串表示def __str__(self):current = self.headresult = []while current is not None:result.append(current.data)current = current.nextreturn ''.join(result)

2.3 块链串

块链串采用链式存储结构每个结点存储一个字符。其结构体定义如下:

typedef struct snode{char data;          //存储字符struct snode *next; //指向下一个结点
}LiString;

基本操作实现:

  • 初始化创建一个头结点,其next指针置为NULL。

  • 赋值:通过尾插法将字符串常量的每个字符逐个插入到链表中。

  • 求子串:从头结点开始遍历链表,找到指定位置的结点,然后逐个复制字符到新的链表中。

  • 连接:将两个链表连接起来,形成一个新的链表。

  • 插入:在指定位置插入一个子链表。

  • 删除:通过调整指针来删除指定位置的子链表。

C语言实现

#include <stdio.h>
#include <stdlib.h>
#include <string.h>#define BLOCK_SIZE 5  // 块的大小// 定义块结构
typedef struct Block {char data[BLOCK_SIZE];  // 存储字符的数组struct Block *next;     // 指向下一个块的指针
} Block;// 定义串结构
typedef struct {Block *head;  // 指向第一个块int length;   // 串的总长度
} String;// 初始化串
void initString(String *s) {s->head = NULL;  // 初始时没有块s->length = 0;   // 初始长度为0
}// 创建新块
Block* createBlock() {Block *block = (Block*)malloc(sizeof(Block));  // 分配内存block->next = NULL;  // 初始化next指针为NULLreturn block;
}// 在指定位置插入字符
void insertChar(String *s, int pos, char c) {if (pos < 0 || pos > s->length) {printf("Invalid position\n");return;}// 计算块索引和块内位置int blockIndex = pos / BLOCK_SIZE;int offset = pos % BLOCK_SIZE;// 遍历到目标块Block *current = s->head;Block *prev = NULL;for (int i = 0; i < blockIndex; i++) {if (current == NULL) {// 如果目标块不存在,创建新块Block *newBlock = createBlock();if (prev == NULL) {s->head = newBlock;} else {prev->next = newBlock;}current = newBlock;} else {prev = current;current = current->next;}}// 如果当前块已满,创建新块if (current == NULL || offset >= BLOCK_SIZE) {Block *newBlock = createBlock();if (prev == NULL) {s->head = newBlock;} else {prev->next = newBlock;}current = newBlock;offset = 0;blockIndex++;}// 插入字符for (int i = BLOCK_SIZE - 1; i > offset; i--) {current->data[i] = current->data[i - 1];}current->data[offset] = c;s->length++;
}// 删除指定位置的字符
void deleteChar(String *s, int pos) {if (pos < 0 || pos >= s->length) {printf("Invalid position\n");return;}// 计算块索引和块内位置int blockIndex = pos / BLOCK_SIZE;int offset = pos % BLOCK_SIZE;// 遍历到目标块Block *current = s->head;Block *prev = NULL;for (int i = 0; i < blockIndex; i++) {prev = current;current = current->next;if (current == NULL) {printf("Block not found\n");return;}}// 删除字符for (int i = offset; i < BLOCK_SIZE - 1; i++) {current->data[i] = current->data[i + 1];}// 如果当前块为空,删除该块if (current->data[0] == '\0') {if (prev == NULL) {s->head = current->next;} else {prev->next = current->next;}free(current);}s->length--;
}// 查找子串
int findSubstring(String *s, const char *sub) {int subLen = strlen(sub);if (subLen == 0) return 0;int pos = 0;Block *current = s->head;while (current != NULL) {for (int i = 0; i < BLOCK_SIZE && pos < s->length; i++) {if (current->data[i] == sub[0]) {// 检查是否匹配子串int j;for (j = 1; j < subLen && pos + j < s->length; j++) {Block *temp = current;int k = i + 1;while (k >= BLOCK_SIZE && temp != NULL) {temp = temp->next;k -= BLOCK_SIZE;}if (temp == NULL || temp->data[k] != sub[j]) {break;}}if (j == subLen) {return pos;}}pos++;}current = current->next;}return -1;
}// 替换子串
void replaceSubstring(String *s, const char *oldSub, const char *newSub) {int pos = findSubstring(s, oldSub);if (pos == -1) return;int oldLen = strlen(oldSub);int newLen = strlen(newSub);// 删除旧子串for (int i = 0; i < oldLen; i++) {deleteChar(s, pos);}// 插入新子串for (int i = 0; i < newLen; i++) {insertChar(s, pos + i, newSub[i]);}
}// 释放串的内存
void freeString(String *s) {Block *current = s->head;while (current != NULL) {Block *temp = current;current = current->next;free(temp);}s->head = NULL;s->length = 0;
}// 打印串
void printString(String *s) {Block *current = s->head;while (current != NULL) {for (int i = 0; i < BLOCK_SIZE && i < s->length; i++) {printf("%c", current->data[i]);}current = current->next;}printf("\n");
}// 主函数
int main() {String s;initString(&s);// 插入字符insertChar(&s, 0, 'H');insertChar(&s, 1, 'e');insertChar(&s, 2, 'l');insertChar(&s, 3, 'l');insertChar(&s, 4, 'o');printf("String: ");printString(&s);// 删除字符deleteChar(&s, 4);printf("After deletion: ");printString(&s);// 查找子串const char *sub = "ll";int pos = findSubstring(&s, sub);if (pos != -1) {printf("Substring found at position: %d\n", pos);} else {printf("Substring not found.\n");}// 替换子串const char *oldSub = "ll";const char *newSub = "mm";replaceSubstring(&s, oldSub, newSub);printf("After replacement: ");printString(&s);// 释放内存freeString(&s);return 0;
}

C++实现

#include <iostream>
#include <cstring>
using namespace std;#define BLOCK_SIZE 5  // 块的大小// 定义块类
class Block {
public:char data[BLOCK_SIZE];  // 存储字符的数组Block *next;            // 指向下一个块的指针Block() {next = NULL;}
};// 定义串类
class String {
private:Block *head;  // 指向第一个块int length;   // 串的总长度public:String() {head = NULL;  // 初始时没有块length = 0;   // 初始长度为0}// 在指定位置插入字符void insertChar(int pos, char c) {if (pos < 0 || pos > length) {cout << "Invalid position" << endl;return;}int blockIndex = pos / BLOCK_SIZE;int offset = pos % BLOCK_SIZE;Block *current = head;Block *prev = NULL;for (int i = 0; i < blockIndex; i++) {if (current == NULL) {Block *newBlock = new Block();if (prev == NULL) {head = newBlock;} else {prev->next = newBlock;}current = newBlock;} else {prev = current;current = current->next;}}if (current == NULL || offset >= BLOCK_SIZE) {Block *newBlock = new Block();if (prev == NULL) {head = newBlock;} else {prev->next = newBlock;}current = newBlock;offset = 0;blockIndex++;}for (int i = BLOCK_SIZE - 1; i > offset; i--) {current->data[i] = current->data[i - 1];}current->data[offset] = c;length++;}// 删除指定位置的字符void deleteChar(int pos) {if (pos < 0 || pos >= length) {cout << "Invalid position" << endl;return;}int blockIndex = pos / BLOCK_SIZE;int offset = pos % BLOCK_SIZE;Block *current = head;Block *prev = NULL;for (int i = 0; i < blockIndex; i++) {prev = current;current = current->next;if (current == NULL) {cout << "Block not found" << endl;return;}}for (int i = offset; i < BLOCK_SIZE - 1; i++) {current->data[i] = current->data[i + 1];}if (current->data[0] == '\0') {if (prev == NULL) {head = current->next;} else {prev->next = current->next;}delete current;}length--;}// 查找子串int findSubstring(const char *sub) {int subLen = strlen(sub);if (subLen == 0) return 0;int pos = 0;Block *current = head;while (current != NULL) {for (int i = 0; i < BLOCK_SIZE && pos < length; i++) {if (current->data[i] == sub[0]) {int j;for (j = 1; j < subLen && pos + j < length; j++) {Block *temp = current;int k = i + 1;while (k >= BLOCK_SIZE && temp != NULL) {temp = temp->next;k -= BLOCK_SIZE;}if (temp == NULL || temp->data[k] != sub[j]) {break;}}if (j == subLen) {return pos;}}pos++;}current = current->next;}return -1;}// 替换子串void replaceSubstring(const char *oldSub, const char *newSub) {int pos = findSubstring(oldSub);if (pos == -1) return;int oldLen = strlen(oldSub);int newLen = strlen(newSub);for (int i = 0; i < oldLen; i++) {deleteChar(pos);}for (int i = 0; i < newLen; i++) {insertChar(pos + i, newSub[i]);}}// 打印串void print() {Block *current = head;while (current != NULL) {for (int i = 0; i < BLOCK_SIZE && i < length; i++) {cout << current->data[i];}current = current->next;}cout << endl;}// 释放内存~String() {Block *current = head;while (current != NULL) {Block *temp = current;current = current->next;delete temp;}}
};int main() {String s;s.insertChar(0, 'H');s.insertChar(1, 'e');s.insertChar(2, 'l');s.insertChar(3, 'l');s.insertChar(4, 'o');cout << "String: ";s.print();s.deleteChar(4);cout << "After deletion: ";s.print();const char *sub = "ll";int pos = s.findSubstring(sub);if (pos != -1) {cout << "Substring found at position: " << pos << endl;} else {cout << "Substring not found." << endl;}const char *oldSub = "ll";const char *newSub = "mm";s.replaceSubstring(oldSub, newSub);cout << "After replacement: ";s.print();return 0;
}

Java实现

public class BlockString {private static final int BLOCK_SIZE = 5;  // 块的大小// 定义块类private static class Block {char[] data = new char[BLOCK_SIZE];  // 存储字符的数组Block next;                          // 指向下一个块的指针Block() {next = null;}}// 定义串类private static class String {private Block head;  // 指向第一个块private int length;  // 串的总长度String() {head = null;  // 初始时没有块length = 0;   // 初始长度为0}// 在指定位置插入字符void insertChar(int pos, char c) {if (pos < 0 || pos > length) {System.out.println("Invalid position");return;}int blockIndex = pos / BLOCK_SIZE;int offset = pos % BLOCK_SIZE;Block current = head;Block prev = null;for (int i = 0; i < blockIndex; i++) {if (current == null) {Block newBlock = new Block();if (prev == null) {head = newBlock;} else {prev.next = newBlock;}current = newBlock;} else {prev = current;current = current.next;}}if (current == null || offset >= BLOCK_SIZE) {Block newBlock = new Block();if (prev == null) {head = newBlock;} else {prev.next = newBlock;}current = newBlock;offset = 0;blockIndex++;}for (int i = BLOCK_SIZE - 1; i > offset; i--) {current.data[i] = current.data[i - 1];}current.data[offset] = c;length++;}// 删除指定位置的字符void deleteChar(int pos) {if (pos < 0 || pos >= length) {System.out.println("Invalid position");return;}int blockIndex = pos / BLOCK_SIZE;int offset = pos % BLOCK_SIZE;Block current = head;Block prev = null;for (int i = 0; i < blockIndex; i++) {prev = current;current = current.next;if (current == null) {System.out.println("Block not found");return;}}for (int i = offset; i < BLOCK_SIZE - 1; i++) {current.data[i] = current.data[i + 1];}if (current.data[0] == '\0') {if (prev == null) {head = current.next;} else {prev.next = current.next;}}length--;}// 查找子串int findSubstring(String sub) {int subLen = sub.length();if (subLen == 0) return 0;int pos = 0;Block current = head;while (current != null) {for (int i = 0; i < BLOCK_SIZE && pos < length; i++) {if (current.data[i] == sub.charAt(0)) {int j;for (j = 1; j < subLen && pos + j < length; j++) {Block temp = current;int k = i + 1;while (k >= BLOCK_SIZE && temp != null) {temp = temp.next;k -= BLOCK_SIZE;}if (temp == null || temp.data[k] != sub.charAt(j)) {break;}}if (j == subLen) {return pos;}}pos++;}current = current.next;}return -1;}// 替换子串void replaceSubstring(String oldSub, String newSub) {int pos = findSubstring(oldSub);if (pos == -1) return;int oldLen = oldSub.length();int newLen = newSub.length();for (int i = 0; i < oldLen; i++) {deleteChar(pos);}for (int i = 0; i < newLen; i++) {insertChar(pos + i, newSub.charAt(i));}}// 打印串void print() {Block current = head;while (current != null) {for (int i = 0; i < BLOCK_SIZE && i < length; i++) {System.out.print(current.data[i]);}current = current.next;}System.out.println();}}public static void main(String[] args) {String s = new String();s.insertChar(0, 'H');s.insertChar(1, 'e');s.insertChar(2, 'l');s.insertChar(3, 'l');s.insertChar(4, 'o');System.out.print("String: ");s.print();s.deleteChar(4);System.out.print("After deletion: ");s.print();String sub = new String();sub.insertChar(0, 'l');sub.insertChar(1, 'l');int pos = s.findSubstring(sub);if (pos != -1) {System.out.println("Substring found at position: " + pos);} else {System.out.println("Substring not found.");}String oldSub = new String();oldSub.insertChar(0, 'l');oldSub.insertChar(1, 'l');String newSub = new String();newSub.insertChar(0, 'm');newSub.insertChar(1, 'm');s.replaceSubstring(oldSub, newSub);System.out.print("After replacement: ");s.print();}
}

Python实现

class Block:def __init__(self, block_size=5):self.data = [''] * block_size  # 存储字符的数组self.next = None              # 指向下一个块的指针self.block_size = block_size  # 块的大小class String:def __init__(self, block_size=5):self.head = None              # 指向第一个块self.length = 0               # 串的总长度self.block_size = block_size  # 块的大小def insert_char(self, pos, c):if pos < 0 or pos > self.length:print("Invalid position")returnblock_index = pos // self.block_sizeoffset = pos % self.block_sizecurrent = self.headprev = Nonefor i in range(block_index):if current is None:new_block = Block(self.block_size)if prev is None:self.head = new_blockelse:prev.next = new_blockcurrent = new_blockelse:prev = currentcurrent = current.nextif current is None or offset >= self.block_size:new_block = Block(self.block_size)if prev is None:self.head = new_blockelse:prev.next = new_blockcurrent = new_blockoffset = 0block_index += 1# 移动字符为新字符腾位置for i in range(self.block_size - 1, offset, -1):if i < self.block_size:current.data[i] = current.data[i - 1]current.data[offset] = cself.length += 1def delete_char(self, pos):if pos < 0 or pos >= self.length:print("Invalid position")returnblock_index = pos // self.block_sizeoffset = pos % self.block_sizecurrent = self.headprev = Nonefor i in range(block_index):prev = currentcurrent = current.nextif current is None:print("Block not found")return# 移动字符填补空缺for i in range(offset, self.block_size - 1):current.data[i] = current.data[i + 1]# 如果当前块为空,删除该块if all(char == '' for char in current.data):if prev is None:self.head = current.nextelse:prev.next = current.nextdel currentself.length -= 1def find_substring(self, sub):sub_len = len(sub)if sub_len == 0:return 0pos = 0current = self.headwhile current is not None:for i in range(self.block_size):if pos >= self.length:breakif current.data[i] == sub[0]:match = Truefor j in range(1, sub_len):if pos + j >= self.length:match = Falsebreaktemp = currentk = i + 1while k >= self.block_size and temp is not None:temp = temp.nextk -= self.block_sizeif temp is None or k >= self.block_size or temp.data[k] != sub[j]:match = Falsebreakif match:return pospos += 1if pos >= self.length:breakcurrent = current.nextreturn -1def replace_substring(self, old_sub, new_sub):pos = self.find_substring(old_sub)if pos == -1:returnold_len = len(old_sub)new_len = len(new_sub)# 删除旧子串for _ in range(old_len):self.delete_char(pos)# 插入新子串for i in range(new_len):self.insert_char(pos + i, new_sub[i])def __str__(self):result = []current = self.headwhile current is not None:for i in range(self.block_size):if len(result) < self.length:result.append(current.data[i])current = current.nextreturn ''.join(result)def main():s = String(block_size=5)s.insert_char(0, 'H')s.insert_char(1, 'e')s.insert_char(2, 'l')s.insert_char(3, 'l')s.insert_char(4, 'o')print("String:", s)s.delete_char(4)print("After deletion:", s)sub = "ll"pos = s.find_substring(sub)if pos != -1:print(f"Substring '{sub}' found at position: {pos}")else:print(f"Substring '{sub}' not found.")old_sub = "ll"new_sub = "mm"s.replace_substring(old_sub, new_sub)print("After replacement:", s)if __name__ == "__main__":main()

三、串的应用举例:简单的行编辑器

   行编辑器是一种以行为单位进行编辑的文本编辑程序。我们可以使用串的数据结构来实现一个简单的行编辑器,具备行插入、行删除等基本功能。

3.1 行编辑器的功能

  • 行插入:在指定行号之后插入一行文本

  • 行删除:删除指定行号的行,或者删除指定范围内的行。

  • 活区切换:将当前活区的内容写入输出文件,并从输入文件中读入下一段作为新的活区。

  • 活区显示:逐页显示活区的内容,每页显示若干行。

3.2 行编辑器的实现

   我们可以使用链表来存储每一行的文本,每个结点存储一行的内容。通过指针操作来实现行的插入和删除。以下是部分代码示例:

typedef struct text{char string[80];    //存储每一行的元素struct text *next;  //指向后一个节点的指针struct text *pre;   //指向前一个节点的指针int num;            //每一行元素的长度int flat;           //确定此行是否被删除的标志
}text;
  • 行插入:在指定行号之后插入一行文本

int insert(text *head, int hang, char *content){text *p = head;for(int i = 0; i < hang - 1; i++){p = p->next;}text *newNode = (text *)malloc(sizeof(text));newNode->num = strlen(content);strcpy(newNode->string, content);newNode->flat = 1;newNode->next = p->next;newNode->pre = p;p->next->pre = newNode;p->next = newNode;return 1;
}
  • 行删除:删除指定行号的行。

int del(text *head, int hang){text *p = head;for(int i = 0; i < hang; i++){p = p->next;}p->pre->next = p->next;p->next->pre = p->pre;free(p);return 1;
}

C语言实现

// 引入标准输入输出头文件,用于使用printf和scanf等函数
#include <stdio.h>
// 引入字符串处理头文件,用于使用strlen等字符串处理函数
#include <string.h>// 定义一个常量MAX_LEN,表示串的最大长度为100
#define MAX_LEN 100// 定义串的结构体,使用typedef为结构体起别名String
typedef struct {// 字符数组,用于存储串的内容,最大长度为MAX_LENchar data[MAX_LEN];// 整型变量,记录当前串的实际长度int length;
} String;// 初始化串的函数,接收一个指向String结构体的指针
void initString(String *s) {// 将串的长度初始化为0,表示空串s->length = 0;
}// 在指定位置插入字符的函数,接收一个指向String结构体的指针、插入位置和要插入的字符
void insertChar(String *s, int pos, char c) {// 检查插入位置是否合法(在0到当前串长度之间)且串还有剩余空间if (pos >= 0 && pos <= s->length && s->length < MAX_LEN) {// 从串的末尾开始,将插入位置及之后的字符依次向后移动一位for (int i = s->length; i > pos; i--) {s->data[i] = s->data[i-1];}// 在指定位置插入字符s->data[pos] = c;// 串的长度加1s->length++;}
}// 删除指定位置字符的函数,接收一个指向String结构体的指针和要删除的位置
void deleteChar(String *s, int pos) {// 检查删除位置是否合法(在0到当前串长度减1之间)if (pos >= 0 && pos < s->length) {// 从删除位置开始,将后面的字符依次向前移动一位for (int i = pos; i < s->length - 1; i++) {s->data[i] = s->data[i+1];}// 串的长度减1s->length--;}
}// 查找子串的函数,接收一个指向String结构体的指针和要查找的子串
int findSubstring(String *s, const char *sub) {// 计算子串的长度int subLen = strlen(sub);// 遍历主串,检查是否存在子串for (int i = 0; i <= s->length - subLen; i++) {int j;// 逐字符比较主串从位置i开始的子串与要查找的子串for (j = 0; j < subLen; j++) {if (s->data[i + j] != sub[j]) {// 若有不相等的字符,跳出内层循环break;}}if (j == subLen) {// 若内层循环正常结束,说明找到了子串,返回其起始位置return i;}}// 若未找到子串,返回-1return -1;
}// 替换子串的函数,接收一个指向String结构体的指针、要替换的旧子串和新子串
void replaceSubstring(String *s, const char *oldSub, const char *newSub) {// 查找旧子串在主串中的位置int pos = findSubstring(s, oldSub);if (pos != -1) {// 计算旧子串的长度int oldLen = strlen(oldSub);// 计算新子串的长度int newLen = strlen(newSub);// 若新子串长度大于旧子串长度if (newLen > oldLen) {// 检查替换后是否会超出串的最大长度if (s->length + newLen - oldLen > MAX_LEN) {// 若超出,输出提示信息并返回printf("Replacement exceeds maximum length.\n");return;}// 从串的末尾开始,将插入位置及之后的字符依次向后移动新旧子串长度差的位数for (int i = s->length - 1; i >= pos + oldLen; i--) {s->data[i + newLen - oldLen] = s->data[i];}} else if (newLen < oldLen) {// 若新子串长度小于旧子串长度,将多余的字符向前移动for (int i = pos + oldLen - 1; i >= pos + newLen; i--) {s->data[i] = s->data[i + oldLen - newLen];}}// 将新子串复制到指定位置for (int i = 0; i < newLen; i++) {s->data[pos + i] = newSub[i];}// 更新串的长度s->length += newLen - oldLen;}
}// 主函数,程序的入口点
int main() {// 定义一个String类型的变量sString s;// 调用初始化函数,将串s初始化为空串initString(&s);// 依次在串s的开头插入字符'H' 'e' 'l' 'l' 'o'insertChar(&s, 0, 'H');insertChar(&s, 1, 'e');insertChar(&s, 2, 'l');insertChar(&s, 3, 'l');insertChar(&s, 4, 'o');// 输出当前串的内容printf("String: %.*s\n", s.length, s.data);// 删除串s中位置为4的字符deleteChar(&s, 4);// 输出删除字符后的串的内容printf("After deletion: %.*s\n", s.length, s.data);// 定义要查找的子串const char *sub = "ll";// 查找子串在串s中的位置int pos = findSubstring(&s, sub);if (pos != -1) {// 若找到,输出子串的起始位置printf("Substring found at position: %d\n", pos);} else {// 若未找到,输出未找到的提示信息printf("Substring not found.\n");}// 定义要替换的旧子串和新子串const char *oldSub = "ll";const char *newSub = "mm";// 调用替换子串的函数,将旧子串替换为新子串replaceSubstring(&s, oldSub, newSub);// 输出替换后的串的内容printf("After replacement: %.*s\n", s.length, s.data);// 程序正常结束,返回0return 0;
}

C++实现

// 引入输入输出流头文件,用于标准输入输出操作
#include <iostream>
// 引入字符串处理头文件,用于使用标准库中的字符串类和相关函数
#include <string>
// 使用标准命名空间,这样可以直接使用标准库中的函数和类,而无需加std::前缀
using namespace std;// 自定义字符串类String
class String {
private:// 指向字符数组的指针,用于存储字符串内容char *data;// 当前字符串的长度int length;// 字符数组的容量,即当前分配的内存大小int capacity;public:// 构造函数,使用初始化列表初始化length为0,capacity为100String() : length(0), capacity(100) {// 为字符数组分配capacity大小的内存空间data = new char[capacity];}// 向字符串指定位置插入一个字符的函数void insertChar(int pos, char c) {// 检查插入位置是否合法,必须在0到length之间(包含两端)if (pos >= 0 && pos <= length) {// 检查当前字符串长度是否达到容量上限if (length == capacity) {// 若达到上限,将容量扩大为原来的2倍capacity *= 2;// 为新的字符数组分配扩大后的容量大小的内存空间char *newData = new char[capacity];// 将原字符数组中的内容复制到新的字符数组中for (int i = 0; i < length; i++) {newData[i] = data[i];}// 释放原字符数组占用的内存空间delete[] data;// 让data指针指向新的字符数组data = newData;}// 将插入位置及之后的字符依次向后移动一位for (int i = length; i > pos; i--) {data[i] = data[i-1];}// 在指定位置插入新字符data[pos] = c;// 字符串长度加1length++;}}// 删除字符串指定位置字符的函数void deleteChar(int pos) {// 检查删除位置是否合法,必须在0到length-1之间if (pos >= 0 && pos < length) {// 将删除位置之后的字符依次向前移动一位for (int i = pos; i < length - 1; i++) {data[i] = data[i+1];}// 字符串长度减1length--;}}// 查找子字符串在当前字符串中首次出现位置的函数int findSubstring(const char *sub) {// 计算子字符串的长度int subLen = strlen(sub);// 遍历当前字符串,检查是否存在子字符串for (int i = 0; i <= length - subLen; i++) {int j;// 逐字符比较当前字符串从位置i开始的子串与目标子字符串for (j = 0; j < subLen; j++) {if (data[i + j] != sub[j]) {// 若有不相等的字符,跳出内层循环break;}}if (j == subLen) {// 若内层循环正常结束,说明找到了子字符串,返回其起始位置return i;}}// 若未找到子字符串,返回-1return -1;}// 替换字符串中指定子字符串的函数void replaceSubstring(const char *oldSub, const char *newSub) {// 查找旧子字符串在当前字符串中的位置int pos = findSubstring(oldSub);if (pos != -1) {// 计算旧子字符串的长度int oldLen = strlen(oldSub);// 计算新子字符串的长度int newLen = strlen(newSub);// 若新子字符串长度大于旧子字符串长度if (newLen > oldLen) {// 检查是否需要扩容if (length + newLen - oldLen > capacity) {// 若需要,将容量调整为长度加上新旧子字符串长度差再加上100capacity = length + newLen - oldLen + 100;// 为新的字符数组分配扩大后的容量大小的内存空间char *newData = new char[capacity];// 将原字符数组中的内容复制到新的字符数组中for (int i = 0; i < length; i++) {newData[i] = data[i];}// 释放原字符数组占用的内存空间delete[] data;// 让data指针指向新的字符数组data = newData;}// 将插入位置之后的字符依次向后移动新旧子字符串长度差的位数for (int i = length - 1; i >= pos + oldLen; i--) {data[i + newLen - oldLen] = data[i];}} else if (newLen < oldLen) {// 若新子字符串长度小于旧子字符串长度,将多余的字符向前移动for (int i = pos + oldLen - 1; i >= pos + newLen; i--) {data[i] = data[i + oldLen - newLen];}}// 将新子字符串复制到指定位置for (int i = 0; i < newLen; i++) {data[pos + i] = newSub[i];}// 更新字符串长度length += newLen - oldLen;}}// 析构函数,用于释放字符数组占用的内存空间~String() {delete[] data;}// 将自定义字符串类转换为标准库字符串类的函数string toString() {return string(data, length);}
};// 主函数,程序的入口点
int main() {// 创建一个自定义字符串类的对象String s;// 依次在字符串开头插入字符'H' 'e' 'l' 'l' 'o's.insertChar(0, 'H');s.insertChar(1, 'e');s.insertChar(2, 'l');s.insertChar(3, 'l');s.insertChar(4, 'o');// 输出当前字符串cout << "String: " << s.toString() << endl;// 删除字符串中位置为4的字符s.deleteChar(4);// 输出删除字符后的字符串cout << "After deletion: " << s.toString() << endl;// 定义要查找的子字符串const char *sub = "ll";// 查找子字符串在当前字符串中的位置int pos = s.findSubstring(sub);if (pos != -1) {// 若找到,输出子字符串的起始位置cout << "Substring found at position: " << pos << endl;} else {// 若未找到,输出未找到的提示信息cout << "Substring not found." << endl;}// 定义要替换的旧子字符串和新子字符串const char *oldSub = "ll";const char *newSub = "mm";// 替换字符串中的旧子字符串为新子字符串s.replaceSubstring(oldSub, newSub);// 输出替换后的字符串cout << "After replacement: " << s.toString() << endl;// 程序正常结束,返回0return 0;
}

Java实现

```java
// 定义一个名为StringEditor的类,用于实现字符串的编辑功能
public class StringEditor {// 定义一个私有的内部类Node,它代表链表中的一个节点private class Node {// 节点中存储的字符数据char data;// 指向下一个节点的引用,用于构建链表结构Node next;}// 链表的头节点,作为链表操作的起始点private Node head;// 记录当前链表所表示字符串的长度private int length;// 类的构造函数,用于初始化StringEditor对象public StringEditor() {// 初始化头节点为null,表示链表为空head = null;// 初始化字符串长度为0length = 0;}// 该方法用于在指定位置插入一个字符public void insertChar(int pos, char c) {// 检查插入位置是否合法,位置需在0到length之间(包含0和length)if (pos >= 0 && pos <= length) {// 创建一个新的节点来存储要插入的字符Node newNode = new Node();// 将字符c赋值给新节点的数据域newNode.data = c;// 如果插入位置为0,即要在链表头部插入if (pos == 0) {// 让新节点的下一个节点指向原来的头节点newNode.next = head;// 更新头节点为新节点head = newNode;} else {// 定义一个当前节点,初始化为头节点,用于遍历链表Node current = head;// 循环找到插入位置的前一个节点for (int i = 0; i < pos - 1; i++) {// 移动到下一个节点current = current.next;}// 让新节点的下一个节点指向当前节点的下一个节点newNode.next = current.next;// 让当前节点的下一个节点指向新节点current.next = newNode;}// 插入成功后,字符串长度加1length++;}}// 该方法用于删除指定位置的字符public void deleteChar(int pos) {// 检查删除位置是否合法,位置需在0到length - 1之间if (pos >= 0 && pos < length) {// 如果删除位置为0,即要删除头节点if (pos == 0) {// 直接将头节点更新为原来头节点的下一个节点head = head.next;} else {// 定义一个当前节点,初始化为头节点,用于遍历链表Node current = head;// 循环找到删除位置的前一个节点for (int i = 0; i < pos - 1; i++) {// 移动到下一个节点current = current.next;}// 跳过要删除的节点,让当前节点的下一个节点指向要删除节点的下一个节点current.next = current.next.next;}// 删除成功后,字符串长度减1length--;}}// 该方法用于查找指定子字符串在链表表示的字符串中首次出现的位置public int findSubstring(String sub) {// 定义一个当前节点,初始化为头节点,用于遍历链表Node current = head;// 创建一个StringBuilder对象,用于将链表中的字符拼接成字符串StringBuilder sb = new StringBuilder();// 遍历链表,将每个节点的字符添加到StringBuilder中while (current != null) {// 添加当前节点的字符sb.append(current.data);// 移动到下一个节点current = current.next;}// 将StringBuilder转换为字符串,并调用indexOf方法查找子字符串的位置return sb.toString().indexOf(sub);}// 该方法用于将链表中指定的旧子字符串替换为新子字符串public void replaceSubstring(String oldSub, String newSub) {// 调用findSubstring方法查找旧子字符串的位置int pos = findSubstring(oldSub);// 如果找到了旧子字符串if (pos != -1) {// 调用deleteSubstring方法删除旧子字符串deleteSubstring(pos, oldSub.length());// 从新子字符串的末尾开始,依次插入每个字符for (int i = newSub.length() - 1; i >= 0; i--) {// 在旧子字符串原来的位置插入新子字符串的字符insertChar(pos, newSub.charAt(i));}}}// 该方法用于删除指定位置开始的指定长度的子字符串,是一个私有方法private void deleteSubstring(int pos, int len) {// 循环len次,每次删除指定位置的字符for (int i = 0; i < len; i++) {// 调用deleteChar方法删除指定位置的字符deleteChar(pos);}}// 重写toString方法,用于将链表表示的字符串转换为普通的字符串对象public String toString() {// 定义一个当前节点,初始化为头节点,用于遍历链表Node current = head;// 创建一个StringBuilder对象,用于将链表中的字符拼接成字符串StringBuilder sb = new StringBuilder();// 遍历链表,将每个节点的字符添加到StringBuilder中while (current != null) {// 添加当前节点的字符sb.append(current.data);// 移动到下一个节点current = current.next;}// 将StringBuilder转换为字符串并返回return sb.toString();}// 主方法,程序的入口点public static void main(String[] args) {// 创建一个StringEditor对象StringEditor editor = new StringEditor();// 在位置0插入字符'H'editor.insertChar(0, 'H');// 在位置1插入字符'e'editor.insertChar(1, 'e');// 在位置2插入字符'l'editor.insertChar(2, 'l');// 在位置3插入字符'l'editor.insertChar(3, 'l');// 在位置4插入字符'o'editor.insertChar(4, 'o');// 输出当前链表表示的字符串System.out.println("String: " + editor.toString());// 删除位置4的字符editor.deleteChar(4);// 输出删除字符后的字符串System.out.println("After deletion: " + editor.toString());// 定义要查找的子字符串String sub = "ll";// 调用findSubstring方法查找子字符串的位置int pos = editor.findSubstring(sub);// 如果找到了子字符串if (pos != -1) {// 输出子字符串的位置System.out.println("Substring found at position: " + pos);} else {// 输出未找到子字符串的信息System.out.println("Substring not found.");}// 定义要替换的旧子字符串String oldSub = "ll";// 定义要替换的新子字符串String newSub = "mm";// 调用replaceSubstring方法进行替换editor.replaceSubstring(oldSub, newSub);// 输出替换后的字符串System.out.println("After replacement: " + editor.toString());}
}
```

Python实现

# 定义一个字符串操作类,模拟基础字符串编辑器功能
class String:def __init__(self):# 初始化字符数据容器(Python列表实现)self.data = []# 记录当前字符串长度,避免频繁计算len()self.length = 0# 字符插入方法def insert_char(self, pos, c):# 有效性校验:插入位置需在[0,当前长度]区间if 0 <= pos <= self.length:# 使用列表的insert方法实现O(n)时间复杂度的插入self.data.insert(pos, c)# 维护长度变量,避免调用len()带来的性能损耗self.length += 1# 字符删除方法  def delete_char(self, pos):# 有效性校验:删除位置需在[0,长度)区间if 0 <= pos < self.length:# 使用del语句实现指定位置元素删除del self.data[pos]# 同步更新长度计数器self.length -= 1# 子字符串查找方法def find_substring(self, sub):# 将字符列表转换为字符串(时间复杂度O(n))# 调用字符串原生find方法实现子串搜索(Boyer-Moore算法)return ''.join(self.data).find(sub)# 子字符串替换方法def replace_substring(self, old_sub, new_sub):# 先查找旧子串的起始位置pos = self.find_substring(old_sub)if pos != -1:# 删除旧子串(需处理连续删除时的位置偏移)self.delete_substring(pos, len(old_sub))# 反向插入新子串:保证插入顺序不影响位置计算# 例如插入"mm"时,先插入'm'再插入'm',保持正确顺序for i in reversed(new_sub):self.insert_char(pos, i)# 子字符串删除辅助方法def delete_substring(self, pos, length):# 执行指定次数的单字符删除# 由于每次删除后后续元素位置会自动前移,因此固定pos即可for _ in range(length):self.delete_char(pos)# 重写字符串表示方法def __str__(self):# 高效拼接字符列表为字符串(时间复杂度O(n))return ''.join(self.data)# 主测试函数
def main():s = String()# 构建初始字符串(演示连续插入)s.insert_char(0, 'H')  # 创建基础字符串s.insert_char(1, 'e')  # 尾部追加s.insert_char(2, 'l')  # 逐步构建s.insert_char(3, 'l')  # 连续插入s.insert_char(4, 'o')  # 完成"Hello"构造print("String:", s)  # 预期输出:Hello# 删除末尾字符演示s.delete_char(4)       # 删除索引4(原第5个字符'o')print("After deletion:", s)  # 预期输出:Hell# 子字符串查找测试sub = "ll"pos = s.find_substring(sub)if pos != -1:print(f"Substring '{sub}' found at position: {pos}")  # 预期找到位置2else:print(f"Substring '{sub}' not found.")# 子字符串替换演示old_sub = "ll"new_sub = "mm"s.replace_substring(old_sub, new_sub)  # 将"ll"替换为"mm"print("After replacement:", s)  # 预期输出:Hmmif __name__ == "__main__":main()

四、总结核心知识点

4.1 核心知识点梳理

  • 串的基本概念:包括串的定义、子串与主串、空串与空格串、串相等等。

  • 串的存储实现:定长顺序串、堆串和快链串的存储结构及基本操作实现。

  • 串的应用:通过实现简单的行编辑器,展示了串在实际问题中的应用。

4.2 时间性能分析

操作定长顺序串堆串块链串
插入字符O(n)O(n)O(1)
删除字符O(n)O(n)O(1)
查找子串O(n)O(n)O(n)
替换子串O(n)O(n)O(n)

4.3 空间性能分析

存储方式空间复杂度适用场景
定长顺序串O(1)长度固定
堆串O(n)长度不固定
块链串O(n)频繁插入和删除

4.4 综合性能分析

存储方式时间性能空间性能适用场景
定长顺序串插入、删除操作时间复杂度较高,为O(n),其中n为串长;查找、连接等操作时间复杂度较低,为O(1)或O(m),其中m为操作涉及的子串长度需要预先分配固定大小的存储空间,空间利用率可能较低适用于串长较短且操作较为简单的场景
堆串插入、删除、连接等操作时间复杂度为O(n),其中n为串长;查找操作时间复杂度较低,为O(1)或O(m)动态分配存储空间,空间利用率较高适用于串长较长且操作较为复杂的场景
快链串插入、删除操作时间复杂度为O(1),查找操作时间复杂度为O(n),其中n为串长

4.5应用场景

存储方式适用场景
定长顺序串文本编辑器、固定长度字符串存储
堆串动态文本处理、模式匹配
快链串频繁插入和删除的文本编辑器

五、总结

    本文详细讲解了串的基本概念、存储实现、应用举例以及性能分析。通过多种编程语言的代码实现,帮助读者更好地理解和实践串的使用。串作为一种基础数据结构,在文本处理和模式匹配等领域有着广泛的应用,掌握其核心知识点对于解决实际问题具有重要意义。

相关文章:

  • 手机上的PDF精简版:随时随地享受阅读
  • 机器学习常用算法总结
  • 【第三章】17-常用模块5-ngx_http_gzip_module
  • 抗量子算法验证工具
  • 2025企业增长新引擎:AI Agent驱动人效跃迁|白皮书2.0发布
  • 物联网智慧教室项目(完整版)
  • 人工智能中的卷积神经网络(CNN)综述
  • JavaScript 调试
  • 内网Windows挂载目录到公网服务器
  • 深度学习(第1章——神经网络原理和Pytorch入门)
  • 【经验分享】基于Calcite+MyBatis实现多数据库SQL自动适配:从原理到生产实践
  • JLINK安装以及使用教程
  • 【AI News | 20250415】每日AI进展
  • uniapp+vue3全选、全不选 模板
  • ArrayList的subList的数据仍是集合
  • 微电网与分布式能源:智能配电技术的场景化落地
  • 面试期间大频率出现的问题
  • App测试小工具
  • 机器学习中的距离度量与优化方法:从曼哈顿距离到梯度下降
  • Linux下使用MTK的SP_Flash_tool刷机工具
  • 民营经济促进法出台,自今年5月20日起施行
  • 辽宁省委书记、省长连夜赶赴辽阳市白塔区火灾事故现场,指导善后处置工作
  • 4月人文社科联合书单|天文学家的椅子
  • 法治日报调查直播间“杀熟”乱象:熟客越买越贵,举证难维权不易
  • 四川省社科联期刊:不建议在读硕士、博士将导师挂名为第一作者
  • 四川落马厅官周海琦受审,1000多人接受警示教育