您的位置:首页 > 其它

关于字符串的几个算法

2017-08-01 01:07 369 查看
这里着重谈及字符串的 子串内容,而非子序列。

一、关于字符串的分割

//
//字符串分割
//
#pragma once
#ifndef Programming_Experience_StringSegmentation_H
#define Programming_Experience_StringSegmentation_H

#include <cstdio>
#include <cstring>

void	StringSegmented(char str[], char delim[]) {

//	函数原型 char* strtok(char* s,const char* delim)
//	当s串不为空时,分割起点为该串首地址;当s串为空串 NULL 时,切割起点为上次 分割符 标记了的下一个索引位置
//  函数只是把分割符依次全都置换成 回车符'\n'
int i = 1;
for (char* sub = strtok(str, delim); sub != NULL; sub = strtok(NULL, delim)) {
printf("subS%d = \"%s\"\n",i++, sub);
}
putchar('\n');
}

//验证原理
void	StringSegmentedⅡ(char str[], char delim[]) {

int len = strlen(str);
typedef char*	charIP;
charIP	startIP = str, endIP = str+len;
//注意对 endIP 的定义, 用户若是规定其为数组的最后一位元素的索引,则初始化为 str+len-1 或者写成 &str[len-1]
//常见的规定是:作为数组的最后一位元素的下一个位置,则初始化为 str+len 或 &str[len]。(如 迭代器)

for (int i = 0; i < len; ++i) {
printf("str[%d] %p %c\t", i, &str[i], str[i]);
}
putchar('\n');
putchar('\n');
int i = 1;
for (char* sub = strtok(str, delim); sub != NULL; sub = strtok(NULL, delim)) {
printf("str = %s\tsub = %s\n", str, sub);	//原始母串s会被修改,且有且仅有一次修改,变为最前的第一个字串
}
putchar('\n');
putchar('\n');
for (charIP ip = startIP; ip != endIP; ++ip) {
if(NULL==*ip) printf("%p %s\t", ip,"\\n");
else printf("%p %c\t",ip,*ip);
}
putchar('\n');

putchar('\n');
}

#endif // !Programming_Experience_StringSegmentation_H


二、生成某一具体字符串的所有 子串,注意互异性避免出现重复子串

//
//生成字符串的所有子串,实现子串查找算法
//
#pragma once
#ifndef Programming_Experience_GenerateSubsequences_H
#define Programming_Experience_GenerateSubsequences_H

#include <iostream>
#include <string>
#include <cstring>
#include <vector>
using namespace std;

//检查 当前子串 是否已存在,避免重复
bool	IsNoRepetition(string& str, vector<string>& vs) {

for (int i = 0; i < vs.size(); ++i) {
if (vs[i] == str)
return false;	//有重
}
return true;	//无重
}

// char型字符串的所有子串
void	GenerateSubstring(const char str[], vector<string>& vs) {

int len = strlen(str);
for (int i = 1; i <= len; ++i) {	// i 表示子串的元素个数,不考虑空串则必须从1开始!
for (int j = 0; j + i <= len; ++j) {	//	j为索引起点
//	两种构造办法
//	string	temp(&str[j], i);
string	temp(str, j, i);
if( IsNoRepetition(temp,vs) )
vs.push_back( temp );
}
}
cout << "SIZE = " << vs.size() << endl;
for (int i = 0; i < vs.size(); ++i) {
if (i != vs.size() - 1 )
cout << vs[i] << " ";
else
cout << vs[i] << endl;
}
}

// string型字符串的所有子串
void	GenerateSubstring(const string& str, vector<string>& vs) {

int len = str.size();
for (int i = 1; i <= len; ++i) {	// i 子串元素个数
for (int j = 0; j + i <= len; ++j) {	//	j 索引起点
string	temp(&str[j], i);
//	string	temp(str, j, i);
if (IsNoRepetition(temp, vs))
vs.push_back(temp);
// 说明,若是母串没有重复的字符,则可以借助匿名变量实现一步到位,如	vs.push_back( string( str, j, i));
}
}
cout << "SIZE = " << vs.size() << endl;
for (int i = 0; i < vs.size(); ++i) {
if (i != vs.size() - 1)
cout << vs[i] << " ";
else
cout << vs[i] << endl;
}
}

