串的算法设计题

(1)写一个算法统计在输入字符串中各个不同字符出现的频度并将结果存入文件(字符串中的合法字符为A-Z这26个字母和0-9这10个数字)。

[题目分析] 由于字母共26个,加上数字符号10个共36个,所以设一长36的整型数组,前10个分量存放数字字符出现的次数,余下存放字母出现的次数。从字符串中读出数字字符时,字符的ASCII代码值减去数字字符 ‘0’的ASCII代码值,得出其数值(0…9),字母的ASCII代码值减去字符‘A’的ASCII代码值加上10,存入其数组的对应下标分量中。遇其它符号不作处理,直至输入字符串结束。

[算法描述]

void Count()//统计输入字符串中数字字符和字母字符的个数。
{
	int num[36];
	char ch;
	for (int i = 0; i < 36; i++)
		num[i] = 0;// 初始化
	while ((ch = getchar()) != '#')
	{
		if ('0' <= ch <= '9')  //数字字符
		{
			int i = ch - 48;
			num[i]++;
		}
		else if ('A' <= ch <= 'Z')  //字母字符
		{
			int i = ch - 'A' + 10;
			num[i]++;
		}
	}
	for (int i = 0; i < 10; i++)
	{
		cout << "数字" << i << "的个数=" << num[i] << endl;
	}
	for (int i = 10; i < 36; i++)
	{
		cout << "字母字符" << i + 55 << "的个数=" << num[i] << endl;
	}
}
#include<iostream>
#include<fstream>
using namespace std;

void Count()//统计输入字符串中数字字符和字母字符的个数。
{ 
	int num[36];
	char ch;
	for(int i=0;i < 36;i++)
		num[i]=0;// 初始化
	while ((ch = getchar()) != '#')
	{
		if ('0' <= ch <= '9')  //数字字符
		{
			int i = ch - 48;
			num[i]++;
		}
		else if ('A' <= ch <= 'Z')  //字母字符
		{
			int i = ch - 'A' + 10;
			num[i]++;
		}
	}
	//写入文件
	ofstream file("myfile.txt");
	if (file.is_open())
	{
		for (int i = 0; i < 10; i++)
		{
			file << "数字" << i << "的个数=" << num[i] << endl;
		}
		for (int i = 10; i < 36; i++)
		{
			file << "字母字符" << i + 55 << "的个数=" << num[i] << endl;
		}
		file.close();
	}
	for (int i = 0; i < 10; i++)
	{
		cout << "数字" << i << "的个数=" << num[i] << endl;
	}
	for (int i = 10; i < 36; i++)
	{
		cout << "字母字符" << i + 55 << "的个数=" << num[i] << endl;
	}
}

int main()
{
	Count();
	system("pause");
	return 0;
}

(2)写一个递归算法来实现字符串逆序存储,要求不另设串存储空间。

[题目分析]实现字符串的逆置并不难,但本题“要求不另设串存储空间”来实现字符串逆序存储,即第一个输入的字符最后存储,最后输入的字符先存储,使用递归可容易做到。

int InvertStore(char A[])
//字符串逆序存储的递归算法。
{
	char ch;
	static int i = 0;//需要使用静态变量
	cin >> ch;
	if (ch != '.')    //规定'.'是字符串输入结束标志
	{
		InvertStore(A);
		A[i++] = ch;//字符串逆序存储
	}
	A[i] = '\0';  //字符串结尾标记

	return i;
}
#include<iostream>
using namespace std;

int InvertStore(char A[])
//字符串逆序存储的递归算法。
{
	char ch;
	static int i = 0;//需要使用静态变量
	cin >> ch;
	if (ch != '.')    //规定'.'是字符串输入结束标志
	{
		InvertStore(A);
		A[i++] = ch;//字符串逆序存储
	}
	A[i] = '\0';  //字符串结尾标记

	return i;
}

void display(char A[],int i)
{
	for (int k = 0; k < i; k++)
	{
		cout << A[k] << " " ;
	}
	cout << endl;
}

int main()
{
	char A[100];
	int i = InvertStore(A);
	display(A, i);
	system("pause");
	return 0;
}


