第六章-过程封装(函数)代码实例(C++蓝豹子)

例6.7

读入一串整型数据,直到输入一个特定值为止,把这些整形数据逆序排列,输出经过重新排列后的数据,要求每个功能都用一个函数实现

思路:根据题意,分解成三个函数,分别是读入一串整数(数组,数组规模,输入结束标记),对这组整数逆序排列(数组,数组规模),输出数组(数组,数组规模),由此确定函数原型

#include <iostream>
using namespace std;

#define MAX 10

//函数原型声明
int ReadIntegerArray(int array[], int max, int flag);
void ReverseIntegerArray(int array[], int size);
void PrintIntegerArray(int array[], int size);


int main(){
	int IntegerArray[MAX], flag, CurrentSize;
	
	cout << "请输入一个结束标记(整数):";
	cin >> flag;
	
	CurrentSize = ReadIntegerArray(IntegerArray, MAX, flag);
	
	ReverseIntegerArray(IntegerArray, CurrentSize);
	
	PrintIntegerArray(IntegerArray, CurrentSize);
	
	return 0;
} 

/**
接收用户的输入 
**/ 
int ReadIntegerArray(int array[], int max, int flag){
	int size = 0;
	
	cout << "请输入数组元素,以" << flag << "结束:";
	while(size < max){
		cin >> array[size];
		
		if(array[size] == flag)
			break;
		else
			++size;
	}
	
	return size;
}

/**
对数组内容逆序排列 
**/

void ReverseIntegerArray(int array[], int size){
	int i, tmp;
	for(i=0; i<size/2; ++i){
		tmp = array[i];
		array[i] = array[size -i -1];
		array[size -i -1] = tmp;
	}
}
/**
输出数组 
**/ 

void PrintIntegerArray(int array[], int size){
	int i;
	if(size == 0) return;
	
	cout << "逆序是:" << endl;
	
	for(i=0; i<size; ++i){
		cout << array[i] << " ";
	}
}


在这里插入图片描述

例5.12 函数版本

要求统计一组正整数的和,这组正整数可以是八进制、十进制、十六进制表示,当时方法是采用字符串保存这组数字,然后从中区分出一个个正整数,代码集中在了mian函数,现在对其进行优化,将相关代码封装成函数,如:把字符串表示的不同基数的正整数转换成一个整型数;把输入的字符串字母转换成大写

#include <iostream>
using namespace std;

int convertToInt(char s[], int start);
void convertToUpper(char s[]);

int main(){
	char str[81];
	int sum = 0, i = 0;
	
	cout << "请输入一组整数,用空格分开:";
	cin.getline(str, 81);
	convertToUpper(str);
	
	while(str[i] == ' ' && str[i] !='\0') //跳过前置空格 
		++i;
	
	while(str[i] !='\0'){
		sum += convertToInt(str, i);
		while(str[i] != ' ' && str[i] != '\0') //跳过刚才已处理的i 
			++i;
		while(str[i] == ' ' && str[i] != '\0') //跳过空格 
			++i;
	}
	
	cout << "整数和为:" << sum << endl;
	
	return 0; 
}

void convertToUpper(char s[]){
	for(int i=0;s[i]!='\0';++i){
		if(s[i]>='a' && s[i]<='z'){
			s[i] = s[i] - 'a' + 'A';
		}
	}
}

int convertToInt(char s[], int start){
	int data = 0, base;
	if(s[start]!='0')
		base = 10;
	else if(s[start+1] == 'X'){
		base = 16;
		start += 2;
	}
	
	else{
		base = 8;
		++start;
	}
	
	switch(base){
		case 10:
			while(s[start]!=' ' && s[start]!='\0'){
				data = data * 10 + s[start++] - '0';
			}
			break;
		case 8:
			while(s[start]!=' ' && s[start]!='\0'){
				data = data * 8 + s[start++] - '0';
			}
			break;
		case 16:
			while(s[start]!=' ' && s[start]!='\0'){
				data = data * 16;
				if(s[start]>='A' && s[start]<='F')
					data += s[start++] - 'A' + 10;
				else
					data += s[start++] - '0';
			}
	}
	
	return data;
} 


在这里插入图片描述

利用函数模板计算两个数最大值

#include <iostream>

using namespace std;

template <class T>
T Max(T a, T b){
	return a>b ? a : b;
}

int main(){
	cout << "Max(3,5) = " << Max(3,5) <<endl;
	cout << "Max(3.3,2.5) = " << Max(3.3,2.5) <<endl;
	cout << "Max('d','r') = " << Max('d','r') <<endl;
	
	return 0;
}

在这里插入图片描述

汉诺塔问题
将n个盘子从start借助temp移动到finish

#include <iostream>
using namespace std;

void Hanoi(int n, char start, char finish, char temp);
int main(){
	Hanoi(3,'A','B','C');
	return 0; 
} 

