/**
* @file 020_move_string.c
* @author dinghuaneng
* @date 2011.06.22
* @brief 將字串進行向左旋轉,即迴圈左移的演算法實現。
* 最後那種方法在時間和空間上都很高效,且代碼簡短,很難出錯。
* 最節約空間和時間的方法來源:《編程珠璣》
* @defgroup move_string
* @{
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/*********************** 最節約時間的方法 ************************/
/**
* @brief 將字串向左旋轉n個位置
* @param str 待旋轉的字串
* @param[in] mov 需要旋轉的數量
* @return 無
*/
void move_string_left(char *str, int mov)
{
if (NULL == str || mov <= 0)
return;
char tmp[mov];
int i;
int len = strlen(str);
if (len == 0)
return;
mov %= len;
if (mov == 0)
return;
for (i = 0; i < sizeof tmp; i++)
tmp[i] = str[i];
tmp[i] = '\0';
for (i = 0; i < len-mov; i++)
str[i] = str[i+mov];
for (; i < len; i++)
str[i] = tmp[i-(len-mov)];
}
/**
* @brief 將字串向右旋轉n個位置
* @param str 待旋轉的字串
* @param[in] mov 需要旋轉的數量
* @return 無
*/
void move_string_right(char *str, int mov)
{
if (NULL == str || mov <= 0)
return;
char tmp[mov];
int i;
int len = strlen(str);
if (len == 0)
return;
mov %= len;
if (mov == 0)
return;
for (i = len - mov; i < len; i++) {
tmp[i-(len-mov)] = str[i];
}
tmp[i-(len-mov)] = '\0';
for (i = len - 1; i >= mov; i--) {
str[i] = str[i-mov];
}
for (; i >= 0; i--)
str[i] = tmp[i];
}
/*********************** 最節約時間的方法 ************************/
/*********************** 最節約空間的方法 ************************/
/**
* @brief 將字串向左旋轉1個位置
* @param str 待旋轉的字串
* @param[in] mov 需要旋轉的數量
* @return 無
*/
void move_string_one_left(char *str)
{
if (NULL == str)
return;
int len = strlen(str);
int i;
if (len == 0)
return;
char tmp = str[0];
for (i=0; i<len-1; i++) {
str[i] = str[i+1];
}
str[i] = tmp;
}
/**
* @brief 將字串向右旋轉1個位置
* @param str 待旋轉的字串
* @param[in] mov 需要旋轉的數量
* @return 無
*/
void move_string_one_right(char *str)
{
if (NULL == str)
return;
int len = strlen(str);
if (len == 0)
return;
char tmp = str[len-1];
int i;
for (i=len-1; i>0; i--) {
str[i] = str[i-1];
}
str[i] = tmp;
}
/*********************** 最節約空間的方法 ************************/
/*********************** 最節約空間和時間的方法之一 ************************/
/**
* @brief 返回數值i和j的最大公約數
* @return 正確返回最大公約數,參數有問題返回-1
*/
int gcd(int i, int j)
{
if (i<=0 || j<=0)
return -1;
while (i != j) {
if (i > j)
i -= j;
else
j -= i;
}
return i;
}
/**
* @brief 將字串向左旋轉n個位置
* @param str 待旋轉的字串
* @param[in] mov 需要旋轉的數量
* @return 無
*/
void move_string_fast_left(char *str, int mov)
{
if (NULL == str || mov <= 0)
return;
int len = strlen(str);
char tmp;
if (!mov)
return;
mov %= len;
if (!mov)
return;
int i, j, k;
int g_cd = gcd(mov, len);
for (i=0; i<g_cd; i++) {
tmp = str[i];
j = i;
while (1) {
k = j + mov;
if (k >= len)
k -= len;
if (k == i)
break;
str[j] = str[k];
j = k;
}
str[j] = tmp;
}
}
/**
* @brief 將字串向右旋轉n個位置
* @param str 待旋轉的字串
* @param[in] mov 需要旋轉的數量
* @return 無
*/
void move_string_fast_right(char *str, int mov)
{
if (NULL == str || mov <= 0)
return;
int len = strlen(str);
if (!mov)
return;
mov %= len; // 修移動次數
if (!mov)
return;
mov = len - mov;
move_string_left(str, mov);
}
/*********************** 最節約空間和時間的方法之一 ************************/
/*********************** 最節約空間和時間的方法之二 ************************/
/**
* @brief 交換字串str中的從pos1開始和從pos2開始長度為num的兩部分元素。
* 注意防止記憶體越界!
* @param str 待交換部分字元的字串
* @param[in] pos1 第一部分起始位置
* @param[in] pos2 第二部分起始位置
* @param[in] num 要交換的字元數量Architexa的反編譯和破解
*/
void swap_string(char *str, int pos1, int pos2, int num)
{
char *str1 = str + pos1;
char *str2 = str + pos2;
int i;
char tmp;
for (i=0; i<num; i++) {
tmp = *str1;
*str1 = *str2;
*str2 = tmp;
str1++;
str2++;
}
}
/**
* @brief 用交換元素的方法進行向左旋轉(迴圈左移)
* @param str 待旋轉的字串
* @param[in] mov 需要旋轉的數量
* @return 無
*/
void move_string_swap_left(char *str, int mov)
{
if (NULL == str || mov <= 0)
return;
int len = strlen(str);
if (!mov)
return;
mov %= len; // 修移動次數
if (!mov)
return;
int i = mov;
int j = len - mov;
while (i != j) {
if (i > j) {
swap_string(str, mov-i, mov, j);
i -= j;
}
else {
swap_string(str, mov - i, mov - i + j, i);
j -= i;
}
}
swap_string(str, mov-i, mov, i);
}
/*********************** 最節約空間和時間的方法之二 ************************/
/*********************** 最節約空間和時間的方法之三 ************************/
/**
* @brief 將字串str中從start開始至end結束的字元進行逆轉
* @param str 待逆轉部分字元的字串
* @param[in] start 開始的位置
* @param[in] end 結束的位置
* @return 無
*/
void reverse(char *str, int start, int end)
{
char *pos1 = str + start;
char *pos2 = str + end;
char tmp;
while (pos1 < pos2) {
tmp = *pos1;
*pos1 = *pos2;
*pos2 = tmp;
pos1++;
pos2--;
}
}
/**
* @brief 利用逆轉的方法對字串進行向左旋轉(迴圈左移)
* @param str 待旋轉的字串
* @param[in] mov 需要旋轉的數量
* @return 無
*/
void move_string_reverse_left(char *str, int mov)
{
if (NULL == str || mov <= 0)
return;
int len = strlen(str);
if (!mov)
return;
mov %= len; // 修移動次數
if (!mov)
return;
reverse(str, 0, mov-1);
reverse(str, mov, len-1);
reverse(str, 0, len-1);
}
/*********************** 最節約空間和時間的方法之三 ************************/
/** @} */
#if 1
int main(int argc, char **argv)
{
char str[] = "Hello World!";
int n = atoi(argv[1]);
int i;
move_string_reverse_left(str, n);
printf("%s\n", str);
return 0;
}
#endif