(3)设二维数组a[1…m, 1…n] 含有m*n 个整数。
① 写一个算法判断a中所有元素是否互不相同?输出相关信息(yes/no);
② 试分析算法的时间复杂度。
[题目分析] 判断二维数组中元素是否互不相同,只有逐个比较,找到一对相等的元素,就可结论为不是互不相同。如何达到每个元素同其它元素比较一次且只一次?在当前行,每个元素要同本行后面的元素比较一次(下面第一个循环控制变量p的for循环),然后同第i+1行及以后各行元素比较一次,这就是循环控制变量k和p的二层for循环。

#include<iostream>
using namespace std;


int JudgeEqual(int *a[], int m, int n)//判断二维数组中所有元素是否互不相同,如是,返回1;否则,返回0。
{
	//分成两个部分,与同行的元素进行比较,与下一行的元素进行比较。
	for (int i = 0; i < m; i++)
	{
		for (int j = 0; j < n - 1; j++)
		{
			for (int p = j + 1; p < n; p++)//和同行其它元素比较
			{
				if (a[i][j] == a[i][p])
				{
					cout << "no";
					return 0;
				}
			}
			//只要有一个相同的,就结论不是互不相同
			for (int k = i + 1; k < m; k++)//和第i+1行及以后元素比较
			{
				for (int p = 0; p < n; p++)
				{
					if (a[i][j] == a[k][p])
					{
						cout << "no";
						return 0;
					}
				}
			}
		}
	}
	cout << "yes";
	return 1;
}
int main()
{
	int m=0, n=0;
	cout << "请输入二维数组的大小:" << endl;
	cin >> m;
	cin >> n;
	//动态二维数组怎么弄来着??
	int **arr = new int*[m];
	for (int i = 0; i < m; i++)
		arr[i] = new int[n];

	cout << "请输入二维数组的值:" << endl;
	for (int i = 0; i < m; i++)
	{
		for (int j = 0; j < n; j++)
		{
			cin >> arr[i][j];
		}
	}

	JudgeEqual(arr, m, n);

	system("pause");
	return 0;
}

二维数组中的每一个元素同其它元素都比较一次,数组中共mn个元素,第1个元素同其它mn-1个元素比较,第2个元素同其它mn-2 个元素比较,……,第mn-1个元素同最后一个元素(mn)比较一次,所以在元素互不相等时总的比较次数为 (mn-1)+(mn-2)+…+2+1=(mn)(mn-1)/2。在有相同元素时,可能第一次比较就相同,也可能最后一次比较时相同,设在(mn-1)个位置上均可能相同,这时的平均比较次数约为(mn)(mn-1)/4,总的时间复杂度是O(n4)。


(4)设任意n个整数存放于数组A(1:n)中,试编写算法,将所有正数排在所有负数前面(要求算法复杂度为0(n))。
[题目分析] 本题属于排序问题,只是排出正负,不排出大小。可在数组首尾设两个指针i和j,i自小至大搜索到负数停止,j自大至小搜索到正数停止。然后i和j所指数据交换,继续以上过程,直到 i=j为止。

#include<iostream>
using namespace std;

void Arrange(int A[], int n)
//n个整数存于数组A中,本算法将数组中所有正数排在所有负数的前面
{
	int i = 0, j = n - 1, x;  //用类C编写,数组下标从0开始
	while (i < j)
	{
		while (i < j && A[i]<0)  i++;
		while (i < j && A[j] > 0)  j--;
		if (i < j&&A[i]>0&&A[j]<0) { x = A[i]; A[i++] = A[j]; A[j--] = x; }//交换A[i] 与A[j]
	}// while(i<j)
}//算法Arrange结束.

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

int main()
{
	int a[5] = { 1,2,3,-1,-2 };
	cout << "原数组:" << endl;
	display(a, 5);

	Arrange(a, 5);
	cout << "现数组:" << endl;
	display(a, 5);
	system("pause");
	return 0;
}

对数组中元素各比较一次,比较次数为n。最佳情况(已排好,正数在前,负数在后)不发生交换,最差情况(负数均在正数前面)发生n/2次交换。用类c编写,数组界偶是0…n-1。空间复杂度为O(1).