void Hanoi(int n, char start, char finish, char temp){
	if(n==1)
		cout << start << "->" << finish << ' ';
	else{
		Hanoi(n-1, start, temp, finish);//从第一根柱子移动到第三根 
		cout << start << "->" << finish << ' ';
		Hanoi(n-1, temp, finish, start);//再从第三根柱子移动到第二根 
	}
}

在这里插入图片描述

例6.11 用递归函数打印一个十进制整数的函数定义及使用

先递归到最后打印第一位数字,然后回调,利用%不断打印最后一位

#include <iostream>
using namespace std;

void printInt(int num);


int main(){
	int num;
	
	cout << "请输入一个整数:" << endl;
	cin >> num;
	
	printInt(num);
	cout << endl;
	
	return 0;
	
} 

void printInt(int num){
	if(num < 10){ //递归终止条件 
		cout << static_cast<char>(num + '0');
	}else{
		printInt(num/10);
		cout << static_cast<char>(num%10 + '0');
	} 
}

在此基础上进一步扩展,根据输入,打印不同进制的整数

#include <iostream>
using namespace std;

void printInt(int num, int base);

static char DIGIT[17] = "0123456789abcdef";

int main(){
	int num,base;
	
	cout << "请输入一个整数:" << endl;
	cin >> num;
	cout << "请输入要打印的进制:" << endl;
	cin >> base;
	
	printInt(num, base);
	cout << endl;
	
	return 0;
	
}

void printInt(int num, int base){
	
	if(num < base)
		cout << DIGIT[num];
	else{
		printInt(num/base, base);
		cout << DIGIT[num%base];
	}
}

在这里插入图片描述

例6.12 设计函数打印n个字符的全排列

#include <iostream>
#include <string.h>
using namespace std;

void PermuteWithFixedPrefix(char str[], int k);

void swap(char str[], int k, int i);

int main(){
	int n;
	cout << "请输入n:";
	cin >> n;
	cin.get();
	
	char str[n+1];
	
	cout << "请输入" << n << "个字符:";
	
	cin.getline(str,n+1);
	
	cout << "全排列结果为:\n";
	
	PermuteWithFixedPrefix(str, 0);
	
	return 0; 
}

void  PermuteWithFixedPrefix(char str[], int k){
	int i;
	if(k == strlen(str))
		cout << str << endl;
	else{
		for(i=k; i<strlen(str); ++i){
			swap(str, k, i);
			PermuteWithFixedPrefix(str, k+1);
			swap(str, k, i);
		}
	}
}

void swap(char str[], int k, int i){
	int tmp;
	tmp = str[k];
	str[k] = str[i];
	str[i] = tmp;
}


在这里插入图片描述

例6.13 8皇后问题

思路:用一个int数组表示第i列放在col[i]行,三个一维布尔数组分别表示第i行能不能放,第i条右高左低的对角线位置能不能放,第i条左高右低的对角线位置能不能放(这个表达出来比较麻烦,需要观察一下),然后递归回溯遍历,从第1列开始放,直到放到最后一列

#include <iostream>
using namespace std;

void queen_all(int k);

int col[9];
bool row[9], digLeft[17], digRight[17];

int main(){
	int j;
	for(j=0;j<=8;j++)
		row[j] = true;
	for(j=0;j<=16;j++)
		digLeft[j] = digRight[j] = true;
	queen_all(1);
	
	return 0; 
}

void queen_all(int k){
	int i,j;
	char awn;//是否继续寻找的标记 
	
	for(i=1; i<9; i++){
		if(row[i] && digLeft[k+i-1] && digRight[8+k-i]){
			col[k] = i; //第k列的皇后放在第i行
			row[i] = digLeft[k+i-1] = digRight[8+k-i] = false;
			if(k == 8){ //找到一个可行解 
				for(j=1;j<=8;j++){
					cout << "第" << j << "列皇后" << "-" << "第" << col[j] << "行" << '\n';
				}
				cout << endl << "是否继续寻找(Q--退出,其他键继续:)";
				cin >> awn;
				if(awn == 'Q' || awn == 'q')
					exit(0);
			}else{
				queen_all(k+1);
			}
			row[i] = digLeft[k+i-1] = digRight[8+k-i] = true; //回溯 
		}
	}
}

在这里插入图片描述

例6.14 分书问题

有编号0、1、2、3、4的5本书,准备分给5个人A、B、C、D、E,每个人的阅读兴趣用一个二维数组描述:
like[i][j]=true //i喜欢书j
like[i][j]=false //i不喜欢书j
编写程序,输出所有皆大欢喜的分书方案

#include <iostream>
using namespace std;

void trynext(int i);


bool like[5][5] = {
	{
		false,false,true,true,false
	},
	{
		true,true,false,false,true
	},
	{
		false,true,true,false,true
	},
	{
		false,false,false,true,false
	},
	{
		false,true,false,false,true
	}
};
int take[5] = {-1,-1,-1,-1,-1};

int n=0;

int main(){
	
	trynext(0); 
	return 0;
	
} 

