串
背景
今天复习串这种数据结构。在这里,我们使用顺序结构数组来实现串,因为链式存储指针域4个字节,而存一个字符1个字节,这样会造成内存空间的浪费。
基本理论
- 首先介绍一些基本概念:
- 串:串是由0个或多个字符组成的有限序列,又名字符串,记为S=‘ a 0 a 1 a 2 . . . a n a_0a_1a_2...a_n a0a1a2...an’
- 串的长度:串中包含字符的个数即该串的长度。
- 空串:长度为0的串
- 子串与主串:串中任意连续字符组成的有限序列称为该串的子串,而该串称为主串
- 子串在主串中的位置:子串在主串第一次出现时,子串的第一个字符在主串中的位置 称为子串在主串中的位置。
- 串相等:串长度相同且对应字符相同
- 接下里介绍串的基本操作
串和线性表的逻辑结构很相似,只不过串中的元素均为字符。此外,串和线性表的基本操作也有差异,线性表的基本操作是针对于单个元素的,而串的基本操作是针对于子串(多个元素)。
串的基本操作如图:
代码实现
- 首先定义串的基本操作(接口):
/// <summary>
/// 串 接口
/// </summary>
public interface IString
{
int Length { get; } // 获取字符个数
char this[int index] { get; set; } // 获取或设置对应索引处的字符
IString Insert(int index, IString s); // 在指定位置处插入串
IString Remove(int startIndex, int count); // 在指定位置移除指定长度的子串
IString SubString(int startIndex, int count); // 获取指定位置、指定长度的子串
IString Concat(IString s); // 串连接
IString Clone(); // 串克隆
int FindParam(IString s); // 查找子串(串匹配)
}
- 顺序结构数组实现串
/// <summary>
/// 顺序结构(数组)实现串
/// </summary>
public class SeqString : IString
{
private readonly char[] _CStr; //存储字符串
/// <summary>
/// 获取字符个数
/// </summary>
public int Length
{
get
{
int i = 0;
while (_CStr[i] != '\0')
i++;
return i;
}
}
/// <summary>
/// 设置或获取对应索引处的字符
/// </summary>
/// <param name="index"></param>
/// <returns></returns>
public char this[int index]
{
get
{
if (index < 0 || index > Length - 1)
throw new IndexOutOfRangeException();
return _CStr[index];
}
set
{
if (index < 0 || index > Length - 1)
throw new IndexOutOfRangeException();
_CStr[index] = value;
}
}
public SeqString()
{
_CStr = new char[] { '\0' };
}
public SeqString(string s)
{
if (s == null)
throw new ArgumentNullException();
int length = s.Length;
_CStr = new char[length + 1];
for (int i = 0; i < length; i++)
_CStr[i] = s[i];
_CStr[length] = '\0';
}
public SeqString(int length)
{
if (length <= 0)
throw new ArgumentOutOfRangeException();
_CStr = new char[length + 1];
_CStr[length] = '\0';
}
/// <summary>
/// 插入子串
/// </summary>
/// <param name="startIndex"></param>
/// <param name="s"></param>
/// <returns></returns>
public IString Insert(int startIndex, IString s)
{
if (s == null)
throw new Exception("所插入的串为空");
if (startIndex < 0 || startIndex > Length)
throw new IndexOutOfRangeException();
SeqString temp = new SeqString(Length + s.Length);
for (int i = 0; i < startIndex; i++)
{
temp._CStr[i] = _CStr[i];
}
for(int i = 0; i < s.Length; i++)
{
temp._CStr[startIndex + i] = s[i];
}
for(int i = startIndex; i < Length; i++)
{
temp._CStr[s.Length + i] = _CStr[i];
}
return temp;
}
/// <summary>
/// 删除子串
/// </summary>
/// <param name="startIndex"></param>
/// <param name="count"></param>
/// <returns></returns>
public IString Remove(int startIndex, int count)
{
if (startIndex < 0 || startIndex > Length - 1)
throw new IndexOutOfRangeException();
if (count < 0)
throw new ArgumentOutOfRangeException();
int left = Length - startIndex; // 最多移除字符个数
count = (left < count) ? left : count; // 实际移除字符个数
SeqString temp = new SeqString(Length - count);
for (int i = 0; i < startIndex; i++)
{
temp._CStr[i] = _CStr[i];
}
for (int i = startIndex; i < Length - count; i++)
{
temp._CStr[i] = _CStr[i + count];
}
return temp;
}
/// <summary>
/// 获取子串
/// </summary>
/// <param name="startIndex"></param>
/// <param name="count"></param>
/// <returns></returns>
public IString SubString(int startIndex, int count)
{
if (startIndex < 0 || startIndex > Length - 1)
throw new IndexOutOfRangeException();
if (count < 0)
throw new ArgumentOutOfRangeException();
int left = Length - startIndex; // 可取子串的最大长度
count = (left < count) ? left : count; // 实际子串字符个数
SeqString temp = new SeqString(count);
for (int i = 0; i < count; i++)
{
temp._CStr[i] = _CStr[i + startIndex];
}
return temp;
}
/// <summary>
/// 两串连接
/// </summary>
/// <param name="s"></param>
/// <returns></returns>
public IString Concat(IString s)
{
if (s == null)
throw new ArgumentNullException();
return Insert(Length, s);
}
public static SeqString operator +(SeqString s1, SeqString s2)
{
if (s1 == null || s2 == null)
throw new ArgumentNullException();
return s1.Concat(s2) as SeqString;
}
/// <summary>
/// 克隆串
/// </summary>
public IString Clone()
{
SeqString temp = new SeqString(Length);
for (int i = 0; i < Length; i++)
{
temp._CStr[i] = _CStr[i];
}
return temp;
}
/// <summary>
/// 查找子串(暴力查找法)
/// </summary>
/// <param name="s"></param>
/// <returns></returns>
public int FindParam(IString s)
{
if (s == null)
throw new ArgumentNullException();
int i = 0;
int j = 0;
while (i < Length && j < s.Length)
{
if (_CStr[i] == s[j])
{
i++;
j++;
}
else
{
i = i - j + 1;
j = 0;
}
}
if (j == s.Length)
return i - j;
else
return -1;
}
public override string ToString()
{
string str = string.Empty;
for (int i = 0; i < Length; i++)
{
str += _CStr[i];
}
return str;
}
}
综上,我们介绍完了串这种顺序结构以及它的基本操作。