String类的实现与KMP算法简述

String的概念

  String:
    因为C++兼容C,所以我们的字符串类也要,不仅String可以使用,还要兼容Char*
    通过C语言中的函数实现String类,这样才可以实现兼容不同版本的C++编译器
    实现String类时,需要考虑字符串的const属性,函数参数是否为const

String类的功能

函数名功能
insert增 ,返回引用
remove删,返回引用
replace改,返回引用
重载[]像C语言一样访问字符串的内容(与List一致必须先有内容才可以访问或修改)
重载比较操作符进行字符串的比较
重载+、+=、-、-=字符串的便捷操作,返回引用
trim()消除前后两端空格,返回引用
bool startWith()以…开始
bool endOf()以…结束
int indexOf()子串位于当前字符串的下标(KMP算法)
String sub(int i,int len)从字符串中提取出子串

  Tip:返回为引用时可以继续修改或者操作,改变的就是原字符串的内容
    若不返回引用,返回的为临时变量,后续对临时变量的修改与原变量无关

String.h

#ifndef __String_H_
#define __String_H_

#include "Object.h"

namespace JYlib
{

/*
字符串类
功能:增、删、查、改
*/
class String : public Object
{
protected:
	char* m_str;
	int m_length;

	void init(const char* s);

	bool equal(const char* l,const char* r,int len)const;

	//kmp子串查找算法
	static int* make_pmt(const char* s);
	static int kmp(const char* s,const char* p);
public:
	String();

	String(char s);

	String(const char* s);

	String(const String& s);

	int length()const;

	const char* str()const;

	String& insert(int i,const char* s);
	String& insert(int i,const String& s);

	String& trim();//消除前后两端空格

	String sub(int i,int len)const;//提取子串

	//子串位于当前类的下标
	int indexOf(const char* s)const;
	int indexOf(const String& s)const;

	String& remove(int i,int len);
	String& remove(const char* s);
	String& remove(const String& s);

	//将字符串中的t替换为s
	String& replace (const char* t,const char* s);
	String& replace(const char* t,const String& s);
	String& replace(const String& t,const char* s);
	String& replace(const String& t,const String& s);

	char& operator[](int i);
	char operator[](int i)const;

	bool startWith(const char* s)const;
	bool startWith(const String& s)const;

	bool endOf(const char* s)const;
	bool endOf(const String& s)const;

	String& operator = (const char c);
	String& operator = (const char* s);
	String& operator = (const String& s);

	String operator + (const char* s)const;
	String operator + (const String& s)const;
	String& operator += (const char* s);
	String& operator += (const String& s);

	String operator - (const char* s)const;
	String operator - (const String& s)const;
	String& operator -= (const char* s);
	String& operator -= (const String& s);

	bool operator == (const char* s)const;
	bool operator == (const String& s)const;
	bool operator != (const char* s)const;
	bool operator != (const String& s)const;
	bool operator > (const char* s)const;
	bool operator > (const String& s)const;
	bool operator >= (const char* s)const;
	bool operator >= (const String& s)const;
	bool operator < (const char* s)const;
	bool operator < (const String& s)const;
	bool operator <= (const char* s)const;
	bool operator <= (const String& s)const;

	~String();
};


}



#endif


String.cpp

#include "String.h"
#include <cstring>
#include <cstdlib>
#include "Exception.h"


using namespace JYlib;


void String::init(const char* s)
{
	m_str = strdup(s);

	if(m_str != NULL)
	{
		m_length = strlen(m_str);
	}
	else
	{
		THROW_EXCEPTION(NoEnoughMemoryException,"No memory to creat String object ...");
	}
}

bool String::equal(const char* l,const char* r,int len)const
{
	for(int i=0;i<len;i++)
	{
		if(l[i]!=r[i])
		{
			return false;
		}
	}
	return true;
}

/*	KMP子串查找算法——生成PMT表	*/
int* String::make_pmt(const char* s)
{
	int len = strlen(s);

	int* ret = reinterpret_cast<int*>(malloc(len * sizeof(int)));

	if(ret)
	{
		int ll = 0;//前缀与后缀的最大重叠长度
		ret[0] = 0;

		for(int i=1;i<len;i++)
		{
			while((ll > 0)&&(s[ll] != s[i]))
			{
				ll = ret[ll -1];
			}
			if(s[ll] == s[i])
			{
				ll++;
			}

			ret[i] = ll;
		}
	}
	else
	{
		THROW_EXCEPTION(NoEnoughMemoryException,"No memory to creat pmt array");
	}

	return ret;
}

/*				KMP子串查找算法	
在目标串s中,查找子串p,生成PMT表需要耗费一定时间
适合用于目标串较子串很长,子串重复性低的场合
*/
int String::kmp(const char* s,const char* p)
{
	int ret = -1;
	int sl = strlen(s);
	int pl = strlen(p);

	int* pmt = make_pmt(p);

	if( (pmt != NULL)&&(0 < pl)&&(pl <= sl) )
	{
		for(int i=0,j=0;i<sl;i++)
		{
			while( (j > 0)&&(s[i] != p[j]) )
			{
				j = pmt[j-1];
			}
			if(s[i] == p[j])
			{
				j++;
			}
			if(j == pl)
			{
				ret = i + 1 - pl;
				break;
			}	
		}
	}
	free(pmt);

	return ret;
}

