数据结构--Chapter4(串与数组)

4 串与数组

4.1 串

    字符串(串),是由n(>=0)个字符组成的优先序列。从逻辑结构来看,串也是一种特殊的线性表,即串可以看成是每个数据元素仅有一个字符组成的线性表。长度n为0的串称为空串,即空串不包含任何字符。包含一个及以上空白字符串的串称为空白串。需要说明的是,空串和空白串的区别。空串不包含任何字符,长度为0;空白串是由一个或多个字符所组成的字符串,其长度是空白字符的个数。

4.1.1 串的抽象数据类型描述

package adt;

public interface IString {
	/**
	 * 将一个已经存在的串置为空串
	 */
	public void clear();

	/**
	 * 判断当前串是否为空。
	 */
	public boolean isEmpty();

	/**
	 * 返回串中的字符个数
	 */
	public int length();

	/**
	 * 读取并返回串中的第index个字符值。其中,0<=index<=length()-1。
	 */
	public char charAt(int index);

	/**
	 * 返回值为当前串中从序号begin开始,到序号end-1为止的子串。其中,0<=begin<=length()-1,1<=end<=length()
	 * 。
	 */
	public IString substring(int begin, int end);

	/**
	 * 在当前串的第offset个字符之前插入串str。其中,0<=offset<=length()。
	 */
	public IString insert(int offset, IString str);

	/**
	 * 删除当前串中从序号begin开始到序号end-1为止的子串。其中0<=begin<=length()-1;1<=end<=length()。
	 */
	public IString delete(int begin, int end);

	/**
	 * 把str串连接到当前串的后面
	 */
	public IString concat(IString str);

	/**
	 * 将当前串与目标串str进行比较,若当前串大于str,则返回一个正整数; 若当前串等于str,则返回0;若当前串小于str,则返回一个负整数
	 */
	public int compareTo(IString str);

	/**
	 * 在当前串中从begin位置开始搜索与str相等的子串,所搜索成功,则返回str在当前串中的位置;否则返回-1。
	 */
	public int indexOf(IString str, int begin);
}


4.1.2 顺序串类的定义

    串的顺序存储结构与线性表的顺序存储结构类似,可以采用一组地址连续的存储单元来存储串字符序列。

package sequeue;

import adt.IString;

public class SeqString implements IString {
	private char[] strvalue;// 字符数组,存放串值
	private int curlen;// 当前串的长度

	// 构造方法1,构造一个空串
	public SeqString() {
		strvalue = new char[0];
		curlen = 0;
	}

	// 构造方法2,以字符串常量构造字符串对象
	public SeqString(String str) {
		char[] tempchararray = str.toCharArray();
		strvalue = tempchararray;
		curlen = tempchararray.length;
	}

	// 构造方法3,以字符数组构造串对象
	public SeqString(char[] value) {
		strvalue = new char[value.length];
		for (int i = 0; i < value.length; i++) {// 复制数组
			strvalue[i] = value[i];
		}
		curlen = value.length;
	}

	@Override
	public void clear() {
		this.curlen = 0;
	}

	@Override
	public boolean isEmpty() {
		return curlen == 0;
	}

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

	@Override
	public char charAt(int index) {
		if ((index < 0) || (index >= curlen)) {
			throw new StringIndexOutOfBoundsException(index);
		}
		return strvalue[index];
	}

	// 扩充字符串存储空间容量,参数指定容量
	public void allocate(int newCapacity) {
		char[] temp = strvalue;
		strvalue = new char[newCapacity];// 复制数组
		for (int i = 0; i < curlen; i++) {
			strvalue[i] = temp[i];
		}
	}

	@Override
	// 返回串中序号从begin至end-1的子串
	public IString substring(int begin, int end) {
		return null;
	}

	@Override
	// 在当前串的第offset个字符之前插入串str
	public IString insert(int offset, IString str) {
		return null;
	}

	@Override
	// 删除当前串中从序号begin开始到序号end-1为止的子串
	public IString delete(int begin, int end) {
		return null;
	}

	@Override
	// 添加指定串str到当前串尾
	public IString concat(IString str) {
		return null;
	}

	@Override
	// 将当前串与目标串str进行比较
	public int compareTo(IString str) {
		return 0;
	}

	@Override
	// 子串定位
	public int indexOf(IString str, int begin) {
		return 0;
	}

}


4.1.3 串的基本操作实现

1. 求子串操作

    求子串操作的功能是,返回当前串中序号从begin至end-1的子串。begin的范围是0<=begin<=length()-1;end的范围是1<=end<=length()。思路:

1)检查begin和end参数的合法性

2)若要截取整个串,则返回原串;否则截取从begin至end-1之间的子串

	// 返回串中序号从begin至end-1的子串
	public IString substring(int begin, int end) {
		if (begin < 0) {
			throw new StringIndexOutOfBoundsException("起始位置不能小于0");
		}
		if (end > curlen) {
			throw new StringIndexOutOfBoundsException("结束位置不能大于串的当前长度");
		}
		if (begin > end) {
			throw new StringIndexOutOfBoundsException("开始位置不能大于结束位置");
		}
		if (begin == 0 && end == curlen) {
			return this;
		} else {
			char[] buffer = new char[end - begin];
			for (int i = 0; i < buffer.length; i++) {
				buffer[i] = this.strvalue[i + begin];
			}
			return new SeqString(buffer);
		}

	}


2.  串的插入操作

    串的插入操作是指,在当前串中第offset个字符之前插入串str,并返回结果串对象。其中,参数offset的有效范围是0<=offset<=length()。思路:

