【C语言】实现一个函数,可以左旋字符串中的K个字符

题目说明:

要求实现一个函数,可以左旋字符串中的K个字符;
其中:
ABCD左旋一个字符得到BCDA
ABCD左旋两个字符得到CDAB


解法一:

解题思路:

拿到一组字符串之后,我们首先设置一个临时变量,存放字符串中的第一个字符。
然后把字符串中的其余字符通过循环依次前移一位,最后再把临时变量的值赋给字符串的最后的一位。

以上是字符串的一次左旋,要左旋几次就可以通过循环重复以上过程几次就可以了。

图解如下所示:

这里写图片描述

程序源码:

#include<iostream>
#include<assert.h>
#include<stdio.h>
#include<Windows.h>

using namespace std;

void string_reverse(char* arr, int len){
    assert(arr);
    assert(len > 0);
    char temp;
    temp = arr[0];
    for (int i = 0; i < len - 1; ++i){
        arr[i] = arr[i + 1];
    }
    arr[len - 1] = temp;
}

void Print(char* arr, int len){
    for (int i = 0; i < len; ++i){
        cout << arr[i] << "   ";
    }
    cout << endl;
}

void test(){
    char arr[] = { 'A', 'B', 'C', 'D', '1', '2', '3', '4' };
    //这里用数组来表示字符串,如果用字符串来表示字符串会产生一个错误
    //char *arr = "ABCD1234";
    int count = 0;
    int len = 0;
    len = sizeof(arr) / sizeof(arr[0]);
    //len = strlen(arr);
    Print(arr, len);
    cout << "请输入要左旋的次数:>" << endl;
    cin >> count;
    count %= len;
    while (count--){
        string_reverse(arr, len);
    }
    Print(arr, len);
}

int main(){
    test();
    system("pause");
    return 0;
}

程序运行结果:

这里写图片描述

【注意】

如果向程序中所标注的直接用字符串来表示的话,会造成以下后果:

这里写图片描述

原因:

我们先来看一个内存分配示意图:
这里写图片描述

假如现在执行以下代码:

   int a,b,c,d;
   a=0;
   b=1;
   c=2;
   d=3;

这里写图片描述

则a的地址最高,d的地址最低,因为这是一个压栈的过程。

这里写图片描述

但是如果执行以下语句的话:

char arr[] = { 'A', 'B', 'C', 'D', '1', '2', '3', '4' };

内存分配如图所示:

这里写图片描述

这时我们可以发现数组内存放的数据的地址是依次增加的,也就是说开始的元素地址最小,结束的元素地址最大。这是为什么呢?

原来数组在申请内存的时候不是为他的元素一个个申请内存,而是一次性的把数组所需要的内存申请好,再依次存放数组元素。

而如果我们在代码中用的是以字符串的形式的话,就会造成问题了:

char *arr = "ABCD1234";

这里写图片描述


解法二:

解题思路:

部分逆置 + 部分逆置
整体逆置

具体思路如图所示:

这里写图片描述

程序源码:


#include<iostream>
#include<assert.h>
#include<stdio.h>
#include<Windows.h>

using namespace std;

void Print(char* arr, int len){
    for (int i = 0; i < len; ++i){
        cout << arr[i] << "   ";
    }
    cout << endl;
}

//数组的逆置
void reverse(char* start, char* end){
    assert(start);
    assert(end);
    while (start<end){
        *start ^= *end;
        *end ^= *start;
        *start ^= *end;
        start++;
        end--;
    }
}

void string_reverse(char* arr, int len,int count){
    assert(arr);
    assert(len > 0);
    assert(count > 0);
    cout << "逆置前半段" << endl;
    reverse(arr, arr + count - 1);
    Print(arr, len);
    cout << "逆置后半段" << endl;
    reverse(arr + count, arr + len - 1);
    Print(arr, len);
    cout << "整体逆置" << endl;
    reverse(arr, arr + len - 1);
    Print(arr, len);
}

void test(){
    char arr[] = { 'A', 'B', 'C', 'D', '1', '2', '3', '4' };
    int count = 0;
    int len = 0;
    len = sizeof(arr) / sizeof(arr[0]);
    cout << "请输入要左旋的次数:>" << endl;
    cin >> count;
    count %= len;
    string_reverse(arr, len, count);
}

int main(){
    test();
    system("pause");
    return 0;
}

程序运行结果:

这里写图片描述

这里写图片描述


解法三:

解题思路:

首先把要逆置的字符串连接成双倍字符串;
然后从双倍字符的第count位开始(count是要逆转的K个字符),到第count + len结束(len是字符串长度);
这一段就是逆转后的字符串了;
示意图如下所示:

这里写图片描述

程序源码:



#include<iostream>
#include<assert.h>
#include<stdio.h>
#include<Windows.h>

using namespace std;

void Print(char* arr, int len){
    for (int i = 0; i < len; ++i){
        cout << arr[i] << "   ";
    }
    cout << endl;
}

void string_reverse(char* arr, int len, int count){
    assert(arr);
    assert(len > 0);
    assert(count > 0);
    //设置双倍字符串
    char *ptemp = (char *)malloc(len * 2 + 1);
    if (NULL == ptemp)
        return;
    char *temp = NULL;
    temp = ptemp;
    strcpy(ptemp, arr);
    strcat(ptemp, arr);
    //在双倍字符串中拿出逆置后的字符串
    strncpy(arr, temp + count, len);
    free(ptemp);
}

void test(){
    char *arr = "ABCD1234";
    int count = 0;
    int len = 0;
    len = strlen(arr);
    Print(arr, len);
    cout << "请输入要左旋的次数:>" << endl;
    cin >> count;
    count %= len;
    string_reverse(arr, len, count);
    Print(arr, len);
}

int main(){
    test();
    system("pause");
    return 0;
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值