String::String()
{
	init("");
}

String::String(char c)
{
	char s[] = {c,'\0'};

	init(s);
}

String::String(const char* s)
{
	init(s ? s : "");
}

String::String(const String& s)
{
	init(s.m_str ? s.m_str : "");
}

int String::length()const
{
	return m_length;
}

const char* String::str()const
{
	return m_str;
}

String& String::insert(int i,const char* s)
{
	if((0 <= i)&&(i <= m_length))
	{
		if((s != NULL)&&(s[0] != '\0'))
		{
			int len = strlen(s);

			char* new_str = reinterpret_cast<char*>(malloc(m_length + len + 1));

			if(new_str)
			{
				strncpy(new_str,m_str,i);
				strncpy(new_str + i,s,len);
				strncpy(new_str + i + len,m_str + i,m_length - i);

				m_length += len;
				new_str[m_length] = '\0';

				free(m_str);
				m_str = new_str;
				return *this;
			}
			else
			{
				THROW_EXCEPTION(NoEnoughMemoryException,"No memory to insert String value ...");
			}
		}
	}
	else
	{
		THROW_EXCEPTION(IndexOutOfBoundsException,"Paramemter is invalid ...");
	}
}

String& String::insert(int i,const String& s)
{
	return insert(i,s.m_str);
}

String& String::trim()
{
	int b = 0;
	int e = m_length-1;

	while(m_str[b] == ' ') b++;
	while(m_str[e] == ' ') e--;

	if(b == 0)
	{
		m_str[e+1] = '\0';
		m_length = e + 1;
	}
	else
	{
		for(int i=0,j=b;j <= e;i++,j++)
		{
			m_str[i] = m_str[j];
		}

		m_length = e - b + 1;
		m_str[m_length] = '\0';
	}

	return *this;
}

String String::sub(int i,int len)const
{
	String ret;

	if((0 <= i)&&(i < m_length))
	{
		if(len < 0)	len = 0;
		if(len + i > m_length) len = m_length - i;	
		char* new_str = reinterpret_cast<char*>(malloc(len + 1));

		strncpy(new_str,m_str + i,len);

		new_str[len] = '\0';

		ret = new_str;
	}
	else
	{
		THROW_EXCEPTION(IndexOutOfBoundsException,"Paramemter is invalid ...");
	}
	return ret;
}

int String::indexOf(const char* s)const
{
	return kmp(m_str,s ? s : "");
}

int String::indexOf(const String& s)const
{
	return kmp(m_str,s.m_str);
}

String& String::remove(int i,int len)
{
	if( (0 <= i)&&(i < m_length) )
	{
		int n = i;
		int m = i + len;
		while((n < m)&&(m < m_length))
		{
			m_str[n] = m_str[m];
			n++;
			m++;
		}
		m_str[n] = '\0';
		m_length = n;
	}
	return *this;
}

String& String::remove(const char* s)
{
	return remove(indexOf(s),s ? strlen(s) : 0);
}

String& String::remove(const String& s)
{
	return remove(indexOf(s),s.m_length);
}

String& String::replace (const char* t,const char* s)
{
	int index = indexOf(t);
	if(index >= 0)
	{
		remove(t);
		insert(index,s);
	}
	
	return *this;
}

String& String::replace(const char* t,const String& s)
{
	return replace(t,s.m_str);
}

String& String::replace(const String& t,const char* s)
{
	return replace(t.m_str,s);
}

String& String::replace(const String& t,const String& s)
{
	return replace(t.m_str,s.m_str);
}

char& String::operator[](int i)
{
	if((0 <= i)&&(i < m_length))
	{
		return m_str[i];
	}
	else
	{
		THROW_EXCEPTION(IndexOutOfBoundsException,"Parameter i is invalid ...");
	}
}

char String::operator[](int i)const
{
	return const_cast<String&>(*this)[i];
}

bool String::startWith(const char* s)const
{
	bool ret = s != NULL;

	if(ret)
	{
		int len = strlen(s);

		ret = (len < m_length) && equal(m_str,s,len);
	}

	return ret;
}

bool String::startWith(const String& s)const
{
	return startWith(s.m_str);
}

bool String::endOf(const char* s)const
{
	bool ret = s != NULL;

	if(ret)
	{
		int len = strlen(s);
		char* str = m_str + m_length - len;

		ret = (len < m_length)&&equal(str,s,len);
	}

	return ret;
}

bool String::endOf(const String& s)const
{
	return endOf(s.m_str);
}

String& String::operator = (const char* s)
{
	if(m_str != s)
	{
		char* new_str = strdup(s ? s : "");
		if(new_str)
		{
			free(m_str);

			m_str = new_str;
			m_length = strlen(m_str);
		}
		else
		{
			THROW_EXCEPTION(NoEnoughMemoryException,"No memory to creat new element ...");
		}
	}
	return *this;
}

String& String::operator = (char c)
{
	char s[]={c,'\0'};

	return (*this = s);
}

