编程珠玑第二章习题—向量的旋转

书中讲到三种方法,“杂技”交换、“求逆算法”和“块交换”法,注意形参一定要传引用!

“杂技”交换法:

void rotate1(string &str, int i)
{
	set<int> s;
	int N = str.size();
	int start = 0;
	while(s.size() != N)
	{
		int n = 0;
		int tmp = str[start];
		while(((n+1)*i+start)%N != start)
		{
			str[(n*i+start)%N] = str[((n+1)*i+start)%N];
			s.insert(((n+1)*i+start)%N);
			++n;
		}
		str[(n*i+start)%N] = tmp;
		s.insert(start);
		if(s.size() != N)
		{
			++start;
			n = 0;
		}
		else
			break;
	}
}

时隔半年修改一下“杂技交换法”的实现,当时写的什么鬼,占用了这么多的辅助空间,实际上只要O(1)的辅助空间就可以了。

//"杂技交换法"
char* rotate(char* pStr, int n)
{
    if(pStr != NULL && n > 0)
    {
        int length = strlen(pStr);
        int countOfSwaped = 0;
        int startOfSwap = 0;
        int index = startOfSwap;
        while(countOfSwaped < length)
        {
        	char temp = pStr[index];
        	int newIndex = (index+n) % length;
        	
        	while(newIndex != startOfSwap)
        	{
        	 	pStr[index] = pStr[newIndex];
        	 	++countOfSwaped;
            	index = newIndex;
            	newIndex = (newIndex+n) % length;
        	}
        	pStr[index] = temp;
        	++countOfSwaped;
        	
        	if(countOfSwaped < length)
        		index = ++startOfSwap;
        }
    }
    return pStr;
}


之前并没有注意到题目里提到的最大公约数问题,如果利用最大公约数来确定循环次数,重新实现的算法如下:点击

“求逆”法:

void reverse(string &str, int start, int end)
{
	int first = start;
	int last = end;
	while(first <= last)
	{
		char tmp = str[first];
		str[first++] = str[last];
		str[last--] = tmp;
	}
}
		
void rotate2(string &str, int i)
{
	int n = str.size();
	reverse(str, 0, i-1);
	reverse(str, i, n-1);
	reverse(str, 0, n-1);
}

代码测试:

int main() 
{
	string str1 = "abcdefgh";
	string str2 = str1;
	rotate1(str1, 4);
	rotate2(str2, 4);
	for(auto it : str1)
		cout << it;
	cout << endl;
	for(auto it : str2)
		cout << it;
	cout << endl;
		
	return 0;
}

“块交换”法:

void swap(char &a, char &b)
{
    char tmp = a;
    a = b;
    b = tmp;
}

void exchange(string &str, int first, int last, int i)
{
    for(int num = 0; num < i; ++num)
		swap(str[first+num], str[last-i+num+1]);
}

void move(string &str, int &first, int &last, int &num)
{
    if(last-first+1 > num)                 //判断要旋转的量和当前块长度的关系,若旋转量已经等于块长度,则旋转已经完成
    {
        int len = last - first + 1 - num;      //假设分成ab两块,交换成ba,len表示块b的长度
        int numOfSwap = num <= len ? num : len;   //确定要交换的量
        exchange(str, first, last, numOfSwap);
        if(num <= len)                     
	    	last -= num;                   //新块的索引已经改变
		else
		{
	    	first += len;
	    	num -= len;
		}
        move(str, first, last, num);
    }
}

void rotate(string &str, int num)
{
    int first = 0;
    int last = str.size() - 1;
    move(str, first, last, num);
}





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值