zoukankan      html  css  js  c++  java
  • 串:串的基本定义及简单应用魔王语言

    串,于我的理解就是字符串
    一般认为有三种存储方式:定长顺序串,堆串,块链串(个人认为比较鸡肋)。定长顺序串类似于普通字符串,同数组的大小一样最长长度固定。堆串存储在堆中,空间大小可重新分配。块链串类似于定长顺序串的链表。
    定长顺序串与堆串应用较多,定长顺序串的一些操作存在截断问题

    ADT String{
      数据对象:串与字符串长度及当前串的最大长度
      结构关系:串中的字符间存在线性关系
      基本运算
      initString(S)  //初始化一个空串
      StringCat(S,T)  //将串T连接至串S末尾
      StringIndexOf(S,T)  //返回串S中第一次出现串T的位置
      StringLastIndexOf(S,T)  //返回串S中最后一次出现串T的位置
      StringInsert(S,pos,T)  //在串S的pos位置插入串T
      StringReplace(S,from,to)  //将串S中的第一个from子串替换为to
      StringReplaceAll(S,from,to)  //将串S中的所有子串from替换为to
      StringReserve(S)  //将串S翻转
      SubString(S,begin,end,T)  //从串S中begin至end取子串T
    }ADT String


    串的一些基本概念

    • 空串    S ="",串中没有字符,strlen(S) = 0
    • 空格串   "  ",串中的字符全为空格
    • 子串    串的一部分,设串T,串S,StringIndexOf(S,T)结果不为-1,则T为主串S的子串
    • 前缀    对于"abcde",“a”,“ab”,“abc”,“abcd”,“abcde”都是前缀
    • 后缀    对于"abcde",“e”,“de”,“cde”,“bcde”,“abcde”都是后缀
    • 前缀子串  从主串左侧第一个字符开始的所有子串
    • 后缀子串  在主串右侧最后一个字符结束的所有子串
    • 串相等   串长相同,串中每一个位置的字符相同
    • 模式匹配  在主串中寻找子串首次出现位置的运算
    • 真前/后缀(子串)  与主串不相等

    堆串的一些基本运算的实现

    typedef struct{
    	char *str;
    	int maxlen;
    }String;
    
    void initString(String *s) {
    	s->str = (char *)malloc(sizeof(char)*STR);
    	s->maxlen = 100;
    }
    
    int StringIndexOf(String *s, char sub[]) {//返回子串开始的下标,无则返回-1
    	char *str = s->str;
    	int i, j;
    	for (i = 0; i < strlen(str); i++) {
    		j = 0;
    		for (j = 0; j < strlen(sub); j++) {
    			if (str[i + j] != sub[j])
    				break;
    		}
    		if (j == strlen(sub)) {
    			return i;
    		}
    	}
    	return -1;
    }
    
    int StringIndexOf(String *s, char c) {
    	char *str = s->str;
    	for (int i = 0; i < strlen(str); i++) {
    		if (str[i] == c)
    			return i;
    	}
    	return -1;
    }
    
    int StringLastIndexOf(String *s, char c) {
    	char *str = s->str;
    	for (int i = strlen(str) - 1; i >=0; i--) {
    		if (str[i] == c)
    			return i;
    	}
    	return -1;
    }
    
    void StringCat(String *s , char sub[]) {
    	char *str = s->str;
    	char *re = NULL;
    	int len = strlen(str) + strlen(sub);
    	if ( len <= s->maxlen) {
    		strcat(str,sub);
    	}
    	else {
    		re = (char *)malloc(sizeof(char)*len + 25);
    		strcpy(re, str);
    		strcat(re, sub);
    		free(str);
    		s->str = re;
    		s->maxlen = len + 24;
    	}
    }
    
    void StringReplace(String *s, char sub[], char obj[]) {//
    	int pos = StringIndexOf(s, sub);
    	if (pos == -1)
    		return;
    	char *str = s->str;
    	int subLen = strlen(sub), objLen = strlen(obj);
    	char tem[125], *re = NULL;
    	strcpy(tem, &str[pos + subLen]);
    	int len = strlen(str) - subLen + objLen;
    	if (len <= s->maxlen) {
    		strcpy(str + pos, obj);
    		strcpy(&str[strlen(str)], tem);
    	}
    	else {
    		re = (char *)malloc(sizeof(char)*len + 25);
    		strncpy(re, str, pos);
    		strcpy(&re[pos],obj);
    		strcpy(&re[pos+objLen], tem);
    		free(str);
    		s->str = re;
    		s->maxlen = len + 24;
    	}
    }
    
    void StringReplace(String *s, int pos, int subLen, char obj[]) {//
    	char *str = s->str;
    	int objLen = strlen(obj);
    	char tem[125], *re = NULL;
    	strcpy(tem, &str[pos + subLen]);
    	int len = strlen(str) - subLen + objLen;
    	if (len <= s->maxlen) {
    		strcpy(str + pos, obj);
    		strcpy(&str[strlen(str)], tem);
    	}
    	else {
    		re = (char *)malloc(sizeof(char)*len + 25);
    		strncpy(re, str, pos);
    		strcpy(&re[pos], obj);
    		strcpy(&re[pos + objLen], tem);
    		free(str);
    		s->str = re;
    		s->maxlen = len + 24;
    	}
    }
    
    void StringReplaceAll(String *s, char sub[], char obj[]) {
    	int pos;
    	int subLen = strlen(sub);
    	while ((pos = StringIndexOf(s, sub)) != -1) {
    		StringReplace(s, pos, subLen, obj);
    	}
    }
    
    void StringInsert(String *s , int pos, char in[]) {//从指定位置开始插入字符串
    	char *str = s->str;
    	char *re = NULL;
    	char tem[125];
    	strcpy(tem, &str[pos]);
    	int requirement = strlen(s->str) + strlen(in);
    	if ( requirement <= s->maxlen) {//空间足够
    		strcpy(&str[pos], in);
    		strcpy(&str[strlen(str)], tem);
    	}
    	else {
    		re = (char *)malloc(sizeof(char)*(requirement + 25));
    		strncpy(re, str, pos);
    		strcpy(&(re[pos]), in);
    		strcpy(&re[strlen(re)], tem);
    		free(str);
    		s->str = re;
    		s->maxlen = requirement + 24;
    	}
    }
    
    char *SubString(String *s, int begin, int end, char *des) {
    	strncpy(des, &(s->str)[begin], end - begin + 1);
    	des[end - begin + 1] = 0;
    	return des;
    }
    
    char *StringReverse(char *str) {
    	int i, len = strlen(str);
    	char c;
    	for (i = 0; i < len / 2; i++) {
    		c = str[i];
    		str[i] = str[len - i - 1];
    		str[len - i - 1] = c;
    	}
    	return str;
    }
    

    魔王语言解释器基于串的实现

    两条规则
    (1)α->β1β2…βn
    (2)(θδ1δ2…δn)->θδnθδn-1…θδ1θ

    总觉得跟语法解释器有一点点相似
    但是想不到方法去自定义与上述两条规则这种层次的规则

    只实现了基于规则(1)的自定义规则,任意字符串可替换为任意字符串
    带括号的按规则(2)去解释 可嵌套括号

    解释括号的算法

    void EliminateBracket(String *s, int left, int right) {//left、right 左右括号的位置
    	if (right <= left)
    		return;
    	char *str = s->str;
    	char sub[NUM];
    	SubString(s, left+2, right-1, sub);
    	char re = str[left + 1];
    	StringReverse(sub);
    	char resub[NUM*2+1];
    	int i, j;
    	for (i = 0, j = 0; i < strlen(sub); i++) {
    		resub[j++] = re;
    		resub[j++] = sub[i];
    	}
    	resub[j++] = re;
    	resub[j] = 0;
    	StringReplace(s, left, right-left+1, resub);//int pos, int subLen  这个方法的第三个参数为被替换串的串长
    	left = StringLastIndexOf(s, '('), right = StringIndexOf(s, ')');
    	EliminateBracket(s, left, right);//递归消除括号
    }
    

    总体实现

    //全局变量
    int amount = 0;//规则条数
    char source[NUM][LEN], object[NUM][LEN];//字符串数组,相同下标的两个source串和object串分别表示一条规则中的被替换串与用来替换的串
    
    void check_rule() {//打印规则
    	system("cls");
    	printf("		高等规则
    ");
    	printf("	α   →   β1β2…βm
    ");
    	printf("	(θδ1δ2…δn)   →   θδnθδn-1… θδ1θ
    
    ");
    	printf("		当前规则
    ");
    	int i = 0;
    	while (i < amount) {
    		printf("	%d、	%s   →   %s
    ", i + 1, source[i], object[i]);
    		i++;
    	}
    }
    
    int import_rule() {//从文件中读入规则
    	int i = 0, j = 0;
    	FILE *fp = fopen("TheLanguageOftheKingOftheDevil.rule", "r");
    	if (fp == NULL) { printf("文件丢失!
    "); return 0; }
    	while (fscanf(fp,"%s   →   %s", source[i++], object[j++]) != EOF);
    	if (i != j) {
    		printf("文件损坏!");
    	}
    	fclose(fp);
    	return i-1;
    }
    
    void write_rule() {//将规则写入文件
    	int i;
    	FILE *fp = fopen("TheLanguageOftheKingOftheDevil.rule", "w");
    	for (i = 0; i < amount; i++) {
    		fprintf(fp, "%s   →   %s
    ", source[i], object[i]);
    	}
    	fclose(fp);
    }
    
    void use_rule(String *s) {//使用规则
    	int i;
    	for (i = 0; i < amount;i++) {
    		StringReplaceAll(s, source[i], object[i]);
    	}
    	EliminateBracket(s, StringLastIndexOf(s, '('), StringIndexOf(s, ')'));
    }
    
    void add_rule() {
    	char from[NUM], to[NUM];
    	printf("请输入要转换的魔王词汇:");
    	scanf("%s", from);
    	printf("请输入该词汇对应的内容:");
    	scanf("%s", to);
    	if (confirm()) {
    		strcpy(source[amount], from);
    		strcpy(object[amount++], to);
    		//保存到文件
    		write_rule();
    	}
    	else {//取消
    		printf("本次修改已取消");
    	}
    }
    
    void sort_rule() {
    	printf("现在一共有%d条规则,如下所示:
    ", amount);
    	int i = 0, j;
    	while (i < amount) {
    		printf("	%d、	%s   →   %s
    ", i + 1, source[i], object[i]);
    		i++;
    	}
    	printf("输入%d个数表示当前规则的新序号,新序号-1则表示删除该条规则
    ,保留的规则序号按先后顺序从小到大
    请输入:",amount);
    	int order[NUM], cnt = 0;
    	char Tsource[NUM][LEN], Tobject[NUM][LEN];
    	for (i = 0; i < amount; i++) {
    		scanf("%d", &order[i]);
    		if (order[i] != -1)
    			cnt++;
    		strcpy(Tsource[i], source[i]);
    		strcpy(Tobject[i], object[i]);
    	}
    	for (i = 1; i < cnt; i++) {//根据order排序
    		for (j = 0; j < amount; j++) {
    			if (order[j] == i)
    			break;
    		}
    		strcpy(source[i - 1], Tsource[j]);
    		strcpy(object[i - 1], Tobject[j]);
    	}
    	amount = cnt;
    	write_rule();
    	printf("修改已完成
    ");
    }
    
    void go_on() {
    	printf("按任意键继续");
    	getch();
    	//getch();VS下可能需要两个getch()
    }
    
    int confirm() {
    	char choice[25] , flag = 1;
    	printf("是否确认本次操作?(0/1):");
    	do {
    		if (flag == 0) {
    			printf("请输入0或1表示选择
    ");
    		}
    		scanf("%s", choice);
    	} while (choice[0] != '0' && choice[0] != '1');
    	return choice[0] - '0';
    }
    
    int main() {
    	//return 0;
    	char choice[20];
    	amount = import_rule();
    	String ss;
    	String *s = &ss;
    	initString(s);
    	while (1) {
    		menu();
    		scanf("%s", choice);
    		switch (choice[0]){
    		case '1':check_rule(); break;
    		case '2':add_rule(); break;
    		case '3':sort_rule(); break;
    		case '4':printf("请输入待解释字符串:"); scanf("%s", s->str); use_rule(s); printf("结果为:%s
    ",s->str); break;
    		case '0':exit(0); break;
    		default:
    			printf("输入有误,请重新选择
    ");
    			break;
    		}
    		go_on();
    	}
    	return 0;
    }
    

    2018/10/13

  • 相关阅读:
    UVA
    UVA
    模板——扩展欧几里得算法(求ax+by=gcd的解)
    UVA
    模板——2.2 素数筛选和合数分解
    模板——素数筛选
    Educational Codeforces Round 46 (Rated for Div. 2)
    Educational Codeforces Round 46 (Rated for Div. 2) E. We Need More Bosses
    Educational Codeforces Round 46 (Rated for Div. 2) D. Yet Another Problem On a Subsequence
    Educational Codeforces Round 46 (Rated for Div. 2) C. Covered Points Count
  • 原文地址:https://www.cnblogs.com/kafm/p/12721841.html
Copyright © 2011-2022 走看看