(5)已知字符串S1中存放一段英文,写出算法format(s1,s2,s3,n),将其按给定的长度n格式化成两端对齐的字符串S2, 其多余的字符送S3。
[题目分析] 本题要求字符串s1拆分成字符串s2和字符串s3,要求字符串s2“按给定长度n格式化成两端对齐的字符串”,即长度为n且首尾字符不得为空格字符。算法从左到右扫描字符串s1,找到第一个非空格字符,计数到n,第n个拷入字符串s2的字符不得为空格,然后将余下字符复制到字符串s3中。

void format(char *s1, char *s2, char *s3,int n)//将字符串s1拆分成字符串s2和字符串s3,要求字符串s2是长n且两端对齐
{
	char *p = s1, *q = s2;
	int i = 0;
	while (*p != '\0' && *p == ' ') p++;//滤掉s1左端空格
	if (*p == '\0') 
	{ 
		cout << "字符串s1为空串或空格串" << endl; 
	    exit(0); 
	}
	while (*p != '\0' && i < n) 
	{ 
		*q = *p; 
		q++; 
		p++; 
		i++; 
	}//字符串s1向字符串s2中复制

	if (*p == '\0') { cout << "字符串s1没有" << n << "个有效字符" << endl; exit(0); }
	if (*(--q) == ' ') //若最后一个字符为空格,则需向后找到第一个非空格字符
	{
		p--;          //p指针也后退
		while (*p == ' '&&*p != '\0') p++;//往后查找一个非空格字符作串s2的尾字符
		if (*p == '\0')
		{
			cout << "s1串没有" << n << "个两端对齐的字符串" << endl; exit(0);
		}
		*q = *p;         //字符串s2最后一个非空字符
		*(++q) = '\0';   //置s2字符串结束标记
	}
	q = s3; 
	p++;      //将s1串其余部分送字符串s3。
	while (*p != '\0') { *q = *p; q++; p++; }
	*q = '\0';        //置串s3结束标记
}

(6)编写算法,实现下面函数的功能。函数void insert(chars,chart,int pos)将字符串t插入到字符串s中,插入位置为pos。假设分配给字符串s的空间足够让字符串t插入。(说明:不得使用任何库函数)
[题目分析] 本题是字符串的插入问题,要求在字符串s的pos位置,插入字符串t。首先应查找字符串s的pos位置,将第pos个字符到字符串s尾的子串向后移动字符串t的长度,然后将字符串t复制到字符串s的第pos位置后。
对插入位置pos要验证其合法性,小于1或大于串s的长度均为非法,因题目假设给字符串s的空间足够大,故对插入不必判溢出。

void insert(char *s, char *t, int pos)
{
	int a = 0;
	int i = 1, x = 0;
	char *p = s, *q = t;//p,q分别为字符串s和t的工作指针
	if (pos < 1)
	{
		cout << "pos参数位置非法" << endl;
		exit(0);
	}
	while (*p != '\0'&&i < pos)
	{
		pos++;
		i++;
	}//查pos位置
	 //若pos小于串s长度,则查到pos位置时,i=pos。
	if (*p == '\0')
	{
		cout << pos << "位置大于字符串s的长度" << endl;
		exit(0);
	}
	else//查找字符串的尾
	{
		while (*q != '\0')
		{
			p++;
			i++;
		}//查到尾时,i为字符‘\0’的下标,p也指向‘\0’。
	}
	a = i;
	while (*q != '\0') { q++; x++; }   //查找字符串t的长度x,循环结束时q指向'\0'。
	m = a + x;
	for (int j = i; j >= pos; j--) 
	{ 
		*(p + x) = *p; 
		p--; 
	}//串s的pos后的子串右移,空出串t的位置。
	q--;  //指针q回退到串t的最后一个字符
	for (int j = 1; j <= x; j++) *p-- = *q--;  //将t串插入到s的pos位置上
}

[算法讨论] 串s的结束标记(’\0’)也后移了,而串t的结尾标记不应插入到s中。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值