字符串比较之初级程序员和高级程序员
1. 问题的引入
这个话题的来源是这样的:开发过程中不可避免的用到了字符串比较的操作,按理说这个并不复杂,因为有现成的接口可以使用(strcmp, strncmp, memcmp等),我在使用过程中也没有仔细考虑过这些接口的具体区别。后来一个工作经验丰富的同事看代码调优时说到了这一点:来,看看你的代码有什么问题吗?
举个例子,我最初的代码是这样:
#include <stdio.h>
#include <string.h>
void main(void)
{
char *str1 = "asdfghjkl";
char *str2 = "asdfghjrtw"
if(strlen(str1) == strlen(str2) && !memcmp(str1, str2, strlen(str1))){
return 1;/*两个字符串一样,返回1;不一样返回0*/
}else{
return 0;
}
}
这个代码在语法和逻辑上并未错误:
- ①先比较字符串长度;
- ②在比较字符串内容
在字符串长度不同的情况下,就没有比较比较字符串内容了。个人感觉这逻辑很严密,然后我的回答是:“我没有看出什么问题呀!”。
然后后面就是涨姿势的时刻了。
2. 出现的问题
2.1 时间复杂度
上述函数的实现时间复杂度是多少呢?
O
(
n
)
+
O
(
n
)
+
O
(
n
)
+
O
(
n
)
=
4
∗
O
(
n
)
。
O(n) + O(n) + O(n) + O(n) = 4*O(n)。
O(n)+O(n)+O(n)+O(n)=4∗O(n)。
- strlen() : O(n)
- memcmp() : O(n)
比较两个字符串,时间复杂度是4O(n),效率确实很低。
正常情况下,一次遍历便可以确定两个字符串是否相等,时间复杂度为O(n)。
2.2 string类的几个函数
-
strlen
-
strcmp
-
strncmp
-
memcmp
string类的几个函数有一个共同的特点:只操作字符串,不处理那些无法打印的字符。默认都是以’\0’作为字符串的结束(strlen不计算最后的‘\0’字符)。strlen的基本实现应为是:如果不是’\0’, 长度递增1;比较函数,它们也都需要逐个字符遍历(最终可能为bit)比较。也就是说他们都需要遍历一遍字符串才能得到结果。
memcmp函数比较的是指定的内存范围,而不管该内存地址中的内容是否为字符串、其他特殊字符。
举个例子:
#include <stdio.h>
#include <string.h>
void main(void)
{
char str1[100] = "asdfghj";
char *str2[100] = "asdfghj"
if(memcmp(str1, str2, sizeof(str1))){
return 1;/*两个字符串一样,返回1;不一样返回0*/
}else{
return 0;
}
}
这个例子中,由于我并没有初始化str1
和str2
,即使它们前8个字符一致,但是后续的92个字节的内存空间的内容并不知道,因此正常情况下为0,即不相等。[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bZ9OZscz-1601516609655)(C:%5CUsers%5CAdmin%5CAppData%5CRoaming%5CTypora%5Ctypora-user-images%5Cimage-20201001093441564.png)]
3. 怎么实现效率高呢?
#include <stdio.h>
#include <string.h>
void main(void)
{
char *str1 = "asdfghjkl";
char *str2 = "asdfghjrtw"
if(!strcmp(str1, str2, strlen(str1)+1)){
return 1;/*两个字符串一样,返回1;不一样返回0*/
}else{
return 0;
}
}
时间复杂度降为2*O(n)。性能提高了一倍。
那么这个问题严重吗?
如果想进阶高级,那这是很基础并且很严重的问题了。从这个问题可以看出(我)基础水平一般,没有深入考虑过性能、效率问题。初级和高级的区别差很多吗?我们从这个问题中应该可以窥见一斑。我们往往忽略的地方,可能正是人家提高进阶的地方。以后工作工程中,应该多多思考了,在实现基本功能的前提下,考虑下程序的时空复杂度,通过对程序时空复杂度的分析,代码水平应该可以有所进步。