领会一些比较巧妙的算法
昨天看到了一些比较巧妙的算法,觉得挺不错的。
参考:http://blog.csdn.net/csdn_zc/article/details/6776929
1. 素数判断
作者给出了几种方法。
方法一:
View Code
int isPrime(int n) //函数返回1表示是质数,返回0表示不是质数
{
int i;
for (i = 2; i < n; i++)
if (n % i == 0)
return 0;
return 1;
}
{
int i;
for (i = 2; i < n; i++)
if (n % i == 0)
return 0;
return 1;
}
这个是最原始的做法:从2开始,检测数n是否能被其之前的任意一个数整除,如果能,说明其不是素数。
方法二:
View Code
int isPrime(int n)
{
int i;
for (i = 2; i*i<n; i++)
if (n % i == 0)
return 0;
return 1;
}
{
int i;
for (i = 2; i*i<n; i++)
if (n % i == 0)
return 0;
return 1;
}
对上面算法的优化是缩小搜索范围,将范围有[2,n)缩小到[2, sqrt(n)). 因为对于一个小于n的整数x,如何n不能整除x,则n必然不能整除n/x,反之,相同,所以只需到sqrt(n)即可。
方法三:
View Code
int isPrime(int n)
{
int i;
if (n <= 3) return 1;
if (n % 2 == 0) return 0;
for (i = 3; i*i<n; i += 2)
if (n % i == 0)
return 0;
return 1;
}
{
int i;
if (n <= 3) return 1;
if (n % 2 == 0) return 0;
for (i = 3; i*i<n; i += 2)
if (n % i == 0)
return 0;
return 1;
}
这个方法是删除掉偶数。因为我们知道,一个数如果不能被2整除,那么也就不能被4、6、等所有的偶数整除。所以我们可以把循环规则改变成先判断2,如果不能被2整除就从3开始判断所有的奇数。
方法四:
View Code
int isPrime(int n)
{
int i, step = 4;
if (n <= 3) return 1;
if (n % 2 == 0) return 0;
if (n % 3 == 0) return 0;
for (i = 5; i*i <n; i += step)
{
if (n % i == 0)
return 0;
step ^= 6;
}
return 1;
}
{
int i, step = 4;
if (n <= 3) return 1;
if (n % 2 == 0) return 0;
if (n % 3 == 0) return 0;
for (i = 5; i*i <n; i += step)
{
if (n % i == 0)
return 0;
step ^= 6;
}
return 1;
}
另外:如果要判断一个范围内,比如100之内的素数,我们可以这样做:从2开始判断,如果这个数不能被前面的素数整除,则这个数是素数。已经得到的素数保存在一个表格中。
View Code
void print_prime(int n)
{
int table[100];
int i,k,j;
table[0]=2;
k=1;
for(i=3;i<n;i++)
{
for(j=0;j<k;j++)
if(i%table[j]==0)
break;
if(j>=k)
table[k++]=i;
}
for(i=0;i<k;i++)
{
printf("%3d",table[i]);
if((i+1)%10==0)
printf("\n");
}
printf("\n");
}
{
int table[100];
int i,k,j;
table[0]=2;
k=1;
for(i=3;i<n;i++)
{
for(j=0;j<k;j++)
if(i%table[j]==0)
break;
if(j>=k)
table[k++]=i;
}
for(i=0;i<k;i++)
{
printf("%3d",table[i]);
if((i+1)%10==0)
printf("\n");
}
printf("\n");
}
2. 菱形打印
作者使用了坐标的思想,
我们知道,要打印的图案是这种:
*
***
*****
***
*
如果将菱形中间的点作为坐标原点的话,可以看到“*”所在的点的左边满足|x|+|y|<=c(c是菱形的边长).
*
***
*****
***
*
所以可以得到下面的代码:
View Code
#include <stdio.h>
#define ABS(x) (x<0?-(x):(x))
int main(void)
{
int i,j;
int c=2;
for(i=-c;i<=c;i++)
{
for(j=-c;j<=c;j++)
{
if(ABS(i)+ABS(j)<=c)
printf("*");
else
printf(" ");
}
printf("\n");
}
return 0;
}
#define ABS(x) (x<0?-(x):(x))
int main(void)
{
int i,j;
int c=2;
for(i=-c;i<=c;i++)
{
for(j=-c;j<=c;j++)
{
if(ABS(i)+ABS(j)<=c)
printf("*");
else
printf(" ");
}
printf("\n");
}
return 0;
}
其他的类型的形状可以使用同样的思路解决。
3. 魔方矩阵
参考:http://blog.csdn.net/cmutoo/article/details/6492895
此处的总结比较全面,大家可以看看
View Code
#include<stdio.h>
#include<math.h>
#define MAX 30
int a[MAX][MAX]; // 幻方矩阵
int n,s; // n:阶数,s:幻方数
int x,y;
int i,j,k;
int total,m;
int ox,oy;
void main()
{
void odd(int m, int index);
void singleEven();
void FourXFour();
void doubleEven();
do
{
printf("Please input n(3<=n[<=17]):\t"); // 屏幕可显示的最大阶数为17
scanf("%d",&n);
if(n<3) continue; // 幻方最小阶数
s=n*(pow(n,2)+1)/2; // 幻方数
printf("s=%d\n",s);
if(n%2==1){
// 奇阶幻方
ox=oy=0;
odd(n,0); // 从1开始填写n阶幻方
}
else if(n%4==0)
{
// 双偶阶幻方
doubleEven();
}
else if(n%2==0)
{
// 单偶阶幻方
singleEven();
}
// 输出制作好的n阶幻方
for(i=0;i<n;i++)
{
s=0;
for(j=0;j<n;j++)
s+=a[i][j],printf("%4d",a[i][j]);
printf("\t=%d\n",s);
}
fflush(stdin); // 清除多余或无效的输入
}while(1);
}
/* 奇数阶幻方
最经典的填法是罗伯特法(楼梯法),填写方法是这样:
把1(或最小的数)放在第一行正中;按以下规律排列剩下的n×n-1个数:
(1)每一个数放在前一个数的右上一格;
(2)如果这个数所要放的格已经超出了顶行那么就把它放在底行,仍然要放在右一列;
(3)如果这个数所要放的格已经超出了最右列那么就把它放在最左列,仍然要放在上一行;
(4)如果这个数所要放的格已经超出了顶行且超出了最右列,那么就把它放在前一个数的下一行同一列的格内;
(5)如果这个数所要放的格已经有数填入,处理方法同(4)。
这种写法总是先向“右上”的方向,象是在爬楼梯。
三阶幻方:
8 1 6
3 5 7
4 9 2 */
// 解奇阶幻方的通用模块
// m 为阶数
// index 为起始标识
void odd(int m, int index)
{
x=m/2;
y=0;
for(i=index+1;i<=index+pow(m,2);i++)
{
a[oy+y][ox+x]=i;
if(i%m==0) y++;
else x++,y--;
// else x++,y+=2; Hourse法
x=(x%m+m)%m;
y=(y%m+m)%m;
}
}
/* 单偶阶幻方
n为偶数,且不能被4整除 (n=6,10,14,18,22……;n=4k+2,k=1,2,3,4,5……)
以n=10为例。这时,k=2
(1) 把方阵分为A,B,C,D四个象限,这样每一个象限肯定是奇数阶。
用楼梯法,依次在A象限,D象限,B象限,C象限按奇数阶幻方的填法填数。
6阶幻方第一步:
8 1 6 | 26 19 24
3 5 7 | 21 23 25
4 9 2 | 22 27 20
-------------------------
35 28 33 | 17 10 15
30 32 34 | 12 14 16
31 36 29 | 13 18 11
(2) 在A象限的中间行、中间格开始,按自左向右的方向,标出k格。
A象限的其它行则标出最左边的k格。
将这些格,和C象限相对位置上的数,互换位置。
6阶幻方第二步:
35* 1 6 | 26 19 24
3 32* 7 | 21 23 25
31* 9 2 | 22 27 20
-------------------------
8* 28 33 | 17 10 15
30 5* 34 | 12 14 16
4* 36 29 | 13 18 11
(3) 在B象限任一行的中间格,自右向左,标出k-1列。
(注:6阶幻方由于k-1=0,所以不用再作B、D象限的数据交换)
将B象限标出的这些数,和D象限相对位置上的数进行交换,就形成幻方。
6阶幻方:
35 1 6 | 26 19* 24
3 32 7 | 21 23* 25
31 9 2 | 22 27* 20
-------------------------
8 28 33 | 17 10* 15
30 5 34 | 12 14* 16
4 36 29 | 13 18* 11 */
void singleEven()
{
int temp;
// 步骤一
// A象限
ox=oy=0;
odd(n/2,pow(n/2,2)*0);
// D象限
ox=oy=n/2;
odd(n/2,pow(n/2,2)*1);
// B象限
ox=n/2,oy=0;
odd(n/2,pow(n/2,2)*2);
// C象限
ox=0,oy=n/2;
odd(n/2,pow(n/2,2)*3);
// 对已经按ADBC象限以奇阶方式填充的幻方做处理
m=(n-2)/4;
for(i=0;i<n/2;i++)
{
// 步骤二
for(j=0;j<m;j++)
{
k=(i==n/4)?n/4+j:j;
temp=a[i][k];
a[i][k]=a[i+n/2][k];
a[i+n/2][k]=temp;
}
// 步骤三
for(j=0;j<m-1;j++)
{
k=n/2+n/4+j;
temp=a[i][k];
a[i][k]=a[i+n/2][k];
a[i+n/2][k]=temp;
}
}
}
/* 双偶阶幻方
n为偶数,且能被4整除 (n=4,8,12,16,20……;n=4k,k=1,2,3,4,5……)
互补:如果两个数字的和,等于幻方最大数和最小数的和,即 n*n+1,称为互补。*/
/* 四阶幻方
将数字从左到右、从上到下按顺序填写:
1 2 3 4
5 6 7 8
9 10 11 12
13 14 15 16
将对角线上的数字,换成与它互补的数字。
这里,n×n+1 = 4×4+1 = 17;
把1换成17-1 = 16;
把6换成17-6 = 11;
把11换成17-11 = 6;
把16换成17-16 = 1;
……
换完后就是一个四阶幻方。
16* 2 3 13*
5 11* 10* 8
9 7* 6* 12
4* 14 15 1* */
void FourXFour()
{
// 对已填写数字的4阶幻方进行对角线互补替换
for(i=0;i<4;i++)
{
a[oy+i][ox+i]=total-a[oy+i][ox+i];
a[oy+i][ox+(4-i-1)]=total-a[oy+i][ox+(4-i-1)];
}
}
/* 对于n=4k阶幻方,我们先把数字按顺序填写。
1 2 3 4 5 6 7 8
9 10 11 12 13 14 15 16
17 18 19 20 21 22 23 24
25 26 27 28 29 30 31 32
33 34 35 36 37 38 39 40
41 42 43 44 45 46 47 48
49 50 51 52 53 54 55 56
57 58 59 60 61 62 63 64
写好后,按4*4把它划分成k*k个方阵。
因为n是4的倍数,一定能用4*4的小方阵分割。
1 2 3 4 | 5 6 7 8
9 10 11 12 | 13 14 15 16
17 18 19 20 | 21 22 23 24
25 26 27 28 | 29 30 31 32
---------------------------------
33 34 35 36 | 37 38 39 40
41 42 43 44 | 45 46 47 48
49 50 51 52 | 53 54 55 56
57 58 59 60 | 61 62 63 64
然后把每个小方阵的对角线上的数字换成互补的数字,就构成幻方。
64* 2 3 61*| 60* 6 7 57*
9 55* 54* 12 | 13 51* 50* 16
17 47* 46* 20 | 21 43* 42* 24
40* 26 27 37*| 36* 30 31 33*
---------------------------------
32* 34 35 29*| 28* 38 39 25*
41 23* 22* 44 | 45 19* 18* 48
49 15* 14* 52 | 53 11* 10* 56
8* 58 59 5*| 4* 62 63 1* */
void doubleEven()
{
// 填写数字
x=y=0;
for(i=1;i<=pow(n,2);i++)
{
a[y][x]=i;
if(i%n==0) x=0,y++;
else x++;
}
total=1+pow(n,2); // 最大数和最小数的和
// 以 4x4 大小分割幻方
m=n/4;
x=y=0;
ox=oy=0;
for(k=1;k<=pow(m,2);k++)
{
// 对每个 4x4 幻方做对角互补替换
FourXFour();
if(k%m==0) ox=0,oy+=4;
else ox=k%m*4; // 转移到下一个 4x4 幻方
}
}
#include<math.h>
#define MAX 30
int a[MAX][MAX]; // 幻方矩阵
int n,s; // n:阶数,s:幻方数
int x,y;
int i,j,k;
int total,m;
int ox,oy;
void main()
{
void odd(int m, int index);
void singleEven();
void FourXFour();
void doubleEven();
do
{
printf("Please input n(3<=n[<=17]):\t"); // 屏幕可显示的最大阶数为17
scanf("%d",&n);
if(n<3) continue; // 幻方最小阶数
s=n*(pow(n,2)+1)/2; // 幻方数
printf("s=%d\n",s);
if(n%2==1){
// 奇阶幻方
ox=oy=0;
odd(n,0); // 从1开始填写n阶幻方
}
else if(n%4==0)
{
// 双偶阶幻方
doubleEven();
}
else if(n%2==0)
{
// 单偶阶幻方
singleEven();
}
// 输出制作好的n阶幻方
for(i=0;i<n;i++)
{
s=0;
for(j=0;j<n;j++)
s+=a[i][j],printf("%4d",a[i][j]);
printf("\t=%d\n",s);
}
fflush(stdin); // 清除多余或无效的输入
}while(1);
}
/* 奇数阶幻方
最经典的填法是罗伯特法(楼梯法),填写方法是这样:
把1(或最小的数)放在第一行正中;按以下规律排列剩下的n×n-1个数:
(1)每一个数放在前一个数的右上一格;
(2)如果这个数所要放的格已经超出了顶行那么就把它放在底行,仍然要放在右一列;
(3)如果这个数所要放的格已经超出了最右列那么就把它放在最左列,仍然要放在上一行;
(4)如果这个数所要放的格已经超出了顶行且超出了最右列,那么就把它放在前一个数的下一行同一列的格内;
(5)如果这个数所要放的格已经有数填入,处理方法同(4)。
这种写法总是先向“右上”的方向,象是在爬楼梯。
三阶幻方:
8 1 6
3 5 7
4 9 2 */
// 解奇阶幻方的通用模块
// m 为阶数
// index 为起始标识
void odd(int m, int index)
{
x=m/2;
y=0;
for(i=index+1;i<=index+pow(m,2);i++)
{
a[oy+y][ox+x]=i;
if(i%m==0) y++;
else x++,y--;
// else x++,y+=2; Hourse法
x=(x%m+m)%m;
y=(y%m+m)%m;
}
}
/* 单偶阶幻方
n为偶数,且不能被4整除 (n=6,10,14,18,22……;n=4k+2,k=1,2,3,4,5……)
以n=10为例。这时,k=2
(1) 把方阵分为A,B,C,D四个象限,这样每一个象限肯定是奇数阶。
用楼梯法,依次在A象限,D象限,B象限,C象限按奇数阶幻方的填法填数。
6阶幻方第一步:
8 1 6 | 26 19 24
3 5 7 | 21 23 25
4 9 2 | 22 27 20
-------------------------
35 28 33 | 17 10 15
30 32 34 | 12 14 16
31 36 29 | 13 18 11
(2) 在A象限的中间行、中间格开始,按自左向右的方向,标出k格。
A象限的其它行则标出最左边的k格。
将这些格,和C象限相对位置上的数,互换位置。
6阶幻方第二步:
35* 1 6 | 26 19 24
3 32* 7 | 21 23 25
31* 9 2 | 22 27 20
-------------------------
8* 28 33 | 17 10 15
30 5* 34 | 12 14 16
4* 36 29 | 13 18 11
(3) 在B象限任一行的中间格,自右向左,标出k-1列。
(注:6阶幻方由于k-1=0,所以不用再作B、D象限的数据交换)
将B象限标出的这些数,和D象限相对位置上的数进行交换,就形成幻方。
6阶幻方:
35 1 6 | 26 19* 24
3 32 7 | 21 23* 25
31 9 2 | 22 27* 20
-------------------------
8 28 33 | 17 10* 15
30 5 34 | 12 14* 16
4 36 29 | 13 18* 11 */
void singleEven()
{
int temp;
// 步骤一
// A象限
ox=oy=0;
odd(n/2,pow(n/2,2)*0);
// D象限
ox=oy=n/2;
odd(n/2,pow(n/2,2)*1);
// B象限
ox=n/2,oy=0;
odd(n/2,pow(n/2,2)*2);
// C象限
ox=0,oy=n/2;
odd(n/2,pow(n/2,2)*3);
// 对已经按ADBC象限以奇阶方式填充的幻方做处理
m=(n-2)/4;
for(i=0;i<n/2;i++)
{
// 步骤二
for(j=0;j<m;j++)
{
k=(i==n/4)?n/4+j:j;
temp=a[i][k];
a[i][k]=a[i+n/2][k];
a[i+n/2][k]=temp;
}
// 步骤三
for(j=0;j<m-1;j++)
{
k=n/2+n/4+j;
temp=a[i][k];
a[i][k]=a[i+n/2][k];
a[i+n/2][k]=temp;
}
}
}
/* 双偶阶幻方
n为偶数,且能被4整除 (n=4,8,12,16,20……;n=4k,k=1,2,3,4,5……)
互补:如果两个数字的和,等于幻方最大数和最小数的和,即 n*n+1,称为互补。*/
/* 四阶幻方
将数字从左到右、从上到下按顺序填写:
1 2 3 4
5 6 7 8
9 10 11 12
13 14 15 16
将对角线上的数字,换成与它互补的数字。
这里,n×n+1 = 4×4+1 = 17;
把1换成17-1 = 16;
把6换成17-6 = 11;
把11换成17-11 = 6;
把16换成17-16 = 1;
……
换完后就是一个四阶幻方。
16* 2 3 13*
5 11* 10* 8
9 7* 6* 12
4* 14 15 1* */
void FourXFour()
{
// 对已填写数字的4阶幻方进行对角线互补替换
for(i=0;i<4;i++)
{
a[oy+i][ox+i]=total-a[oy+i][ox+i];
a[oy+i][ox+(4-i-1)]=total-a[oy+i][ox+(4-i-1)];
}
}
/* 对于n=4k阶幻方,我们先把数字按顺序填写。
1 2 3 4 5 6 7 8
9 10 11 12 13 14 15 16
17 18 19 20 21 22 23 24
25 26 27 28 29 30 31 32
33 34 35 36 37 38 39 40
41 42 43 44 45 46 47 48
49 50 51 52 53 54 55 56
57 58 59 60 61 62 63 64
写好后,按4*4把它划分成k*k个方阵。
因为n是4的倍数,一定能用4*4的小方阵分割。
1 2 3 4 | 5 6 7 8
9 10 11 12 | 13 14 15 16
17 18 19 20 | 21 22 23 24
25 26 27 28 | 29 30 31 32
---------------------------------
33 34 35 36 | 37 38 39 40
41 42 43 44 | 45 46 47 48
49 50 51 52 | 53 54 55 56
57 58 59 60 | 61 62 63 64
然后把每个小方阵的对角线上的数字换成互补的数字,就构成幻方。
64* 2 3 61*| 60* 6 7 57*
9 55* 54* 12 | 13 51* 50* 16
17 47* 46* 20 | 21 43* 42* 24
40* 26 27 37*| 36* 30 31 33*
---------------------------------
32* 34 35 29*| 28* 38 39 25*
41 23* 22* 44 | 45 19* 18* 48
49 15* 14* 52 | 53 11* 10* 56
8* 58 59 5*| 4* 62 63 1* */
void doubleEven()
{
// 填写数字
x=y=0;
for(i=1;i<=pow(n,2);i++)
{
a[y][x]=i;
if(i%n==0) x=0,y++;
else x++;
}
total=1+pow(n,2); // 最大数和最小数的和
// 以 4x4 大小分割幻方
m=n/4;
x=y=0;
ox=oy=0;
for(k=1;k<=pow(m,2);k++)
{
// 对每个 4x4 幻方做对角互补替换
FourXFour();
if(k%m==0) ox=0,oy+=4;
else ox=k%m*4; // 转移到下一个 4x4 幻方
}
}
#include<stdio.h>
View Code
function M = magic(n)
%MAGIC Magic square.
% MAGIC(N) is an N-by-N matrix constructed from the integers
% 1 through N^2 with equal row, column, and diagonal sums.
% Produces valid magic squares for all N > 0 except N = 2.
% Copyright 1984-2002 The MathWorks, Inc.
% $Revision: 5.15 $ $Date: 2002/04/15 03:44:23 $
% Historically, MATLAB's magic was a built-in function.
% This M-file uses a new algorithm to generate the same matrices.
n = floor(real(double(n(1))));
% Odd order.
if mod(n,2) == 1
[J,I] = meshgrid(1:n);
A = mod(I+J-(n+3)/2,n);
B = mod(I+2*J-2,n);
M = n*A + B + 1;
% Doubly even order.
elseif mod(n,4) == 0
[J,I] = meshgrid(1:n);
K = fix(mod(I,4)/2) == fix(mod(J,4)/2);
M = reshape(1:n*n,n,n)';
M(K) = n*n+1 - M(K);
% Singly even order.
else
p = n/2;
M = magic(p);
M = [M M+2*p^2; M+3*p^2 M+p^2];
if n == 2, return, end
i = (1:p)';
k = (n-2)/4;
j = [1:k (n-k+2):n];
M([i; i+p],j) = M([i+p; i],j);
i = k+1;
j = [1 i];
M([i; i+p],j) = M([i+p; i],j);
end
%MAGIC Magic square.
% MAGIC(N) is an N-by-N matrix constructed from the integers
% 1 through N^2 with equal row, column, and diagonal sums.
% Produces valid magic squares for all N > 0 except N = 2.
% Copyright 1984-2002 The MathWorks, Inc.
% $Revision: 5.15 $ $Date: 2002/04/15 03:44:23 $
% Historically, MATLAB's magic was a built-in function.
% This M-file uses a new algorithm to generate the same matrices.
n = floor(real(double(n(1))));
% Odd order.
if mod(n,2) == 1
[J,I] = meshgrid(1:n);
A = mod(I+J-(n+3)/2,n);
B = mod(I+2*J-2,n);
M = n*A + B + 1;
% Doubly even order.
elseif mod(n,4) == 0
[J,I] = meshgrid(1:n);
K = fix(mod(I,4)/2) == fix(mod(J,4)/2);
M = reshape(1:n*n,n,n)';
M(K) = n*n+1 - M(K);
% Singly even order.
else
p = n/2;
M = magic(p);
M = [M M+2*p^2; M+3*p^2 M+p^2];
if n == 2, return, end
i = (1:p)';
k = (n-2)/4;
j = [1:k (n-k+2):n];
M([i; i+p],j) = M([i+p; i],j);
i = k+1;
j = [1 i];
M([i; i+p],j) = M([i+p; i],j);
end
4.字符串循环移位
问题,给你一个字符串,要求循环左移n位
比如对"abcdefg" 循环左移2位,我们要得到"cdefgab"
附加条件,不能使用连续辅助空间(包括动态分配),只能使用若干单个变量(即O(1)空间)
首先,我们知道,反转一个字符串操作("abcd"变"dcba"),是不需要额外数组辅助的,只要头尾数据交换就可以了
然而,可能你不知道,仅仅使用字符串反转可以实现字符串循环移位:
附加条件,不能使用连续辅助空间(包括动态分配),只能使用若干单个变量(即O(1)空间)
首先,我们知道,反转一个字符串操作("abcd"变"dcba"),是不需要额外数组辅助的,只要头尾数据交换就可以了
然而,可能你不知道,仅仅使用字符串反转可以实现字符串循环移位:
View Code
#include <stdio.h>
#include <string.h>
//反转字符串,把st与ed所指向的中间的内容反转(包含st不包含ed)
void str_rev(char* st, char *ed)
{
for (--ed; st < ed; ++st, --ed)
{
char c;
c = *st;
*st = *ed;
*ed = c;
}
}
//用三反转等效左移字符串(st与ed之间,包含st不包含ed的内容)
char* str_shl(char* st, char* ed, int n)
{
str_rev(st, &st[n]);
str_rev( &st[n], ed);
str_rev(st, ed);
return st;
}
int main()
{
char str[] = "abcdefghijklmnopqrstuvwxyz";
puts( str_shl(str, str + strlen(str), 6) );
return 0;
}
#include <string.h>
//反转字符串,把st与ed所指向的中间的内容反转(包含st不包含ed)
void str_rev(char* st, char *ed)
{
for (--ed; st < ed; ++st, --ed)
{
char c;
c = *st;
*st = *ed;
*ed = c;
}
}
//用三反转等效左移字符串(st与ed之间,包含st不包含ed的内容)
char* str_shl(char* st, char* ed, int n)
{
str_rev(st, &st[n]);
str_rev( &st[n], ed);
str_rev(st, ed);
return st;
}
int main()
{
char str[] = "abcdefghijklmnopqrstuvwxyz";
puts( str_shl(str, str + strlen(str), 6) );
return 0;
}
参考:http://blog.csdn.net/csdn_zc/article/details/6776853
其中也介绍了数字循环移位的问题:
C语言中没有提供循环移位的操作符,但可以通过简洁的方式实现循环移位
设一个操作数x有s位则循环左移n位的操作为:
(x << n) | (x >> (s - n));
同理右移n位位:
(x >> n) | (x << (s - n));
实际编程中可以用宏定义实现循环移位:
#define ROTATE_LEFT(x, s, n) ((x) << (n)) | ((x) >> ((s) - (n)))
#define ROTATE_RIGHT(x, s, n) ((x) >> (n)) | ((x) << ((s) - (n)))
(x << n) | (x >> (s - n));
同理右移n位位:
(x >> n) | (x << (s - n));
实际编程中可以用宏定义实现循环移位:
#define ROTATE_LEFT(x, s, n) ((x) << (n)) | ((x) >> ((s) - (n)))
#define ROTATE_RIGHT(x, s, n) ((x) >> (n)) | ((x) << ((s) - (n)))
几个对位操作的样例如下:
#define SETBIT(REG,N) REG|=(1<<N) //对REG的N位置1
#define CLRBIT(REG,N) REG&=~(1<<N) //对REG的N位清零
#define SETBIT(REG,N) REG|=(1<<N) //对REG的N位置1
#define CLRBIT(REG,N) REG&=~(1<<N) //对REG的N位清零
#define INVBIT(REG,N) REG^=(1<<N) //对REG的N位取反