### 问题描述
从2开始到n-1都不能整除则为素数。
### 优化
1. 从2到sqrt(n)不能整除就可以
1. 通过对被2、3和5整除的特殊检验,避免了近3/4的开方运算,其次,只考虑奇数作为可能的因子,在剩余的数中避免了大约一半的整除检验(注意一点,2,3,5本身也是素数)(If( n%2 == 0 ) return (n==2); //能被2整除且不是2本身的不是素数)
1. 用乘法运算代替开方运算
~~~
int prime(int n)
{
if(n%2==0)return (n==2);
if(n%3==0)return (n==3);
if(n%5==0)return (n==5);
for(int i=7; i*i<=n; i+=2)
if(n%i==0)return 0;
return 1;
}
~~~
### 简单的埃氏筛法
实现简单的埃氏筛法(Sieve of Eratosthenes)来计算所有小于n的素数。这个程序的主要数据结构是一个n比特的数组,初始值都为真。每发现一个素数时,数组中所有这个素数的倍数就设置为假。下一个素数就是数组中下一个为真的比特。
### 解析
下面的C程序实现了埃氏筛法来计算所有小于n的素数。其基本数据结构是n比特数组x,初始值全部为1。每发现一个素数,数组中所有它的倍数都设为0。下一个素数就是数组中的下一个取值为1的比特位。
~~~
#include
using namespace std;
int main( ){
int i, p, n;
char x[100001];
n = 100000;
for (i = 1; i <= n; i++)
x[i] = 1;
x[1] = 0; //1不是素数
p = 2; //第一个素数
while (p <= n){
cout<
';
块变换(字符反转)
最后更新于:2022-04-01 21:40:31
### 问题描述
前面有两节提供了不同方法解决关于将一个具有n个元素的一维向量向左旋转i个位置。即:***[旋转交换](http://blog.csdn.net/utimes/article/details/8762497)***和***[J](http://blog.csdn.net/utimes/article/details/8759966)****[uggling算法](http://blog.csdn.net/utimes/article/details/8759966)*。本节,提出另一种方案,块变换解决此问题。
(来源于**《编程珠玑》第2版**的第2章第11页问题B)
请将一个具有n个元素的一维向量向左旋转i个位置。例如,假设n=8,i=3,那么向量abcdefgh旋转之后得到向量defghabc。简单编码使用一个具有n个元素的中间向量分n步即可完成此作业。你可以仅使用几十字节的微小内存,花费与n成比例的时间来旋转该向量吗?
### 解析
直观的想法:由于要对数组整体向左循环移动k位,那么我们就可以对数组中的每一个元素向左移动k位(超过数组长度的可以取模回到数组中),此时总是能获得结果的。如原串 01234567结果:34567012。观察结果,直接的想法,我们能不能直接把待移动的串直接后面(0123456789 -- 7893456012)。此时,012是正确的位置了,但是其他元素还需调整。但是我们可以看到,把7893456变成3456789也需要向左循环移3位,这和第一步的变化是一样的,可以用递归做。
**原理:**将待旋转的向量x看成是由向量a和b组成的,那么旋转向量x实际上就是将向量ab的两个部分交换为向量ba
**步骤**:假设a比b短(谁长,谁分成两部分)
1)将b分割为bl和br两个部分,使得br的长度和a的长度一样
2)交换a和br,即ablbr转换成了brbla。通过本次变换,序列a就位于它的最终位置了。
3)我们需要集中精力交换b的两个部分了,这个时候就回到了最初的问题上了,我们可以递归地处理b部分。
举例:待旋转字符串"0123456789",向左移动3位
原串: 0123456789结果:3456789012
第一步: 把**b**分成**bl**和**br**两部分
**a b**
**012** 3456789 ->**012**3456789(3456是一部分,789是一部分)
第二步: 把**a**与**br**交换
**br bl a**
789 3456 012 (此时,012就是自己的最终的位置)
第三步: 之后可以递归处理 789 3456(**a**代表789,**b**代表3456)
----------------------------------------------------------
全部过程
待旋转序列:0123456789 结果:3456789012
红色表示已排好,绿色表示分的第一部分,黑色表示分的第二部分
第一步:7893456012
第二步:4563789012
第三步:3564789012
第四步:3465789012
第五步:3456789012
### 程序代码
~~~
#include
#include
using namespace std;
// 函数作用:把两块数据互换
// arr:待翻转的字符串,aStart:第一块内容的起始位置,bStart:第二块内容的起始位置,len:交换的长度
void swap(char* arr,int aStart,int bStart,int len){
assert(arr != NULL && aStart >= 0 && bStart >= 0 && len > 0);
char tmp;
while(len-- > 0){
tmp = arr[aStart];
arr[aStart] = arr[bStart];
arr[bStart] = tmp;
aStart++;
bStart++;
}
//cout< rightLen) {
swap(str,leftStart,leftStart+leftLen,rightLen);
Rotate(str,leftStart +rightLen,len-rightLen,len-2*rightLen);
}
else {
swap(str,leftStart,leftStart+len-leftLen,leftLen);
Rotate(str,leftStart,len-leftLen,leftLen);
}
}
void LeftRotateString(char* str,int k){
Rotate(str,0,strlen(str),k);
}
int main( ){
char str[60] = "abcdefghi";
LeftRotateString(str,3);
cout<
';
旋转交换或向量旋转
最后更新于:2022-04-01 21:40:29
### 问题描述
(来源于**《编程珠玑》第2版**的第2章第11页问题B)
请将一个具有n个元素的一维向量向左旋转i个位置。例如,假设n=8,i=3,那么向量abcdefgh旋转之后得到向量defghabc。简单编码使用一个具有n个元素的中间向量分n步即可完成此作业。你可以仅使用几十字节的微小内存,花费与n成比例的时间来旋转该向量吗?
### 解决思路
### 方案一:
将向量x中的前i个元素复制到一个临时数组中,接着将余下的n-i个元素左移i个位置,然后再将前i个元素从临时数组中复制回x中的后面位置。该方案使用了i个额外的位置,如i足够大,过于浪费空间。
~~~
#include
void Rotate(char *a, int length, int i) {
char tmp[10];
int step = i % length;
if (step == 0) {
return;
}
int j = 0;
for (j = 0; j < step; j++){
tmp[j] = a[j];
}
tmp[step] = '\0';
for (j = step; j < length; j++){
a[j -step] = a[j];
}
while((a[length - step + j] = tmp[j]) != '\0'){
j++;
}
}
void main() {
char a[9] = "abcdefgh";
Rotate(a,8,3);
printf("%s",a);
}
~~~
### 方案二:
定义一个函数来将x向左旋转一个位置,然后调用该函数i次。该方案需要将数组移到i将,过于浪费时间。
### 方案三:
先将x[0]移临时变量t中,然后将x[i]移到x[0]中,x[2i]移到x[i]中,依次类推,直到我们又回到从x[0]中提取元素,不过在这时我们要从t中提取元素,然后结束该过程。当i=3,n=12时,该阶段将以下面的次序移到各个元素。
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/8ad043a1fbf8ab77b127a5b20c318b09_361x138.jpg)
如果该过程不能移动所有的元素,那么我们再从x[1]开始移动,一直依次进行下去,直到移动了所有的元素时为止。
该方案过于精巧,像书中所说的一样堪称巧妙的杂技表演,非常容易出错。
### 方案四:
旋转向量x实际上就是将向量ab的两个部分交换为向量ba,这里a代表x的前i个元素。假设a比b短。将b分割成bl和br,使br的长度和a的长度一样。交换a和br,将ablbr转换成brbla。因为序列a已在它的最终位置了,所以我们可以集中精力交换b的两个部分了。由于这个新问题和原先的问题是一样的,所以我们以递归的方式进行解决。
该方案要求编码细腻,还需要深思熟虑,以确保程序具有足够的效率。
### 方案五:
[最佳]
将这个问题看作是把数组ab转换成数组ba吧,但同时也假定我们具有在数组中转置指定部分元素的函数。我们先从ab开始,转置a得到arb,再转置b得到arbr,然后再转置整个arbr得到(arbr)r,实际上就是ba。
~~~
reverse(0, i-1) /*cbadefgh*/
reverse(i, n-1) /*cbahgfed*/
reverse(0, n-1) /*defghabc*/
~~~
该转置代码在时间和空间上都很有效,并且是这么简短和简单,想出错都很难。
书中还提供了将10个元素的数组向上旋转5个位置的手摇法例子:先是掌心对着你自己,左手在右手上面,如图所示
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/75d51204d2a69e41dffd8d9fcd0d4f4c_740x281.jpg)
### 代码实现
~~~
#include
void swap(int *p, int *q);
void reverse(int *vector, int index_begin, int index_end);
void revrot(int *vector, int len, int step);
int main(int argc, char **argv){
int step = 3;
int i = 0;
int vector[1024] = {1,2,3,4,5,6,7,8};
revrot(vector, 8, step);
printf("after revolve: ");
for(i = 0; i < 8; i++){
printf("%d ", vector[i]);
}
printf("\n");
}
void swap(int *p, int *q){
int temp;
temp = *p;
*p = *q;
*q = temp;
}
void reverse(int *vector, int index_begin, int index_end){
while(index_begin < index_end){
swap(vector + index_begin, vector + index_end);
index_begin++;
index_end--;
}
}
void revrot(int *vector, int len, int step){
reverse(vector, 0, step - 1);
reverse(vector, step, len - 1);
reverse(vector, 0, len - 1);
}
~~~
**转载请注明出处**:[http://blog.csdn.net/utimes/article/details/8762497](http://blog.csdn.net/utimes/article/details/8762497)
';
快速排序
最后更新于:2022-04-01 21:40:26
在编程珠玑一书对快速排序讲得较为透彻,最早的快排是单向的,慢慢演化成双向的,也就是目前的版本。从此书能看到这种演化的必要性。我想在这里,对其原理搞懂了就不会忘了(^_^)。
### 快速排序思想
1962年,由C.A.R.Hoare创造出来。该算法核心思想就一句话:“**排序数组时,将数组分成两个小部分,然后对它们递归排序**”。然而采取什么样的策略将数组分成两个部分是关键,想想看,如果随便将数组A分成A1和A2两个小部分,即便分别将A1和A2排好序,那么A1和A2重新组合成A时仍然是无序的。所以,我们可以在数组中找一个值,称为key值,我们在把数组A分解为A1和A2前先对A做一些处理,让小于key值的元素都移到其左边,所有大于key值的元素都移到其右边。这样递归排序A1和A2,数组A就排好了。
**举例** 我们要排序的数组如下:
| 55 | 41 | 59 | 26 | 53 | 58 | 97 | 93 |
|-----|-----|-----|-----|-----|-----|-----|-----|
我们选取第一个元素作为key值,即55.(一般都是选取第一个元素)。假如我们有一种办法可以将数组做一步预处理,让小于key值的元素都位于其左边,大于key值的元素都位于其右边,预处理完数组如下:
| 41 | 26 | 53 | 55 | 59 | 58 | 97 | 93 |
|-----|-----|-----|-----|-----|-----|-----|-----|
这样数组就被key值划分成了两段,A[0...2]小于key,A[4...7]大于key,可见key值本身已排好序,接下来对A[0...2]和A[4...7]分别进行递归排序,那么整个数组就排好序了。预处理做的工作再次澄清下:找一个key值,把key位放到某位置A[p],使小于key值的元素都位于A[p]左边,大于key值的元素都位于A[p]的右边。到此,我们的快排模型就成型了。
~~~
//s, u 代表待排序部分的下界和上界
void qsort(s, u){
//递归结束条件是待排序部分的元素个数小于2
if(s >= u) {
return;
}
//此处进行预处理,预处理后key值位于位置p
qsort(s, p-1);
qsort(p+1, u);
}
~~~
接下来看如何做预处理。我们选取A[0]做为key值, p作为key值的位置。我们从A[1]开始遍历后面的数组,用变量i指示目前的位置,每次找到小于key的值都与A[++p]交换。开始时p=0.
| 55 | 41 | 59 | 26 | 53 | 58 | 97 | 93 |
|-----|-----|-----|-----|-----|-----|-----|-----|
i = 1,A[i]位置为41, 即A[i] < key, swap(++p , i),即p = 1:
| 55 | 41 | 59 | 26 | 53 | 58 | 97 | 93 |
|-----|-----|-----|-----|-----|-----|-----|-----|
i = 2,A[i]位置为59,A[i] > key,不做任何改变。
i = 3,A[i]位置为26,A[i] < key,swap(++p, i), 即p = 2:
| 55 | 41 | 26 | 59 | 53 | 58 | 97 | 93 |
|-----|-----|-----|-----|-----|-----|-----|-----|
i = 4,A[i]位置为53,A[i] < key,swap(++p, i),p = 3:
| 55 | 41 | 26 | 53 | 59 | 58 | 97 | 93 |
|-----|-----|-----|-----|-----|-----|-----|-----|
i = 5,A[i]位置为58,A[i] > key,不做任何改变。
i = 6,A[i]位置为97,A[i] > key,不做任何改变.
i = 7,A[i]位置为93,A[i] > key,不做任何改变.结束循环。此时p为key的最终位置。还需一步把key值填入p位置。
最后swap(l, p)即把Key值放到最终位置上了。至于为什么要交换l,p的位置,可以另拿一组数据试一下:55,41,59,26,99,58,97,93。
~~~
//l, u 代表待排序部分的下界和上界
void qsort(int l, int u){
//递归结束条件是待排序部分的元素个数小于2
if(l >= u) return;
int p = l;
for(int i = l+1; i <= u; i++) {
if(A[i] < A[l])
swap(++p, i);
}
swap(l, p);
qsort(l, p-1);
qsort(p+1, u);
}
~~~
这就是第一代快速排序算法,正常情况下其复杂度为nlogn,但在考虑一种极端情况:n个相同元素组成的数组。在n-1次划分中每次划分都需要O(n)的时间,所以总的时间为O(n^2)。使用双向划分就可以避免这个问题。
### 双向划分快速排序
~~~
/*l, u 代表待排序部分的下界和上界*/
void qsort(int l, int u){
/*递归结束条件是待排序部分的元素个数小于2*/
if(l >= u) return;
key = A[l]
for(int i = l, j = u+1; i <= j; ) {
do i++ while(i <= u && A[i] < key));
do j-- while(A[j] > key);
if(i > j)
break;
swap(i, j);
}
swap(l, j);
qsort(l, j-1);
qsort(j+1, u);
}
~~~
**转载请注明了出处**:[http://blog.csdn.net/utimes/article/details/8762451](http://blog.csdn.net/utimes/article/details/8762451)
';
约瑟夫环解法
最后更新于:2022-04-01 21:40:24
### 问题描述
设有n个人围坐一圈并按顺时针方向从1到n编号,从第s个人开始进行1到m的报数, 报数到第m个人, 此人出圈, 再从他的下一个人重新开始1到m的报数,如此进行下去直到所有的人都出圈为止。现要求按出圈次序,给出这n个人的顺序表p。请考生编制函数Josegh()实现此功能并调用函数WriteDat()把编号按照出圈的顺序输出到OUT.DAT文件中。设 n = 100, s = 1, m = 10进行编程。
### 解析
约瑟夫环有好多种解法,但是大体的可以分为两类:1. 将符合出圈要求的人进行标注,但是不出圈,只是下次再轮到此人时,直接跳过,不参加报数2. 将符合出圈要求的人直接出圈(从环中删除),剩下的人继续报数。这里列的是第二种方法,删除的方法是把该元素放到数组中的最后一个位置上,在出圈元素的后边的元素,都向前移动一位。
### 实现如下:
~~~
void Josegh(void)
{
int i;
int count;//count当做数数的变量
int people=n;//定义没有出圈的人数
int tem;//存放出圈人的编号
int j;
//为这100个人进行编号
for(i=0;i
1) {
i=i%people;//已经出圈人的下标不再计算之内,也就是说数到数组中最后一个没有出圈的编号的时候,i重新指向0
count=count%m;//count数到9的时候再从零开始数
//count数到10的时候count的值为0,执行下面的if语句
if(count==0){
//下面的循环将出圈的人之后的编号往前移动一位,出圈的人的编号放在p数组中的最后一位,视为出圈,同时人数减少一个
tem=p[i];
for(j=i;j
';
产生不重复的随机数
最后更新于:2022-04-01 21:40:22
我们在前几节,介绍了一篇三种方案解决**如何生成位于0到n-1之间的k个不同的随机顺序的随机整数?**[[请点击](http://blog.csdn.net/utimes/article/details/8761541)],本节则基于上述中,拓展如下所示的问题,然后,给出几个方案。
### 问题描述
产生[0, n) 范围内不重复的随机数。
### 方案一:Knuth 的S方案
有一个结论:从r中等概率的选出s个,某一个被选中的概率为s/r。证明:从r中选出s个有C(r, s)种情况,其中C(r, s)表示组合。同理,若要选定某项比如t,则需要从生下的(r-1)项中,选择(s-1)项,有C(r-1, s-1)种情况。则从r项中选择s项,t被选中的概率为 P = C(r-1, s - 1) / C(r, s) ;另一方面有排列组合的性质知,C(r,s) = r!/( s! *(r-s)! ) 则有
C(r - 1, s - 1) = (r-1)!/( (s-1)! * (r-s)! ) = s/r * r/s * (r-1)!/( (s-1)! * (r-s)! )
= s/r * r*(r-1)! / ( s*(s-1)! * (r-s)!) = s/r * r!/( s! *(r-s)! ) = s/r * C(r, s)
故有P = s/r
伪代码
~~~
for i = [0, n)
if bigrand()%r < s then
print i
--s;
--r;
~~~
例如n=5, m =2, 那么选第一个元素的概率就是2/5,如果选上了那么选第二个元素概率就是1/4,否则选择第二个元素的概率就是2/4
~~~
void gen_knuth(int n, int m){
for(int i = 0; i < n; i ++){
if(big_rand()%(n-i) < m){
cout << i;
m--;
}
}
cout<< endl;
}
~~~
### 方案二:Knuth 置换方法P
首先用一个数组顺序存储[0, n)的数据,然后随机交换任意两个下标的元素,最终取其最初的m个,记得到m个不同的随机数。
~~~
for i = [0, n)
x[i] = i;
for i = [0, m)
swap(i, randint(i, n-1))
~~~
### 方案三:蓄水池方法
蓄水池方法用以解决n很大或者n实现不可知的情况。将k看成水池容量,n = length(S)看成一个事先未知的集合S的大小
~~~
array R[k]; // result
integer i, j; // fill the reservoir array
for each i in 1 to k
do R[i] := S[i] done; // replace elements with gradually decreasing probability
for each i in k+1 to length(S)
do j := random(1, i); // important: inclusive range
if j <= k then
R[j] := S[i]
fi
done
~~~
个人的理解是,若文档非空(至少有一行),则先记下该行,然后看文档是否读完,若没有(对应着 while more input lines),当前行是第k行,则以1/k的概率(相当于把1到k行放在一起,等概率选择)决定是否用第k行替换上次的选择的结果。一次类推,最终array R[1] 中存储的一个[0, n)的随机
';
二分搜索
最后更新于:2022-04-01 21:40:20
### 问题描述
(来源于**《编程珠玑》第2版**的第2章第11页问题A)
Given a sequential file that contains at most four billion 32-bit integers in random order, find an integer that isn't in the file (and there must be at least one missing -- why?). How would you solve this problem with ample quantities of main memory ? How would you solve it if you could use several external "scratch" files but only a few hundreds bytes of main memories ? [译]给定一个包含40亿个随机排列的顺序文件,找到一个不在文件中的32位整数,在有足够内存的情况下应该如何解决该问题?如果有几个外部的临时文件可用,但是仅有几百字节的内存,又该如何解决?如有足够内存,完全可用第一章介绍的位图方法解决。这里关注内存不足时的解决方案。
### 基本思想
二分搜索(binary search)又称折半查找,它是一种效率较高的查找方法。二分查找要求:1)必须采用顺序存储结构; 2)必须按关键字大小有序排列。优缺点:折半查找法的优点是比较次数少,查找速度快,平均性能好;其缺点是要求待查表为有序表,且插入删除困难。 因此,折半查找方法适用于不经常变动而查找频繁的有序列表。充分利用了元素间的次序关系,采用分治策略,可在最坏的情况下用O(log n)完成搜索任务。
首先,将表中间位置记录的关键字与查找关键字比较, 如果两者相等,则查找成功; 否则利用中间位置记录将表分成前、后两个子表, 如果中间位置记录的关键字大于查找关键字,则进一步查找前一子表,否则进一步查找后一子表。重复以上过程,直到找到满足条件的记录,使查找成功,或直到子表不存在为止,此时查找不成功。将n个元素分成个数大致相同的两半,取a[n/2]与欲查找的x作比较,如果x=a[n/2]则找到x,算法终止。如果x
a[n/2],则我们只要在数组a的右半部继续搜索x。
二分搜索法的应用极其广泛,而且它的思想易于理解。第一个二分搜索算法早在1946 年就出现了,但是第一个完全正确的二分搜索算法直到1962年才出现。Bentley在他的著作《Writing Correct Programs》中写道,90%的计算机专家不能在2小时内写出完全正确的二分搜索算法。问题的关键在于准确地制定各次查找范围的边界以及终止条件的确定,正确地归纳奇偶数的各种情况,其实整理后可以发现它的具体算法是很直观的。
**分析**
对于32位的整数,可以表示的整数个数为2^32 = 4 294 967 296 > 4e9(40亿),因此有些数据不在该文件中。部分呼号约定:设存有40亿数据的文件为F,其中每个数据均为32bit,不在该文件中的数据集合为M(just think about the word missing for a while)。F 中的数据和M中的数据一起构成32比特能够表示的所有数据,即|F| + |M| = 2^32。从F中各数据的最高位比特开始,按其为0或者1分为两部分,假设分别为A、B,则A、B的大小有两种情况:
1) A和B中的数据个数相同。[由于|F| < 2^32,则|A| = |B| = |F|/2 < 2^31,]由于最初的数据文件F不包含数据M,则A、B均不包含M中的数据,即A、B中均缺失32比特能够表示的”部分数据“(即M中的数据),此时随便找一个文件,比如A,设定其为新的F,同时假设A中缺失的数据为新的M(也就是先前M中以0开头的数据,由于A 是以0开头的数据,事实上M当然是未知的),然后按照次高位比特进行划分。
2) A和B中的数据个数不同。假设A的个数多余B中的个数,即|A| > |B|,不能确定A中是否缺失数据,因为A完全可能包含以0开头的所有数据,这样A就不缺失数据。但是可以确定的是B一定缺失数据,否则|B| = 2^31,总数为40亿(小于2^32),导致A中的数据小于2^31,进而少于于B中的数据个数,与开始处的假设矛盾。令B为新的F,B中缺失的数据位新的M(即M中以1打头的数据,这也是由于B是以1开始的)。
通过上述最高位比特的分析后,可以得到一个文件F,其数据规模不超过N/2,其中N位F中的所有数据。同时可知有些数据不在文件F中,仅在M中。接着按第二位比特的信心对F进行上述的A、B分类,A是F中第二位比特为0的数据,B是F中第二位比特为1的数据。也能得出A、B中数据个数的信息。
1、若|A| = |B|,即A、B缺失数据,令F为A即可,继续。
2、若|A| != |B|,假设|A| > |B| ,则B缺失数据,令F为B,继续。
可以得到新的F其规模不超过N/4,继续A、B分类
### 示例模拟:
一大堆的文字描述不好理解,下面以一组4bit数字模拟一下上面的过程:4bit共可表示2^4 = 16个整数,假设初始文件F如下:
~~~
0 0000
1 0001
3 0011
4 0100
5 0101
6 0110
7 0111
8 1000
9 1001
11 1011
12 1100
13 1101
14 1110
15 1111
~~~
前面一列为10进制数,可以看到文件中缺失了0010(2),1010(10)。
### 第一次分解文件
A文件只包含0xxx的数:(x为未探索的位)
~~~
0 0000
1 0001
3 0011
4 0100
5 0101
6 0110
7 0111
~~~
B文件只包含1xxx的数:
~~~
8 1000
9 1001
11 1011
12 1100
13 1101
14 1110
15 1111
~~~
按照上面的分析,|A|=|B|=7 < 2^3 ,都有数据缺失,随机选取A文件为新的文件F。
### 第二次分解文件
A文件只包含00xx的数:
~~~
0 0000
1 0001
3 0011
~~~
B文件只包含01xx的数:
~~~
4 0100
5 0101
6 0110
7 0111
~~~
由于|A| < |B|,选取A为新的F文件。
### 第三次分解文件
A文件只包含000x的数据:
~~~
0 0000
1 0001
~~~
B文件只包含001x的数据:
~~~
3 0011
~~~
由于|B| < |A|,选取B为新的F文件。
### 第四次分解文件
A文件只包含0010的数据:没有数据。
B文件只包含0011的数据:0011
此时|A| < |B| ,所以缺失的数据必在A中,那么缺失的数据应该为0010,即十进制2。
### 代码
~~~
#include
#include
#define MAX_BIT 32
void file_split(FILE *srcfd, FILE *bit0fd, FILE *bit1fd, unsigned int *bit0_count,
unsigned int *bit1_count, int cur_bit);
/* binary search(0/1 search). For simplicity, ignore error checking */
int main(int argc, char**argv){
unsigned int mdata = 0;
unsigned int bit0_count = 0;
unsigned int bit1_count = 0;
unsigned int missing_num = 0xFFFFFFFF;
char mdatafn[] = "mdata.txt";
char bit0fn[] = "bit0.txt";
char bit1fn[] = "bit1.txt";
FILE *mdatafn_ptr = NULL;
FILE *bit0_ptr = NULL;
FILE *bit1_ptr = NULL;
int cur_bit = MAX_BIT;
mdatafn_ptr = fopen(mdatafn, "w+");
printf("Please input one number or input EOF to stop input:\n");
while(scanf("%u", &mdata) != EOF){
fprintf(mdatafn_ptr, "%u\n", mdata);
printf("Please input one number or input EOF to stop input:\n");
}
fflush(mdatafn_ptr);
rewind(mdatafn_ptr);
bit0_ptr = fopen(bit0fn, "w+");
bit1_ptr = fopen(bit1fn, "w+");
while(cur_bit-- > 0){
bit0_count = 0;
bit1_count = 0;
file_split(mdatafn_ptr, bit0_ptr, bit1_ptr, &bit0_count, &bit1_count, cur_bit);
if(bit0_count <= bit1_count){ /* if |A| <= |B|, select A as new metadata */
printf("the missiong data's %d bit is 0.\n", cur_bit+1);
missing_num &= (~(1<
';