C语言-字符串的左旋问题

左旋字符串的思路有两种。

思路一:将除第一个字符外的每一个字符向前移动一位,*(str+k)=*(str+k+1),再将最前面的那一个字符挪到最后面(这里要先额外定义一个变量tmp,存储第一个位置所放置元素的值,即char tmp=*str,以免后面的字符向前挪动时将第一个字符覆盖掉)

代码实现:

#include<stdio.h>
void string_left_rotate(char* str, int k)//在函数定义中,arr代表数组首元素的地址,因此这里用字符型指针str接收,指针str同样指向数组首元素。
{
	int i = 0;
	int n = strlen(str);
	for (i = 0; i < k; i++)
	{
		char tmp = *str;//指针str最开始指向数组首元素地址,因此,最开始对其解引用时得到的就是数组的第一个元素,将其赋给字符型变量tmp。又由于在循环中,指针str从来不变,因此,每次执行到这条语句时,都会将数组第一个元素的值赋给字符变量tmp,不管第一个变量是谁,而且,由于tmp是一个变量,来着不拒,可以随便变化。
		int j = 0;
		for (j = 0; j < n - 1; j++)
		{
			*(str + j) = *(str + j + 1);//将除第一个元素外的所有元素向前移动一位。
		}
		*(str + n - 1) = tmp;//将原本处在当前字符串中最后一位的元素赋值为tmp,亦即第一个元素对应的值,以上两条语句就实现了数组的左旋。
	}
}
int main()
{
	char arr[10] = "ABCDEF";
	int k = 10;
	string_left_rotate(arr, k);//定义一函数,参数为定义的数组及数组中元素个数
	printf("%s\n", arr);
	return 0;
}

思路二:对一整个字符串而言,如果要左旋前k个字符,那可以将前k个和后面的字符先分别逆序,逆序完成后再将整个字符串逆序,最终的结果就等效于思路一中的字符串左旋的效果。

代码实现:

#include<stdio.h>
#include<assert.h>
void reverse(char* left, char* right)
{
	assert(left != NULL);
	assert(right != NULL);
	while (left < right)
	{
		char tmp;
		tmp = *left;
		*left = *right;
		*right = tmp;
		right--;
		left++;
	}
}
void string_left_rotate(char*str,int x)//字符串翻转的函数需要一个指针以找到函数需要处理的字符串,根据这个指针就可以找到字符串中的每一个字符,
//reverse函数中的左右指针更是不在话下
{
	int n = strlen(str);
	reverse(str, str + x - 1);
	reverse(str + x, str + n - 1);
	reverse(str, str + n - 1);
}
int main()
{
	char arr[20] = { "ABCDEFGH" };
	string_left_rotate(arr, 3);
	printf("%s\n", arr);
	return 0;
}

补充一点:sizeof和strlen在函数内部的使用问题。

需要注意的是,对于sizeof而言,其计算的是其括号内元素类型的长度,如果将sizeof放在函数内部去计算字符串的长度的话,会出问题,因为在函数传接收数组的地址时,已经将其退化为一个指针了,sizeof(数组名)的情况下虽然可以计算数组的长度,亦即数组名代表整个数组,但是经过函数的传参操作后,整个数组早已退化成为一个指针,因此,此时计算出的是指针的长度。而对于strlen而言,其计算的是括号内指针指向的地址中元素的长度,所以不会受影响。

因此如果要用sizeof计算数组的长度,最好在主函数中计算,将计算结果保存在一个变量中,在放入函数中以便于使用。

附加问题:判断一个字符串是否是另外一个字符串的左旋:

思路:对于字符串的左旋而言,唯一改变的就是字符排列的位置,左旋操作甚至不会改变字符与字符之间的先后顺序(这里将字符串想象成一个链表),因此,如果一个字符串是另一个字符串的左旋,那么他们一定会由相同的字符所组成,并且字符之间有着相同的先后顺序,也就是说经过若干次左旋后(0到n-1次)两个字符串一定会相等。比较字符串可以用strcmp函数来实现。

#include<stdio.h>
#include<assert.h>
int is_string_rotate(char* str1,char* str2)
{
	int i = 0;
	int n = strlen(str1);
	for (i = 0; i < n; i++)//一个长度为n的字符串,最多左旋n-1次,当左旋n次时就会变回最开始的样子,对于i而言的for循环,整个循环的意义是在最坏情况下,
		//以从0(即不变)的幅度,到n-1的幅度对字符串进行逆序(对于逆序而言,0次和n次是等价的)
	{
		int j = 0;
		char tmp = *str1;
		for (j = 0; j < n; j++)//对于j而言的for循环,整个循环的结果是将循环前排在第一位的字符挪到最后一位去
		{
			*(str1 + j) = *(str1 + j + 1);
		}
		*(str1+n-1) = tmp;
		if (strcmp(str1, str2) == 0)
		{
			return 1;
		}
	}
	return 0;
}
int main()
{
	char arr1[20] = { "ABCDEFG" };
	char arr2[20] = { "DEFGABC" };
	int m=is_string_rotate(arr1, arr2);
	if (m == 1)
	{
		printf("字符串2是字符串1的逆序");
	}
	else
	{
		printf("字符串2不是字符串1的逆序");
	}
	return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值