Loading

数据结构笔记6 串

在应用程序中使用最频繁的类型是字符串。字符串简称串,是一种特殊的线 性表,其特殊性在于串中的数据元素是一个个的字符。字符串在计算机的许多方面应用很广。如在汇编和高级语言的编译程序中,源程序和目标程序都是字符串 数据。在事务处理程序中,顾客的信息如姓名、地址等及货物的名称、产地和规 格等,都被作为字符串来处理。另外,字符串还具有自身的一些特性。因此,把字符串作为一种数据结构来研究。

 

串的基本概念 

     串(String)由n(n ≥0)字符组成的有限序列。一般记为:S=”c1c2 …cn ”(n≥0) 其中,S是串名,双引号作为串的定界符,用双引号引起来的字符序列是串 值。ci(1≤i≤n )可以是字母、数字或其它字符,n为串的长度,当n=0时,称为空串(Empty String)。  串中任意个连续的字符组成的子序列称为该串的子串(Substring)。包含子串的串相应地称为主串。子串的第一个字符在主串中的位置叫子串的位置。

由于串中的字符都是连续存储的,而在C#中串具有恒定不变的特性,即字 符串一经创建,就不能将其变长、变短或者改变其中任何的字符。所以,这里不 讨论串的链式存储,也不用接口来表示串的操作。

串的基本操作的实现

1、求串长
     求串的长度就是求串中字符的个数,可以通过求数组 data的长度来求串的长度。求串的长度的实现如下:

 public int GetLength()
{
return data.Length;
} 

2、串比较 
    如果两个串的长度相等并且对应位置的字符相同,则串相等,返回 0;如果串s对应位置的字符大于该串的字符或者如果串s的长度大于该串,而在该串的 长度返回内二者对应位置的字符相同,则返回-1,该串小于串s;其余情况返回 1,该串大于串s。  串比较的算法实现如下:

public int Compare(StringDS s)
{
int len=((this.GetLength()<=s.GetLength())? this.GetLength():s.GetLength());
int i = 0;
for (i = 0; i < len; ++i)
{
if (this[i] != s[i])
{
break;
}
}
if (i <= len)
{
if (this[i] < s[i])
{
return -1;
}
else if (this[i] > s[i])
{
return 1;
}
}
else if(this.GetLength()    s.GetLength())
{
return 0;
}
else if (this.GetLength() < s.GetLength())
{
return -1;
}
return 1;
} 

3、求子串 
    从主串的index位置起找长度为len的子串,若找到,返回该子串,否则,返回一个空串。 算法实现如下:

        public StringDS SubString(int index, int len)
{
if ((index<0) || (index>this.GetLength()-1)
|| (len<0) || (len>this.GetLength()-index))
{
Console.WriteLine("Position or Length is error!");
return null;
}
StringDS s = new StringDS(len);
for (int i = 0; i < len; ++i)
{
s[i] = this[i + index-1];
}
return s;
}

4、串连接 
    将一个串和另外一个串连接成一个串,其结果返回一个新串,新串的长度是两个串的长度之和,新串的前部分是原串,长度为该串的长度,新串的后部分是串s,长度为串s的长度。 串连接的算法实现如下:

           public StringDS Concat(StringDS s)
{
StringDS s1 = new StringDS(this.GetLength()
+ s.GetLength());
for(int i = 0; i < this.GetLength(); ++i)
{
s1.data[i] = this[i];
}
for(int j = 0; j < s.GetLength(); ++j)
{
s1.data[this.GetLength() + j] = s[j];
}
return s1;
}  

5、串插入 
     串插入是在一个串的位置index处插入一个串s。如果位置符合条件,则该操作返回一个新串,新串的长度是该串的长度与串s的长度之和,新串的第1部分是 该串的开始字符到第index之间的字符,第2部分是串s,第3部分是该串从index 位置字符到该串的结束位置处的字符。如果位置不符合条件,则返回一个空串。  串插入的算法如下:

public StringDS Insert(int index, StringDS s)
{
int len = s.GetLength();
int len2 = len + this.GetLength();
StringDS s1 = new StringDS(len2);
if (index < 0 || index > this.GetLength() - 1)
{
Console.WriteLine("Position is error!");
return null;
}
for (int i = 0; i < index; ++i)
{
s1[i] = this[i];
}
for(int i = index; i < index + len ; ++i)
{
s1[i] = s[i - index];
}
for (int i = index + len; i < len2; ++i)
{
s1[i] = this[i - len];
}
return s1;
}  

6、串删除 
     串删除是从把串的第index位置起连续的len个字符的子串从主串中删除掉。 如果位置和长度符合条件,则该操作返回一个新串,新串的长度是原串的长度减 去len,新串的前部分是原串的开始到第index个位置之间的字符,后部分是原串 从第index+len位置到原串结束的字符。如果位置和长度不符合条件,则返回一 个空串。  串删除的算法实现如下:

      public StringDS Delete(int index, int len)
{
if ((index<0) || (index>this.GetLength()-1)
|| (len<0) || (len>this.GetLength()-index))
{
Console.WriteLine("Position or Length is error!");
return null;
}
StringDS s = new StringDS(this.GetLength() - len);
for (int i = 0; i < index; ++i)
{
s[i] = this[i];
}
for (int i = index + len; i < this.GetLength(); ++i)
{
s[i] = this[i];
}
return s;
}  

7、串定位 
   查找子串s在主串中首次出现的位置。如果找到,返回子串s在主串中首次出现的位置,否则,返回-1。  串定位的算法实现如下:

public int Index(StringDS s)
{
if (this.GetLength() < s.GetLength())
{
Console.WriteLine("There is not string s!");
return -1;
}
int i = 0;
int len = this.GetLength() - s.GetLength();
while (i < len)
{
if (Compare(s)    0)
{
break;
}
}
if (i <= len)
{
return i;
}
return -1;
}

 

在C#中,一个String 表示一个恒定不变的字符序列集合。String 类型是封闭类型,所以,它不能被其它类继承,而它直接继承自 object。因此,String 是引用类型,不是值类型,在托管堆上而不是在线程的堆栈上分配空间。String 类型还继承了 IComparable 、ICloneable 、IConvertible 、IComparable<string> 、IEnumerable<char>、IEnumerable 和IEquatable<string>等接口。String 的恒定性指的是一个串一旦被创建,就不能将其变长、变短或者改变其中任何的字符。所以,当我们对一个串进行操作时,不能改变字符串,C#也 提供了 StringBuilder 类型来支持高效地动态创建字符串。
   在C#中,创建串不能用new 操作符,而是使用一种称为字符串驻留的机制。这是因为 C#语言将 String 看作是基元类型。基元类型是被编译器直接支持的类型,可以在源代码中用文本常量(Literal)来直接表达字符串。当C#编译器对源代码进行编译时,将文本常量字符串存放在托管模块的元数据中。而当 CLR 初始 化时,CLR创建一个空的散列表,其中的键是字符串,值为指向托管堆中字符 串对象的引用。散列表就是哈希表。当 JIT 编译器编译方法时,它会在散列表中查找每一个文本常量字符串。如果找不到,就会在托管堆中构造一个新的 String 对象(指向字符串),然后将该字符串和指 向该字符串对象的引用添加到散列表中;如果找到了,不会执行任何操作。

posted @ 2009-07-14 12:30  Dhoopu  阅读(330)  评论(0编辑  收藏  举报