学堂在线-程序设计基础-第四章

第四章-筛法与查找

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 为负数
在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值