1)检查插入位置的合法范围。

2)若插入时存储空间不足,则调用allocate(newCount),重新分配存储空间。

3)将strvalue中从offset开始的字符向后移动len个位置(len为待插入串str的长度)。

4)将str串插入到strvalue中从offset开始的位置。

5)改变串的长度

	public IString insert(int offset, IString str) {
		if ((offset < 0) || (offset > curlen)) {
			throw new StringIndexOutOfBoundsException("插入位置不合法");
		}
		int len = str.length();
		int newCount = curlen + len;
		if (newCount > strvalue.length) {
			allocate(newCount);// 插入存储空间不足,需扩充容量
		}
		for (int i = curlen - 1; i >= offset; i++) {
			strvalue[len + i] = strvalue[i];// 从offset开始向后移动len个字符
		}
		for (int i = 0; i < len; i++) {
			strvalue[offset + i] = str.charAt(i);// 复制串str
		}
		this.curlen = newCount;//改变串长度
		return this;
	}


3. 串的删除操作

    串的删除操作是指在当前串中删除从start到end-1之间的子串,并返回当前串对象。参数start和end的取值范围分别是0<=begin<=length()-1和1<=end<=length()。思路:

1)检查参数的合法性

2)将strvalue中从end开始到尾串的子串向前移动到从begin开始的位置。

3)当前串长度减去end-begin。

	public IString delete(int begin, int end) {
		if (begin < 0) {
			throw new StringIndexOutOfBoundsException("起始位置不能小于0");
		}
		if (end > curlen) {
			throw new StringIndexOutOfBoundsException("结束位置不能大于串的当前长度");
		}
		if (begin > end) {
			throw new StringIndexOutOfBoundsException("开始位置不能大于结束位置");
		}
		for (int i = 0; i < end - begin; i++) {
			strvalue[begin + i] = strvalue[end + i];// 从end开始至串尾的子串向前移动到从begin开始的位置
		}
		curlen = curlen - (end - begin);// 当前串的长度将去(end-begin)
		return this;
	}


4. 串的比较操作

    串的比较操作是将当前串与参数str指定的串进行比较,若当前串的值大于str的串的值,则返回一个正整数;  若当前串的值等于str的串值,则返回0;若当前串的值小于str的串值,则返回一个负整数。思路:

1)求出当前串与待比较串的长度,并把较小值赋值到n

2)从下标0到n-1依次取出两个串中对应的字符进行比较,若不等,则返回  第一个不相等的字符的数值差

3)若下标从0到n-1对应的字符均相等,则返回两个串长度的差

	public int compareTo(SeqString str) {
		int len1 = this.curlen;
		int len2 = str.length();// 求出当前串与待比较串的长度
		int n = Math.min(len1, len2);// 把较小值赋值到n

		char[] s1 = this.strvalue;
		char[] s2 = str.strvalue;
		int k = 0;
		while (k < n) {
			char ch1 = s1[k];
			char ch2 = s2[k];
			if (ch1 != ch2) {
				return ch1 - ch2; // 返回第一个不相等字符的数值差
			}
			k++;
		}
		return len1 - len2;// 返回两个串长度的差
	}


5. 串的模式匹配操作

    串的查找定位操作(也称为串的模式匹配操作)是指在当前串(主串)中寻找子串(模式串)的过程。若在主串中找到了一个和模式串相同的子串,则查找成功;若在主串中找不到与模式串相同的子串,则查找失败。当模式匹配成功时,返回模式串的首字符在主串中的为序号;当匹配失败时,返回-1。

    两种主要的模式匹配算法是Brute-Force算法和KMP算法。

1)Brute-Force模式匹配算法

    Brute-Force算法是一种简单、直观的模式匹配算法。其实现方法是:设s为主串,t为模式串,i为主串当前比较字符的下标,j为模式串当前比较的下标。令i的初值为start,j的初值为0。从主串的第start个字符(i=start)起和模式串的第一个字符(j=0)比较,若相等,则继续比较后续字段(i++,j++);否则从主串的第二个字符起重新开始和模式串比较(i返回到原位置加1,j返回到0),依次类推,知道模式串中的每一个字符依次和主串s的一个连续的字符序列相等,则称匹配成功,返回模式串t的第一个字符在主串s中的位置;否则称匹配失败,返回-1。

	public int indexOf(IString t, int start) {
		if (this != null && t != null && t.length() > 0
				&& this.length() >= t.length()) {
			int slen = this.length();
			int tlen = t.length();
			int i = start;
			int j = 0;//j为模式串当前字符的下标
			while (i < slen && j < tlen) {
				if (this.charAt(i) == t.charAt(j)) {
					i++;
					j++;//继续比较后续字符
				} else {
					i = j - i + 1;//主串下标返回原位置加1
					j = 0;//模式串下标返回到0
				}
			}
			if (j >= t.length()) {
				return i - tlen;// 匹配成功,返回子串序号
			} else {
				return -1;
			}
		}
		return -1;
	}


2)KMP算法

4.2 数组

    数组是n(n>=1)个具有相同类型的数据元素a0,a1,... an-1构成的有限序列,并且这些数据元素占用一片地址连续的内存单元。其中,n称为数组的长度。

    一维数组可以看成是一个顺序存储结构的线性表。数组元素是一维数组的数组称为二维数组,数组元素是二维数组的数组称为三维数组,以此类推。二维数组和三维数组都属于多维数组。实际上,多维数组实际上时是用一维数组实现的。

     

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值