文章目录
第四章-筛法与查找
4.1 插花游戏
笔记
函数(function)是一个具有特定的功能的、相对独立的模块,能够被多次使用。
函数设计的要素:
功能:函数的定义(definition)
模块:函数的声明(declaration)-->函数名,输入类型,输出类型
使用:函数的调用(call)
代码实现
#include <iostream>
using namespace std;
bool isPrime(int);
int main()
{
for (int n = 2; n <= 100; n++)
if (isPrime(n))
cout << n <<endl;
return 0;
}
bool isPrime(int n)
{
for (int i = 2; i*i <= n; i++)
if (n % i == 0)
return false;
return true;
}
4.2 筛法
笔记
数组定义:数组的类型,数组的名称,变量的个数;
筛法思路:埃拉托斯特尼筛法
初始化“筛子”-->枚举-->用筛子筛选
4.2.3 代码实现
#include <iostream>
using namespace std;
const int N=100;
bool seive[N+1];
int main()
{
for (int i = 2; i <= N; i++)
seive[i] = true;
for (int d = 2; d*d <= N; d++)
if (seive[d])
for (int n = d*d; n <= N; n +=d)
seive[n] = false;
for (int n =2; n <= N; n++)
if (seive[n])
cout << n <<endl;
return 0;
}
4.2.5 代码实现
#include <iostream>
using namespace std;
int main()
{
int r3 = 0, r5 = 0, r7 = 0;
int seive[200];
cin >> r3 >> r5 >> r7;
for (int i = 0; i < 200; i++)
seive[i] = 0;
for (int i = r3; i < 200; i = i + 3)
seive[i]++;
for (int i = r5; i < 200; i = i + 5)
seive[i]++;
for (int i = r7; i < 200; i = i + 7)
seive[i]++;
for (int i = 0; i < 200; i++)
if (seive[i] == 3)
cout << i <<endl;
return 0;
}
注意:循环中的 i 需要 小于 数组中变量个数,因为200个变量的数组最后一个位seive[199]
4.2.7 代码实现
#include <iostream>
using namespace std;
int main()
{
int r3 = 0, r5 = 0, r7 = 0;
cin >> r3 >> r5 >> r7;
int res = (r3 * 70 + r5 * 21 + r7 * 15) % 105;
cout << res <<endl;
return 0;
}
4.2.7 韩信点兵问题的数学理解
- 能被 5,7 除尽数是 35k,其中 k=2,即70除3正好余1,70a 除3正好余a。
- 能被 3,7 除尽数是 21k,其中 k=1,即21除5正好余1,21b 除5正好余b。
- 能被 3,5 除尽数是 15k,其中 k=1,即15除7正好余1,15c 除7正好余c。
所以
- 70a + 21b + 15c 除3正好余a。
- 70a + 21b + 15c 除5正好余b。
- 70a + 21b + 15c 除7正好余c。
所以
(70a + 21b + 15c)%(3 * 5 * 7)为最小值
以上内容摘自网络
4.3 线性查找
笔记
线性查找:扑克牌问题
初始化-->枚举-->判定查找-->找到跳出-->输出
查找最小值/最大值:
初始化-->枚举-->判定查找-->更新判定值-->输出
4.3.2 代码实现
#include <iostream>
using namespace std;
int main()
{
int cards[13] = {101,112,109,107,202,209,
213,212,313,303,403,412,402};
int pos = -1;
for (int i =0; i < 13; i++)
if (cards[i] == 112)
{
pos = i;
break;
}
if (pos != -1)
cout << "黑桃Q是第" << pos + 1 << "张牌" <<endl;
else
cout << "没找到" <<endl;
return 0;
}
4.3.4 代码实现
#include <iostream>
using namespace std;
int main()
{
int cards[13] = {101,112,109,107,202,209,
213,212,313,303,403,412,402};
int last_card = 7;
int min = 14;
int pos = -1;
for (int i =0; i < 13; i++)
if ((cards[i] % 100) > 7)
if ((cards[i] % 100) < min)
{
pos = i;
min = cards[i] % 100;
}
if (pos != -1)
cout << "比" << last_card << "大的最小牌是第"
<< pos + 1 << "张牌" <<endl;
else
cout << "没找到" <<endl;
return 0;
}
注意到,本例中有两张 9 均符合结果,判定为 小于 所以输出的是第一个符合条件的牌的位置
4.4 折半查找
笔记
已知查找目标是有序排列的
选择目标最中间的数据作为判定目标,每次判定筛选掉一半数据,所以是折半查找
初始化-->选取中间数据判定-->找到跳出,未找到更新范围-->范围内无牌-->输出
代码实现
#include <iostream>
using namespace std;
int main()
{
int target_card = 112;
int cards[13] = {101,107,109,112,202,209,
212,213,303,313,402,403,412};
int pos = -1;
int low = 0, high = 12;
while (low <= high)
{
int middle = (low + high) / 2;
if (cards[middle] == target_card)
{
pos = middle;
break;
}
else if (cards[middle] > target_card)
high = middle -1;
else
low = middle +1;
}
if (pos != -1)
cout << target_card << "是第"
<< pos + 1 << "张牌" <<endl;
else
cout << "没找到" <<endl;
return 0;
}
4.5 排序问题
笔记
插入排序:将第 i 个元素 插入 之前的数据中的比自己大的数据之前
选择排序: 选取 第 i 个之后的最小值放在 i 的位置
折半插入排序:在插入排序中,第 i 个元素之前的数据已经被排序,所以进行插入时可以使用折半查找
4.5.1 代码实现
//插入排序
#include <iostream>
using namespace std;
int main()
{
int cards[13] = {101,112,109,107,202,209,
213,212,313,303,403,412,402};
for (int i =0; i < 13; i++)
{
int pos = -1, min = 500, target = cards[i];
for (int j = 0; j < i; j++)
if(cards[j] > target)
if(cards[j] < min)
{
min = cards[j];
pos = j;
}
if (pos != -1)
{
for (int j = i; j >pos; j--)
cards[j] = cards[j - 1];
cards[pos] = target;
}
}
for (int i =0; i < 13; i++)
cout << cards[i] << " ";
cout <<endl;
return 0;
}
4.5.1 代码简化
因为第 i 个数据之前的值,已经从小到大排列过,所以当按照顺序找到的第一个比 cards[i] 大的数时,这个数肯定是期望的最小数,所以可以简化掉对 min 的处理
for (int i =0; i < 13; i++)
{
int pos = 0, target = cards[i];
while (target > cards[pos])
pos++;
for (int j = i; j >pos; j--)
cards[j] = cards[j - 1];
cards[pos] = target;
}
4.5.2 代码实现
//选择排序
#include <iostream>
using namespace std;
int main()
{
int cards[13] = {101,112,109,107,202,209,
213,212,313,303,403,412,402};
for (int i =0; i < 13; i++)
{
int min = cards[i],pos = i;
for (int j = i + 1; j < 13; j++)
if (cards[j] < min)
{
min = cards[j];
pos = j;
}
cards[pos] = cards[i];
cards[i] = min;
}
for (int i =0; i < 13; i++)
cout << cards[i] << " ";
cout <<endl;
return 0;
}
4.5.3 代码实现
//函数写法
#include <iostream>
using namespace std;
void insertsort(int cards[], int n);
void selectsort(int cards[], int n);
int main()
{
int cards[13] = {101,112,109,107,202,209,
213,212,313,303,403,412,402};
// insertsort(cards, 13);
selectsort(cards, sizeof(cards) / sizeof(int));
for (int i =0; i < 13; i++)
cout << cards[i] << " ";
cout <<endl;
return 0;
return 0;
}
void insertsort(int cards[], int n)
{
for (int i =0; i < n; i++)
{
int pos = 0, target = cards[i];
while (target > cards[pos])
pos++;
for (int j = i; j >pos; j--)
cards[j] = cards[j - 1];
cards[pos] = target;
}
}
void selectsort(int cards[], int n)
{
for (int i =0; i < n; i++)
{
int min = cards[i],pos = i;
for (int j = i + 1; j < n; j++)
if (cards[j] < min)
{
min = cards[j];
pos = j;
}
cards[pos] = cards[i];
cards[i] = min;
}
}
4.5.3 代码拓展
数组的长度,使用 sizeof() 提取数组长度,因为数组是一个 int 类型的数组,所以需要除以 sizeof(int) 才是最终的数组长度。
4.5.4 代码实现
//折半插入排序
#include <iostream>
using namespace std;
int main()
{
int cards[13] = {101,112,109,107,202,209,
213,212,313,303,403,412,402};
for (int i =0; i < 13; i++)
{
int pos = -1,target = cards[i];
int low = 0, high = i - 1;
while (low <= high)
{
int middle = (low + high) / 2;
if((cards[middle] < target) && (cards[middle + 1] > target))
{
pos = middle + 1;
break;
}
else if (cards[middle] > target)
high = middle -1;
else
low = middle +1;
}
if (pos != -1)
{
for (int j = i; j >pos; j--)
cards[j] = cards[j - 1];
cards[pos] = target;
}
}
for (int i =0; i < 13; i++)
cout << cards[i] << " ";
cout <<endl;
return 0;
}
语法自测-试题答案
本题中 i-j 为负数