左旋字符串的思路有两种。
思路一:将除第一个字符外的每一个字符向前移动一位,*(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;
}