• 求职_第1篇 程序设计基础及数据机构基础_第2章 字符串


    256+

    2.1字符串与子串、子序列

    例1:字符串“www.qq.com”所有非空子串个数为(如果两个子串相同则算一个)。

    长度为1的子串有10个,减去重复的2(子串w重复)+1(子串q重复)+1(子串.重复)=4个,还剩6个,

    长度为2的子串有9-1(子串ww重复)=8个,

    长度为3的子串有8个,

    长度为4的子串有7个,

    ......

    长度为10的子串有1个,加起来为50。

    2.2C风格字符串

    例1:下列代码的输出是什么?

    	char x = '';
    	printf("%d
    ", x);//0
    
    	char y = '0';
    	printf("%d
    ", y);//48
    
    	char z = 'a';
    	printf("%d
    ", z);//97
    
    	char a = 'A';
    	printf("%d
    ", a);//65
    

    例2:下面函数的功能是?

    求字符串的长度

    int fun(char *x)
    {
    	char *y = x;
    	while (*y++);
    	return y - x - 1;
    }
    

    例3:What is the result of the following program?

    abddcccd

    #include <iostream>
    #include <windows.h>
    
    char * f(char *str, char ch)
    {
    	char *it1 = str;
    	char *it2 = str;
    	while (*it2 != '')
    	{
    		while (*it2 == ch)
    		{
    			it2++;
    		}
    		*it1++ = *it2++;
    	}
    	return str;
    }
    
    int main()
    {
    	char *a = new char[10];
    	strcpy(a, "abcdcccd");
    	std::cout << f(a, 'c');
    	delete[]a;
    
    	system("pause");
    
    	return 0;
    }
    

    2.3标志库提供的字符串处理函数

    2.3.1strlen

    自定义函数实现strlen的功能是:

    int myStrlen(const char *str)
    {
    	assert(str != NULL);
    	int len = 0;
    	while ((*str++) != '')
    	{
    		len++;
    	}
    	return len;
    }
    

    例1:下面的程序的输出是什么?

    x=tse
    y=
    请按任意键继续. . .

    #include <iostream>
    #include <windows.h>
    
    int main()
    {
    	int n;
    	char y[10] = "ntse";
    	char *x = y;
    
    	n = strlen(x);
    	*x = x[n];
    	x++;
    	printf("x=%s
    ", x);
    	printf("y=%s
    ", y);
    
    	system("pause");
    
    	return 0;
    }
    

    2.3.2strcmp

    自定义函数实现strcmp()函数的功能:

    int myStrcmp(const char *str1, const char *str2)
    {
    	assert(str1 != NULL && str2 != NULL);
    	int ret = 0;
    	while (!(ret = *(unsigned char *)str1 - *(unsigned char *)str2) && *str1)
    	{
    		str1++;
    		str2++;
    	}
    	if (ret < 0)
    	{
    		ret = -1;
    	}
    	else if (ret > 0)
    	{
    		ret = 1;
    	}
    	return ret;
    }
    

    例1:判断字符串a和b是否相等,应当使用?

    if(strcmp(a,b))

    2.3.3strcat和strcpy

    自定义函数实现strcat()函数的功能:

    char *myStrcat(char *strDest, const char *strSrc)
    {
    	char *address = strDest;
    	assert((strDest != NULL) && (strSrc != NULL));
    	while (*strDest)
    	{
    		strDest++;
    	}
    	while (*strDest++ = *strSrc++);
    	return address;
    }
    

    自定义函数实现strcpy()函数的功能:

    char *myStrcpy(char *strDestination, const char *strSource)
    {
    	assert(strDestination != NULL && strSource != NULL);
    	char *strD = strDestination;
    	while ((*strDestination++ = *strSource++) != '');
    	return strD;
    }
    

    例1:以下哪个说法正确?

    Debug版崩溃,Release版正常

    int func()
    {
    	char b[2] = { 0 };
    	strcpy(b, "aaa");
    }
    

    2.3.4memcpy和memset

    例1:下面的代码可能出现下列哪些运行结果?

     

    程序运行正常

    aucBuff数组写越界

    #define MAX_BUFF_LEN 100
    
    void MyFunc(unsigned char *pucData, unsigned short wLen)
    {
    	unsigned char aucBuff[MAX_BUFF_LEN];
    	memcpy(aucBuff, pucData, wLen);
    }
    

    2.4字符串的实际应用

    2.4.1字符串包含问题

    1)串的模式匹配算法

    例1:在字符串中查找子串。给定一个字符串A,要求在A中查找一个子串B。

    char *strFind(const char *string, const char *substring)
    {
    	assert(string != NULL && substring != NULL);
    	int m = strlen(string);
    	int n = strlen(substring);
    	int j = 0;
    	if (m < n)
    	{
    		return NULL;
    	}
    	for (int i = 0; i < m - n; i++)//时间复杂度为O((m-n+1)*n)
    	{
    		for (j = 0; j < n; j++)
    		{
    			if (string[i + j] != substring[j])
    			{
    				break;
    			}
    		}
    		if (j == n)
    		{
    			return string + i;
    		}
    	}
    	return NULL;
    }
    

    2.4.2字符串转换为数字

    例1:输入一个表示整数的字符串,把该字符串转换成整数并输出。例如输入字符串“345”,则输出整数345。

    enum Status { kValid = 0, kInvalid };
    int g_nStatus = kValid;
    
    int StrToInt(const char *str)
    {
    	g_nStatus = kInvalid;
    	long long num = 0;
    	if (str != NULL)
    	{
    		const char *digit = str;
    		bool minus = false;
    		if (*digit == '+')
    		{
    			digit++;
    		}
    		else if (*digit == '-')
    		{
    			digit++;
    			minus = true;
    		}
    		while (*digit != '')
    		{
    			if (*digit >= '0' && *digit <= '9')
    			{
    				num = num * 10 + (*digit - '0');
    				if (num > (long long)std::numeric_limits<int>::max)
    				{
    					num = 0;
    					break;
    				}
    				digit++;
    			}
    			else
    			{
    				num = 0;
    				break;
    			}
    		}
    		if (*digit == '')
    		{
    			g_nStatus = kValid;
    			if (minus)
    			{
    				num = 0 - num;
    			}
    		}
    	}
    	return num;
    }
    

    例3:输入两个很大的正数(用C字符串表示),输出它们的乘积,假设不考虑非法输入。

    void multiply(const char *a, const char *b)
    {
    	assert(a != NULL && b != NULL);
    	int i, j, ca, cb, *s;
    	ca = strlen(a);
    	cb = strlen(b);
    	s = (int *)malloc(sizeof(int)*(ca + cb));//分配存储空间
    	for (i = 0; i < ca + cb; i++)
    	{
    		s[i] = 0;//每个元素赋初值0
    	}
    	for (i = 0; i < ca; i++)
    	{
    		for (j = 0; j < cb; j++)
    		{
    			s[i + j + 1] += (a[i] - '0')*(b[j] - '0');
    		}
    	}
    	for (i = ca + cb - 1; i >= 0; i--)//这里实现进位操作
    	{
    		if (s[i] >= 10)
    		{
    			s[i - 1] += s[i] / 10;
    			s[i] %= 10;
    		}
    	}
    	char *c = (char *)malloc((ca + cb) * sizeof(char));
    	i = 0;
    	while (s[i] == 0)
    	{
    		i++;//跳过头部0元素
    	}
    	for (j = 0; i < ca + cb; i++, j++)
    	{
    		c[j] = s[i] + '0';
    	}
    	c[j] = '';
    	for (i = 0; i < ca + cb; i++)
    	{
    		std::cout << c[i];
    	}
    	std::cout << std::endl;
    }
    

    2.4.3其他应用

    例1:字符串中单词的逆转,即将单词出现的顺序进行逆转。如将“Today is Friday!”逆转为“Friday! is Today”。

    void Reverse(char *pb, char *pe)
    {
    	if (pb == NULL || pe == NULL)
    	{
    		return;
    	}
    	while (pb < pe)
    	{
    		char temp = *pb;//交换pb和pe的内容
    		*pb = *pe;
    		*pe = temp;
    		pb++;
    		pe--;
    	}
    }
    
    char *ReverseSentence(char *pData)
    {
    	if (pData == NULL)
    	{
    		return NULL;
    	}
    	char *pBegin = pData;
    	char *pEnd = pData;
    	while (*pEnd != '')
    	{
    		pEnd++;
    	}
    	pEnd--;//去掉空格
    	Reverse(pBegin, pEnd);
    	pBegin = pEnd = pData;
    	while (*pBegin != '')
    	{
    		if (*pBegin == ' ')
    		{
    			pBegin++;;
    			pEnd++;
    			continue;
    		}
    		//反转单词
    		else if (*pEnd == ' ' || *pEnd == '')
    		{
    			Reverse(pBegin, --pEnd);
    			pBegin = ++pEnd;
    		}
    		else
    		{
    			pEnd++;
    		}
    	}
    	return pData;
    }
    

    例2:删除模式串中出现的字符,如“welcome to asted”,模式串为“aeiou”那么得到的字符串为“wlcm t std”,要求性能最优,字符串中全部为小写字母。

    void fun(char *s)
    {
    	assert(s != NULL);
    	int i = 0, j = 0;
    	while (s[j] != '')
    	{
    		while (s[j] == 'a' || s[j] == 'e' || s[j] == 'i' || s[j] == 'o' || s[j] == 'u')
    		{
    			j++;
    		}
    		s[i++] = s[j++];
    	}
    	s[i] = '';
    }
    

    例3:删除字符串开始及末尾的空白符(若干空格),并且把数组中间的多个空格(如果有)符转化为1个。

    void fun(char *s)
    {
    	int i = 0, j = 0;
    	while (s[j] == ' ')//删除头部的空白符
    	{
    		j++;
    	}
    	int len = strlen(s) - 1;
    	while (s[len] == ' ')//删除尾部的空白符
    	{
    		len--;
    	}
    	s[len + 1] = '';
    	while (s[j] != '')
    	{
    		while (s[j] == ' ')
    		{
    			j++;
    		}
    		/*将中间连续的空白符变为一个,判断!= 0是为了防止将头部的连续字符变为1个*/
    		if (s[j - 1] == ' '&& s[j - 2] == ' '&& i != 0)
    		{
    			s[i++] = ' ';
    		}
    		s[i++] = s[j++];
    	}
    	s[i] = '';
    }
    

    例4:在一个字符串中找到第一个只出现一次的字符。如输入abaccdeff,则输出b,假设字符集是ASCII。

    void FirstNotRepeatingChar(const char *pString)
    {
    	assert(pString != NULL);
    	const int tableSize = 256;
    	unsigned int hashTable[tableSize];
    	for (unsigned int i = 0; i < tableSize; ++i)
    	{
    		hashTable[i] = 0;
    	}
    	const char *pHashKey = pString;
    	while (*(pHashKey) != '')
    	{
    		hashTable[*(pHashKey++)]++;
    	}
    	pHashKey = pString;
    	while (*pHashKey != '')
    	{
    		if (hashTable[*pHashKey] == 1)
    		{
    			printf("%c", *pHashKey);
    			return;
    		}
    		pHashKey++;
    	}
    }
    

    判断一个字符串中所有字符是否都不相同?

    bool char_set[256];
    
    int isUniqueCharString(const char *str)
    {
    	assert(str != NULL);
    	int len = strlen(str);
    	for (int i = 0; i < len; ++i)
    	{
    		int val = str[i];
    		if (char_set[val])
    		{
    			return 0;
    		}
    		char_set[val] = true;
    	}
    	return 1;
    }
    

    如果要求在上述算法的基础上进一步降低空间要求,可以使用bit-map(后续章节讲解),如果假设字符串仅包含从'a'到'z'的字符,我们可以将空间需求降低到一个int。

    int isUniqueChars(char *str)
    {
    	assert(str != NULL);
    	int checker = 0;
    	int len = strlen(str);
    	for (int i = 0; i < len; ++i)
    	{
    		int val = str[i] = 'a';
    		if ((checker & (1 << val)) > 0)
    		{
    			return 0;
    		}
    		checker |= (1 << val);
    	}
    	return 1;
    }
    

    本章习题

    1.下面程序的运行结果是。

    运行出错。因为p的对象存储于文字常量区,不能对其进行修改

    	char *p = "abcdefgh";
    	p += 3;
    
    	std::cout << strlen(strcpy(p, "ABCD")) << std::endl;
    

    2.例如需要将字符串数组strDest[]追加到字符串数组strSrc[]的后面,下面哪种方法可以保证程序不会越界?

    都可以。

    	strncat(strSrc, strDest, min(sizeof(strSrc) - strlen(strSrc) - 1, strlen(strDest)));
    
    	snprintf(strSrc, sizeof(strSrc) - 1, "%s%s", strSrc, strDest);
    

    3.写成函数strcpy的实现。

    char *myStrcpy(char *strDest, const char *strSrc)
    {
    	assert((strDest != NULL) && (strSrc != NULL));
    	char *address = strDest;
    	while ((*strDest++ = *strSrc++) != '');
    	return address;
    }
    

    4.设计一个算法移除字符串中的重复字符,并写出测试用例。

    void removeDuplicates(char *str)
    {
    	if (str == NULL)
    	{
    		return;
    	}
    	int len = strlen(str);
    	if (len < 2)
    	{
    		return;
    	}
    	int tail = 1;
    	for (int i = 1; i < len; ++i)
    	{
    		int j;
    		for (j = 0; j < tail; ++j)
    		{
    			if (str[i] == str[j])
    			{
    				break;
    			}
    		}
    		if (j == tail)
    		{
    			str[tail] = str[i];
    			++tail;
    		}
    	}
    	str[tail] = 0;
    }
    

    上述算法时间复杂度为O(n^2),如果可以申请一个固定大小的内存,则可以将时间复杂度降低为O(n)。

    void removeDuplicates2(char *str)
    {
    	if (str == NULL)
    	{
    		return;
    	}
    	int len = strlen(str);
    	if (len < 2)
    	{
    		return;
    	}
    	bool hit[256];
    	for (int i = 0; i < 256; ++i)
    	{
    		hit[i] = false;
    	}
    	hit[str[0]] = true;
    	int tail = 1;
    	for (int i = 1; i < len; ++i)
    	{
    		if (!hit[str[i]])
    		{
    			str[tail] = str[i];
    			++tail;
    			hit[str[i]] = true;
    		}
    	}
    	str[tail] = 0;
    }
    

    5.将字符串中的所有空格替换为'%20'。函数原型为:

    225415112521

  • 相关阅读:
    性能测试,负载测试,压力测试,容量测试的区别
    全文检索引擎Solr系列——整合MySQL、MongoDB
    全文检索引擎Solr系列——整合中文分词组件IKAnalyzer
    全文检索引擎Solr系列——整合中文分词组件mmseg4j
    全文检索引擎Solr系列——Solr核心概念、配置文件
    全文检索引擎Solr系列—–全文检索基本原理
    ES之一:Elasticsearch6.4 windows安装 head插件ik分词插件安装
    FTP,FTPS,FTPS与防火墙
    NGINX通过Stream转发ftp请求
    nginx 的第三方模块ngx_http_accesskey_module 来实现下载文件的防盗链步骤(linux系统下)
  • 原文地址:https://www.cnblogs.com/denggelin/p/6821997.html
Copyright © 2020-2023  润新知