// 备注说明:若只是输出 字符串(char型、string均可)的所有字串,而不需要存储,
//可以直接输出,不过要避免字串重复。

#endif // !Programming_Experience_GenerateSubsequences_H


三、排列组合

//
//字符串的排列组合 及 全排序
//
#pragma once
#ifndef Programming_Experience_PermutationsAndSorting_H
#define Programming_Experience_PermutationsAndSorting_H

#include <iostream>
#include <algorithm>
#include <string>
using namespace std;

//默认为 自升序到降序 的排列组合
//注意使用库函数里的 next_permutation 或 prev_permutation 的前提是 必须先对待处理的数据进行 排序操作,然后再做其他操作。
template <typename T>
void	PermutationUpwards(T a[], int n) {	// int,double,float,char 型数组

sort(a, a + n);

int c = 0;
do {
c++;

for (int i = 0; i < n; ++i) {
cout << a[i] << " ";
}
cout << endl;
} while ( next_permutation(a, a + n));

cout << c << " Times" << endl;
}
//	next_permutation 函数会默认向下生成所有的排列,不过为了避免遗漏就需要先输出原始的数据(它也是一分排列)
//	故使用do…while循环,这样代码更简练些。另外记得初始化计数变量count。

//设计 从降序到升序 的排列组合

template<typename T>
bool	cmp(T& a, T& b) {
return	a > b;
}

template <typename T>
void	PermutationDownwards(T a[], int n) {	// int,double,float,char 型数组

sort(a, a + n, cmp<T> );

int c = 0;
do {
c++;

for (int i = 0; i < n; ++i) {
cout << a[i] << " ";
}
cout << endl;
} while ( prev_permutation(a, a + n));

cout << c << " Times" << endl;
}
//	prev_permutation 函数会默认向上生成所有的排列

// 重载 自升序到降序 的排列组合
void	PermutationUpwards(string& str ) {	// string 型字符串

sort( str.begin(),str.end() );	// 也可写成 sort(str.begin(),str.begin() + str.size() );
int c = 0;
do {
c++;
cout << str << endl;
} while ( next_permutation( str.begin(), str.end() ) );

cout << c << " Times" << endl;
}

// 重载 从降序到升序 的排列组合
void	PermutationDownwards(string& str) {

sort(str.begin(), str.end(),cmp<char>);
int c = 0;
do {
c++;
cout << str << endl;
} while (prev_permutation(str.begin(), str.end()) );

cout << c << " Times" << endl;
}

// 需要的话,还可以再设计一个模板函数,实现对 vector<T> 的排列组合(即多个数组或字符串的整体之间的排列组合)

#endif // !Programming_Experience_PermutationsAndSorting_H


测试的main函数如下:

//关于子序列的一些算法,查找、排列组合、排序…
//Created by Ant on 27/07/2017
//
#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
#include <vector>
#include <algorithm>
#include "GenerateSubsequences.h"
#include "PermutationsAndSorting.h"
#include "StringSegmentation.h"
using namespace std;

int main() {

// 字符串分割
const int N = 30;
char str[] = "Hi,this is a simple test.";
char strⅡ
;
strcpy(strⅡ, str);
cout << str << endl;
char* delim = ", .";
StringSegmented(str, delim );
StringSegmentedⅡ(strⅡ, delim);

// 生成所有字串
char* s1 = "ABC123D";
string s2 = "AB12B12";
vector<string> vs;
GenerateSubstring(s1, vs);
vs.clear();
GenerateSubstring(s2, vs);
vs.clear();

// 排列组合
const int n = 3;
int a
= { 1,3,2 };
int a1
= { 3,1,2 };

PermutationUpwards(a, n);
cout << endl;
PermutationDownwards(a1, n);
cout << endl;

string temp = "Ab2a";
string temp1 = "Ab2a";

PermutationUpwards(temp);
cout << endl;
PermutationDownwards(temp1);
cout << endl;

return 0;
}


运行结果:

(由于太长,需分两张来弄)





喂丸待续……

4000
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息