c++ 字母a~z升序排列编号 字典序问题 递归
互相学习,仅供参考,欢迎指正
**
字典序问题
**
问题描述:
***在数据加密和数据压缩中常需要对特殊的字符串进行编码。给定的字母表A由26个小写英文字母组成A={a,b,…,z}。该字母表产生的升序字符串是指字符串中字母按照从左到右出现的次序与字母在字母表中出现的次序相同,且每个字符最多出现1次。例如,a,b,ab,bc,xyz等字符串都是升序字符串。现在对字母表A产生的所有长度不超过6的升序字符串按照字典序排列并编码如下。
1 2 … 26 27 28 …
a b … z ab ac …
对于任意长度不超过6的升序字符串,迅速计算出它在上述字典中的编码。***
下面按照实验步骤解答
实验报告
问题分析:字典序问题,已知排序规则是位数少的排前面、相同位数按字母表序排列
所以要求出某个升序字符串的位置,一种思路是把该字符串前面的数目相加算法设计:(1)使用递归求出以第i位字母开头共有k位的字符串有多少
(2)求出给出字符串所占位数m,把位数少于m的所有字符串相加
(3)加上位数相同但首字符较小的
(4)加上字符串中字母与其后面字母之间之间字母开头的m-i长度字符串的数量
3.算法实现:
f函数为2.(1)的实现
Order为(2)(3)(4)的实现
Judge判断是否为a~z升序字符串
5.运行结果图:
算法分析:算法逻辑并不难,把字符串之前的相加就行,需要知道哪些情况需要加上,以及通过递归实现
经验归纳:一步步分析,想法上不一定多么巧妙,难的是需要用代码来实现,以及递归的逻辑
#include <string>#include <iostream>#include <fstream>#include <sstream>using namespace std;int f(int i, int k) {int j;int sum = 0;if (k == 1) {return 1;}else {for (j = i + 1; j <= 26; j++) {sum += f(j, k - 1);}}return sum;}//第i个字母开头长度为k的数量 int order(string str){int sum = 1;//自己占一位//1.加上位数少于字符串的数量int i, j, len, h;len = str.length();for (i = 1; i < len; i++){for (j = 1; j <= 26; j++){sum += f(j, i);}}h = str[0] - 'a' + 1;//h为首位字符的位数//2.加上位数相同但首字符较小的for (i = 1; i < h; i++){sum += f(i, len);}//3.再加上字符串中首字母相同长度相同排在前面的字符串的数量int count = h;for (i = 1; i < len; i++) {h = str[i] - 'a' + 1;len = len - i;for (j = count + 1; j < h; j++) {sum += f(j, len);}count = h;} return sum;}//判断是否为a~z升序字符串bool judge(string str){int n = str.length(),i=0;for(i=0;i<n-1;i++){//如果后面不比前面大则报错if (str[i] - str[i+1]>0){return false;}if (str[i]<'a' || str[i]>'z'){return false;}}if (str[i]<'a' || str[i]>'z'){return false;}return true;}int main(){ifstream infile("input.txt");ofstream outfile("output.txt");string s;stringstream ss;//通过字符流把字符串转换为数字int k;//表示有k个升序字符串if (!infile.is_open()){cout << "未成功打开文件"<<endl;}getline(infile,s);//读取一行,第一行即为数字kss << s;ss >> k;while (getline(infile, s)){//读取字符串,判断编号if (judge(s)){cout << order(s) << endl;outfile << order(s) << endl;}else{cout << "字符串不是a~z升序" << endl;outfile << "字符串不是a~z升序"<<endl;}}infile.close();outfile.close();return 0;}