读程序员编程艺术第一章---左旋字符串(三)

STL中的循环移位法用到了gcd原理。gcd原理的实现是简单的欧几里得算法又称辗转相除法,这里就不在赘述了。

对于数组的循环移位,可以采用的方法一共有四种。

1、将数组拷贝复制到相同长度的数组之中,改变顺序,并拷贝回原来的数组。

2、先交换前面的能够交换的部分,在处理尾巴。如上一遍中的指针翻转法就是这么做的。

3、分组交换。

4、所有序号为(j+i*m)%n(j表示循环的起始链位置,i为计数变量,m为左旋位数,n表示字符串长度),会构成一个循环链(共有gcd(n,m)个),每个循环链上的元素只要移动一个位置既可,最后整个过程一共交换了n次(每一个循环链长n/gcd(n,m),总共有gcd(n,m)个循环链)。


下面我们来看一个简单的例子:


字符串abcd需要左旋维dabc,可以知道n=4,m=3。

根据4中的方法:

1、j=0,即起始位置为0;

2、得到循环链

     for i=0:n-1

        int k=i*m%n;

     end;

     得到循环链是0,3,2,1

3、我们根据这个循环序列复制一遍即可得到想要的结果。

     temp=ch[0],ch[0]=hc[3],ch[3]=ch[2],ch[2]=ch[1],ch[1]=temp;

     即abcd-->_bcd-->dbc_-->db_c-->d_bc-->dabc;

     很奇妙是吧。

上面是对于m,n互为质数的情况,现在我们讨论一下m,n不是互为质数情况。此时循环链不止一个,我们只要把每个循环链依次的执行一遍既可以得到我们想要的结果。所有序号为(j+i*m)%n(其中j为0到gcd(n,m)-1之间的某一个数,i=0:n-1)会构成一个循环,一共有gcd(n,m)个循环链。

可以编写代码 如下:

#include"stdafx.h"
#include<stdio.h>
#include"string"
#include"iostream"
using namespace std;

//求最大公因数
int gcd(int m,int n)
{
	//递归出口
	if(m%n==0)
		return n;
	else
	{
		//设置临时变量,防止m丢失
		int temp=m;
		m=n;
		n=temp%n;
		//递归
		gcd(m,n);
	}
}

//定义左旋函数
void rotate(string &str,int m)
{
	//字符串长度
	int lenofStr=str.length();
	//循环链的个数,也即是外层循环的次数
	int numofGroup=gcd(lenofStr,m);
	//每个循环链的个数,也即是内层循环的次数
	int elemInSub=lenofStr/numofGroup;

	for(int j=0;j<numofGroup;j++)
	{
		char temp=str[j];
		int i;
		//一次循环链的交换
		for(i=0;i<elemInSub-1;i++)
		{
			str[(j+i*m)%lenofStr]=str[(j+(i+1)*m)%lenofStr];
		}
		str[(j+i*m)%lenofStr]=temp;
	}
}
int main()
{
	string str="abcdef";
	cout<<str<<endl;
	rotate(str,3);
	cout<<str<<endl;
	return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值