• 串:串的基本定义及简单应用魔王语言


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

    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

  • 相关阅读:
    POJ 3368.Frequent values
    HDOJ 1166.敌兵布阵
    javaWeb之文件下载
    javaWeb之文件上传
    centos系统下忘记了root密码怎么办?
    如何在centos下挂载与卸载磁盘
    验证码生成(java版本)
    javaweb怎么过滤乱码
    mysql修改默认字段大小
    我所知道的命名方式(软件)
  • 原文地址:https://www.cnblogs.com/kafm/p/12721841.html
Copyright © 2020-2023  润新知