void trynext(int i){
	int j, k;
	
	for(j=0; j<5; ++j){
		if(like[i][j] && take[j]==-1){
			take[j] = i;
			if(i==4){
				n++;
				cout << "\n第" << n << "种方案:" << endl;
				cout << "书\t人" << endl;
				for(k=0;k<5;k++){
					cout << k << '\t' << char(take[k]+'A') << endl;
				} 
			}
			else{
				trynext(i+1);
			}
			
			take[j]=-1;//回溯 寻找下一方案 
		}
	} 
}

在这里插入图片描述

例6.15 快速排序

在这里插入图片描述

#include <iostream>
using namespace std;

void quicksort(int a[], int low, int high);

int divide(int a[], int low, int high);

int main(){
	
	int a[] = {5,7,3,0,4,2,1,9,6,8};
	cout << "排序前:" << "\n";
	for(int x:a){
		cout << x << " ";
	}
	cout << endl;
	quicksort(a,0,9);
	cout << "排序后:" << "\n";
	for(int x:a){
		cout << x << " ";
	} 
} 


void quicksort(int a[], int low, int high){
	int mid;
	
	if(low >= high)
		return;
	
	mid = divide(a,low,high);
	quicksort(a,low,mid-1);//排左一半 
	quicksort(a,mid+1,high);//排右一半 
	
}

//分段函数,将数组分成两段 
int divide(int a[], int low, int high){
	int k = a[low];
	while(low != high){
		while(low<high && a[high]>=k)
			--high;
		if(low<high){
			a[low] = a[high];
			++low;
		}
		while(low<high && a[low]<=k)
			++low;
		if(low<high){
			a[high] = a[low];
			--high;
		}
	}
	a[low] = k;
	return low;
}

例6.16 最大连续子序列和

如果所有整数都是负的,最长子序列和返回0

思路:可以利用分治法实现,分三种情况讨论,最大子序列和在左半部分,最大子序列和在右半部分,最大子序列和横跨左右部分,取其中的最大值

#include <iostream>
#include <limits.h>
using namespace std;

int NEGMAX = INT_MIN;

int maxSum(int a[], int left, int right);

int max3(int a, int b, int c);
int main(){
	int a[] = {4, -3, 5, -2, -1, 2, 6, -2};
	int res = maxSum(a,0,7);
	cout << "最长连续子序列和:" << res << endl;
}

int maxSum(int a[], int left, int right){
	int maxLeft,maxRight,center;
	
	int leftSum = 0, rightSum = 0;
	
	int maxLeftTmp = NEGMAX, maxRightTmp = NEGMAX; //NEGMAX最大负整数
	
	if(left == right)
		return a[left] > 0 ? a[left] : 0;
	center = (left + right) / 2;
	
	maxLeft = maxSum(a, left, center);//计算左半部分最大子序列和
	maxRight = maxSum(a, center+1, right);//计算右半部分最大子序列和
	
	//找从前半部分开始到后半部分结束的最大连续子序列和
	//从中间开始右到左遍历 
	for(int i = center; i>=left; --i){
		leftSum+=a[i];
		if(leftSum > maxLeftTmp)
			maxLeftTmp = leftSum;
	}
	
	//从中间下一个开始左到右遍历 
	for(int i = center+1; i<=right; ++i){
		rightSum+=a[i];
		if(rightSum > maxRightTmp)
			maxRightTmp = rightSum;
	} 
	
	return max3(maxLeft, maxRight, maxLeftTmp+maxRightTmp);
		 
} 

int max3(int a,int b,int c){
	int max;
	max = a>b?a:b;
	return (max>c?max:c);
}

在这里插入图片描述

例6.17 硬币找零问题

对于一种货币,有面值为C1,C2…Cn(分)的硬币,最少需要多少个硬币来找出K分钱的零钱

动态规划解法:
从1分钱开始不断构建表格,coinsUsed[j]表示找零钱j需要的最小的硬币数,初始化coinsUsed[0]=0,coins[maxChange]是最终答案

#include <iostream>
using namespace std;

void makechange(int coins[], int differentCoins, int maxChange, int coinUsed[]);

int coinsUsed[10000];
int main(){
	int coins[] = {1,5,10,21,25};
	int maxChange;
	cout << "请输入要找的零钱(单位:分):";
	cin >> maxChange;
	makechange(coins,5,maxChange,coinsUsed);
	
	cout << "找"<< maxChange << "分零钱的最少硬币数:" << coinsUsed[maxChange] << endl;
}

void makechange(int coins[], int differentCoins, int maxChange, int coinUsed[]){
	coinUsed[0] = 0;
	for(int cents = 1; cents<= maxChange; cents++){
		int minCoins = cents;//都用1分找零时硬币数最大 
		for(int j=1;j<differentCoins;j++){
			if(coins[j] > cents) //如果coins[j]大于要找的零钱则直接跳过进入下一次循环 
				continue;
			//减去当前硬币后零钱需要的最少硬币数+当前硬币
			if(coinUsed[cents - coins[j]]+1<minCoins){ 
				minCoins = coinUsed[cents - coins[j]] + 1;
			}
		}
		coinUsed[cents] = minCoins;
	}
}

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值