【C语言习题】27.字符串左旋


作业标题

字符串左旋

作业内容

实现一个函数,可以左旋字符串中的k个字符。

例如:

ABCD左旋一个字符得到BCDA

ABCD左旋两个字符得到CDAB

2.解题思路

存储字符串需要用数组,最大的问题是如何左旋?

1.把要第一个元素先存起来,把后面的依次前移,第一个元素放原来最后面。左旋几次,就执行几次。

2.利用复制函数,先把后面的字符串元素存起来,再把需要左旋的前面的元素存到后面。

3.如果是左旋3位:先将要左旋的前三个家伙逆序(CBADEFG),然后将后半段也逆序(CBAGFED),最后整体逆序(DEFGABC)即可。


3.具体代码

#include <stdio.h>
#include <assert.h>
void reverse_arr(char *src, int k)// 函数用于反转字符串数组src中的前k个字符
{
	int tmp;	
	assert(src != NULL);// 断言src不为空指针
    if(k<=0){
        return 0;
    }
	while (k--)// 保存当前字符
	{
		char *cur = src; // 创建临时指针指向字符串的开始
		tmp = *cur;  // 保存当前字符
		while (*(cur+1) != '\0')// 循环移动字符串中的字符,直到到达字符串的末尾
		{
		    *cur = *(cur+1);// 将下一个字符移动到当前位置
		    cur ++;// 移动指针到下一个字符
		}
		*cur = tmp;// 将保存的字符放到字符串的末尾
	}
}
int main()
{
	char arr[] = "ABCDE";
	int k = 0;
	scanf("%d",&k);
	reverse_arr(arr, k);
	printf("%s\n", arr);
	return 0;
}

打印:

在这里插入图片描述

代码讲解:

  1. 先进入main函数,定义arr字符数组,并存入需要左旋的字符串。

  2. 定义一个整型常量k

  3. 输入这个整型常量,得到需要左旋的位数

  4. 进入reverse_arr()函数,将arr数组首地址和 左旋位数传给这个函数

  5. 定义一个整型变量tmp。

  6. assert(src != NULL);断言src不为空指针

  7. if(k<=0){
        return 0;
    }
    

    如果输入的是非正数,那么就停止reverse_arr()函数。

  8. 进入while循环,循环进行k次。

  9. char *cur = src; 创建临时指针指向字符串的开始

  10. tmp = *cur; 保存当前字符

  11. while (*(cur+1) != '\0')// 循环移动字符串中的字符,直到到达字符串的末尾
    {
        *cur = *(cur+1);// 将下一个字符移动到当前位置
        cur ++;// 移动指针到下一个字符
    }
    

    进入while循环,循环次数为k-1次。目的是将arr[1]到arr[4]的元素往前挪一位。

  12. *cur = tmp; 将保存的字符放到字符串的末尾,也就是把arr[0]的元素给arr[4]。

  13. 然后继续循环,每次循环都会左旋一次。直到循环结束,返回main函数。

  14. 打印左旋后的arr数组。


改进一:

这个思路当然可以,但是一次一次转毕竟太麻烦,就不能一次到位么?

我们可以选择拼接法,一次到位:

void leftRound(char * src, int time)
{
	int len = strlen(src);
	int pos = time % len; //断开位置的下标
	char tmp[256] = { 0 }; //更准确的话可以选择malloc len + 1个字节的空间来做这个tmp
	
	strcpy(tmp, src + pos); //先将后面的全部拷过来
	strncat(tmp, src, pos); //然后将前面几个接上
	strcpy(src, tmp); //最后拷回去
}

