编程珠玑-第二章旋转算法篇
来源:互联网 发布:淘宝哪里卖二手东西 编辑:程序博客网 时间:2024/05/18 17:26
这个算法在执行gcd(i,n)次后就停止了,为什么? 先来了解一点数论知识(以下内容摘自《初等数论》,潘承洞著):
1 同余:
设m不等于0, 若m|a-b,即 a-b=km, 则称m为模,a同余于b模m,以及b是a对模m的剩余。记作
<!--[if !msEquation]--> <!--[endif]-->。
2 同余类
对给定的模m,有且恰有m个不同的模m的同余类,他们是
0 mod m,1 mod m,…,(m-1)mod m。
3 完全剩余系
一组数y1,y2,…,ys称为是模m的完全剩余系,如果对任意的a有且仅有一个yj是a对模m的剩余,即a同余于yj模m。
由此可见0,1,2,…,m-1是一个完全剩余系。因此,如果m个数是两两不同余的,那么这m个数便是完全剩余系。
基于以上知识,我们可以证明这样一个事实,即如果i和n互质的话,那么序列:
0 i mod n 2i mod n 3i mod n …. (n-1)*i mod n
就包括了集合{0,1,2 … n-1}的所有元素。(下一个元素(n)*i mod n 又是0)
为什么?
证明:
由于0,1,2,…,n-1本身是一个完全剩余系,即它们两两互不同余。设此序列为Xi(0<=i<=n-1),可得下式:
Xi≠Xj (mod n),
由于i与n是互质的,所以
Xi*i ≠i*Xj (mod n),这里由于不能打出不同余字符因此用不等于替代,因此i*Xi是m个互不同余数,那么可断定它们是完全剩余系。有了上面的结论,那么如果i和n互质,下面的赋值过程便能完成所有值的赋值(设数组为X[0..n-1],长度为n):
t = X[0]
X[0] = X[i mod n]
X[i mod n] = X[2i mod n]
…….
X[(n-2)*i mod n] = X[(n-1)*i mod n]
X[ (n-1)*i mod n] = t。
因为以上操作已经把包括{0,1,…,n-1}所有元素放到了最终位置上,每次完成一个元素的放置。根据以上我们得到了一个中间结论,如果i和n互质,我们就可以一次完成。那么如果i和n不是互质的呢? 自然的想法是利用我们已经得到的结论,让i和n互质,即让i’ = i/(gcd(i,n)),n’ = n/(gcd(i,n))。这样便构造了一对互质的数, i’和n’。这意味着把整个数组的每g=gcd(i,n)个元素组成块,如下所示:
这样,根据已得结论,我们可以一次获得最终答案,因为i’和n’互质,由于我们的单位是块元素,所以,必须要g次来完成块的移动,每次相当于把g中的一个元素移到最终位置上。所以总共需要g次移动,算法终止。□ 整个证明过程最巧妙的地方在于对i和n进行处理的时候,以及处理之后转换成块元素的这个地方,感觉很巧妙,这样的证明绝对秒杀什么陪集数目的说法,回味无穷。
下面是我的实现:
#include <stdio.h>int gcd(int i, int n){ while(i != n){ if(i > n) i -= n; else n -= i; } return i;}template<class T>void turnleft(T a[],int i,int n){int count = gcd(i,n);for(int var =0;var<count;var++){T temp = a[var];int first = var;while(1){int second = (i+first)%n;if(second==var)break;a[first] = a[second];first = second;printf("%s\n",a);}a[first] = temp;printf("%s\n",a);}}int main(){char a[9] = "abcdefgh";turnleft(a,3,8);//for(int i=0;i<8;i++)//printf("%c",a[i]);printf("%s\n",a);return 0;}
2:转置算法。
这种算法比较直观,容易理解。应用的话,代码正确率也高些。
#include <stdio.h>template <typename T>void Swap(T a[],int l,int r,int interval){for(int i=0;i<interval;i++){T temp = a[l+i];a[l+i] = a[r+i];a[r+i] = temp;}}template <typename T>void swap_block(T a[],int interval,int n){if((interval==0)||(interval==n))return ;int i;int p = i = interval;int j= n-interval;while(i!=j){if(i>j){Swap(a,p-i,p,j);i-= j;}else{Swap(a,p-i,p+j-i,i);j-=i;}//printf("%s\n",a);}Swap(a,p-i,p,i);//printf("%s\n",a);}int main(){char a[] = "abcdefgh";swap_block(a,3,8);printf("%s\n",a);return 0;}
感想:总觉得在算法面前,智商不够用,大牛们究竟是什么样的脑袋,虽然觉得算法这东西很大程度上就是熟能生巧的过程,但是如何思考,如何在不看帮助的情况下,自己做出一些有意义的见解,想法。看来有必要什么时候的去看看波西亚的《如何解题》这本书,提高提高。不过,其实现在慢慢的抓住细节,弄懂没一点知识,多少有了点感觉。加油!
- 编程珠玑-第二章旋转算法篇
- 编程珠玑第二章旋转算法
- 向量旋转算法《编程珠玑》第二章笔记
- rotate旋转分析(编程珠玑第二章)
- 编程珠玑 第二章 算法
- 编程珠玑--旋转算法
- 《编程珠玑》 第二章 算法 习题
- 编程珠玑第二章的算法实现
- 《编程珠玑》--第二章 啊哈!算法
- 【编程珠玑】第二章:啊哈,算法
- 变位词算法(编程珠玑第二章)
- 编程珠玑之第二章:杂耍算法
- 编程珠玑第二章习题—向量的旋转
- 编程珠玑-第二章(字符串旋转与排序)
- 编程珠玑---第二章---n元一维向量向左旋转
- 编程珠玑第二章
- 编程珠玑第二章
- 编程珠玑第二章
- Managing_A_Working_Copy
- 第十二周试验报告1
- 类的sizeof - 学习笔记
- 扑克牌英文大全
- 成就存储专家之路--存储从入门到精通
- 编程珠玑-第二章旋转算法篇
- android中ADT版本问题: java.lang.NoClassDefFoundError和conversion to dalvik format failed with error 1错误
- Android蓝牙通讯模块源码(Android蓝牙开发浅析 续)
- ArcGIS拓扑概览 .
- U盘做系统时显示“安装程序无法定位现有系统分区,也无法创建新的系统分区”的解决方法
- wifi test
- Jtree使用详细教程
- 高级串口编程
- 学习机器人