String& String::operator = (const String& s)
{
	return (*this = s.m_str);
}

String String::operator + (const char* s)const
{
	String ret;
	int len = m_length + strlen(s ? s : ""); 

	char* new_str = reinterpret_cast<char*>(malloc(len+1));

	if(new_str)
	{
		strcpy(new_str,m_str);
		strcat(new_str,s ? s : "");

		free(ret.m_str);

		ret.m_str = new_str;
		ret.m_length = len;
	}
	else
	{
		THROW_EXCEPTION(NoEnoughMemoryException,"No memory to creat new element ...");
	}
	return ret;
}

String String::operator + (const String& s)const
{
	return (*this + s.m_str);
}

String& String::operator += (const char* s)
{
	return (*this = *this + s);
}

String& String::operator += (const String& s)
{
	return (*this = *this + s.m_str);
}

String String::operator - (const char* s)const
{
	return String(*this).remove(s);
}

String String::operator - (const String& s)const
{
	return String(*this).remove(s);
}

String& String::operator -= (const char* s)
{
	return remove(s);
}

String& String::operator -= (const String& s)
{
	return remove(s);
}


/*----------------比较操作符----------------*/
bool String::operator == (const char* s)const
{
	return (strcmp(m_str,s ? s : "") == 0);
}

bool String::operator == (const String& s)const
{
	return (strcmp(m_str,s.m_str) == 0);
}

bool String::operator != (const char* s)const
{
	return (strcmp(m_str,s ? s : "") != 0);
}

bool String::operator != (const String& s)const
{
	return (strcmp(m_str,s.m_str) != 0);
}

bool String::operator < (const char* s)const
{
	return (strcmp(m_str,s ? s : "") < 0);
}

bool String::operator < (const String& s)const
{
	return (strcmp(m_str,s.m_str) < 0);
}

bool String::operator <= (const char* s)const
{
	return (strcmp(m_str,s ? s : "") <= 0);
}

bool String::operator <= (const String& s)const
{
	return (strcmp(m_str,s.m_str) <= 0);
}

bool String::operator > (const char* s)const
{
	return (strcmp(m_str,s ? s : "") > 0);
}

bool String::operator > (const String& s)const
{
	return (strcmp(m_str,s.m_str) > 0);
}

bool String::operator >= (const char* s)const
{
	return (strcmp(m_str,s ? s : "") >= 0);
}

bool String::operator >= (const String& s)const
{
	return (strcmp(m_str,s.m_str) >= 0);
}
/*----------------比较操作符----------------*/


String::~String()
{
	free(m_str);
}


KMP算法原理

  从上图可以发现:
    匹配失败时,右移位数与子串本身相关,与目标串无关
    移动位数 = 已匹配的字符数 - 对应的部分匹配值
    任意子串都存在一个唯一的部分匹配表

  部分匹配表的相关概念:
    前缀:除了最后—个字符以外,一个字符串的全部头部组合
    后缀:除了第—个字符以外,—个字符串的全部尾部组合
    部分匹配值:前缀和后缀最长共有元素的长度

  以ABCDABD为例:

  实现关键:
    PMT[1] = 0 (下标为0的元素匹配值为0)
    从2个字符开始递推(从下标为1的字符开始递推)
    假设 PMT[n] = PMT[n-1] + 1 (最长共有元素的长度)
    当假设不成立,PMT[n]在PMT[n-1]的基础上减小

KMP.h

#ifndef __KMP_H_
#define __KMP_H_

#include <cstdlib>
#include <cstring>
#include "Exception.h"


namespace JYlib
{
/*
KMP子串查找算法——生成PMT表
*/
int* make_pmt(const char* s)
{
	int len = strlen(s);

	int* ret = reinterpret_cast<int*>(malloc(len * sizeof(int)));

	if(ret)
	{
		int ll = 0;//前缀与后缀的最大重叠长度
		ret[0] = 0;

		for(int i=1;i<len;i++)
		{
			while((ll > 0)&&(s[ll] != s[i]))
			{
				ll = ret[ll -1];
			}
			if(s[ll] == s[i])
			{
				ll++;
			}

			ret[i] = ll;
		}
	}
	else
	{
		THROW_EXCEPTION(NoEnoughMemoryException,"No memory to creat pmt array");
	}

	return ret;
}

/*
			KMP子串查找算法
在目标串s中,查找子串p,生成PMT表需要耗费一定时间
适合用于目标串较子串很长,子串重复性低的场合
*/
int kmp(const char* s,const char* p)
{
	int ret = -1;
	int sl = strlen(s);
	int pl = strlen(p);

	int* pmt = make_pmt(p);

	if( (pmt != NULL)&&(0 < pl)&&(pl <= sl) )
	{
		for(int i=0,j=0;i<sl;i++)
		{
			while( (j > 0)&&(s[i] != p[j]) )
			{
				j = pmt[j-1];
			}
			if(s[i] == p[j])
			{
				j++;
			}
			if(j == pl)
			{
				ret = i + 1 - pl;
				break;
			}	
		}
	}
	free(pmt);

	return ret;
}

}


#endif

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值