代码讲解:

  1. 进入leftRound函数int len = strlen(src);定义整型变量len来存放字符数组arr的长度。

  2. int pos = time % len; 定义整型变量pos来存放断开位置的下标。

    如果我们想左旋2个字符,那么这里的pos就是2。

  3. char tmp[256] = { 0 };定义一个字符数组tmp来存放左旋的数组元素。

  4. strcpy(tmp, src + pos); 先将后面的全部拷过来

    char *strcpy(char *dest, const char *src);

    参数说明:

    dest :目标字符串指针,指向用于存储复制内容的内存空间。
    src :源字符串指针,指向要复制的字符串。

    返回值:

    返回一个指向目标字符串 dest 的指针。

    工作原理:

    strcpy 函数的是将 src 指向的字符串复制到 dest 指向的内存空间中,直到遇到 src 字符串的结束符 \0 。复制完成后, dest 指向的字符串将与 src 指向的字符串相同。

    例如,我们想左旋2个字符,那么这里的strcpy函数是把arr[2]往后的字符串复制到tmp数组里面。

  5. strncat(tmp, src, pos); 将前面几个接上

    char * strncpy(char *dest, const char *src, size_t n);

    参数说明:

    dest :目标字符串指针,指向要追加内容的字符串。
    src :源字符串指针,指向要追加的字符串。
    n :要追加的最大字符数。

    返回值:

    返回一个指向目标字符串 dest 的指针。

    工作原理:

    strncat 函数的工作原理是将 src 指向的字符串的前 n 个字符追加到 dest 指向的字符串的末尾。如果 src 字符串的长度小于 n ,则追加 src 字符串的全部内容;如果 src 字符串的长度大于或等于 n ,则只追加前 n 个字符。

    例如,我们想左旋2个字符,那么这里的strncpy函数是把arr[2]往前的字符串:arr[0]arr[1]复制到tmp数组后面。(反正左旋后就是在后面的)

  6. strcpy(src, tmp); 最后把tmp里的元素拷到src里面去。


改进二:

这个方法要用到一个数组形成的辅助空间,让人觉得有点不爽,还可以有更好的选择,例如ABCDEFG,左旋3次后变成DEFGABC,有一个特殊的操作方式:

先将要左旋的前三个家伙逆序(CBADEFG),然后将后半段也逆序(CBAGFED),最后整体逆序(DEFGABC)即可。这样只需要做数值交换即可,可以写一个函数帮我们完成局部逆序,代码如下:

void reverse_part(char *str, int start, int end) //将字符串从start到end这一段逆序
{
	int i, j;
	char tmp;

	for (i = start, j = end; i < j; i++, j--)
	{
		tmp = str[i];
		str[i] = str[j];
		str[j] = tmp;
	}
}

void leftRound(char * src, int time)
{
	int len = strlen(src);
	int pos = time % len;
	reverse_part(src, 0, pos - 1); //逆序前段
	reverse_part(src, pos, len - 1); //逆序后段
	reverse_part(src, 0, len - 1); //整体逆序
}

代码讲解:

  1. 进入leftRound函数,int len = strlen(src);定义整型变量len来存放字符数组arr的长度。

  2. int pos = time % len; 定义整型变量pos来存放断开位置的下标。

    如果我们想左旋2个字符,那么这里的pos就是2。

  3. reverse_part(src, 0, pos - 1);进入reverse_part函数。逆序前段。

  4. 定义整型变量i和j,定义字符变量tmp。

  5. 进入for循环,i=0;j=pos-1;

    这个for循环干的其实就是先把数组第一个元素和(前端)最后一个元素互换位置,然后把第二个元素和(前端)最后第二个元素互换位置,依此类推。

  6. reverse_part(src, pos, len - 1); 逆序后段。

  7. 进入for循环,i=pos;j=len-1;

    这个for循环干的其实就是先把数组(后端)第一个元素和最后一个元素互换位置,然后把(后端)第二个元素和最后第二个元素互换位置,依此类推。

  8. reverse_part(src, 0, len - 1); 整体逆序

  9. 进入for循环,i=0;j=len-1;

    这个for循环干的其实就是先把数组第一个元素和最后一个元素互换位置,然后把第二个元素和最后第二个元素互换位置,依此类推。
    环,i=pos;j=len-1;

    这个for循环干的其实就是先把数组(后端)第一个元素和最后一个元素互换位置,然后把(后端)第二个元素和最后第二个元素互换位置,依此类推。

  10. reverse_part(src, 0, len - 1); 整体逆序

  11. 进入for循环,i=0;j=len-1;

    这个for循环干的其实就是先把数组第一个元素和最后一个元素互换位置,然后把第二个元素和最后第二个元素互换位置,依此类推。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值