C语言程序设计经典例题总结(详解)(一)

本专辑将之前的刷题博客进行了合并和修改,有助于读者和笔者复习回顾

1.1:2023/12/4总结:走马灯数142857和高精度加法

一、走马灯数(神奇的142857)

有一个六位数,由6个不同的数字组成,该数分别乘以2,3,4,5,6将分别得到另外5个不同的六位数,并且依然是这6个数字组成的6位数。

问有几个符合条件的6位数,它们分别等于多少?

1.用一个数组统计一个整数每个数字出现的次数。

2.对于两个数组是否一样。(函数返回为1则表示一样)例题答案思路如下

#include <stdio.h>

void tj(int a[10],int n)        //统计整数n每个数字分解一维数组中 
{
    while(n!=0)            //只要n不为0 
    {
        a[n%10]++;        //对应的元素值加1,表示这个数字出现了一次 
        n=n/10;            //n缩小10倍 
    }
}

int db(int a[10],int b[10])   //对比两个一维数组是否完全相等 
{
    int flag=1;        //标志值 
    for(int i=0;i<10;i++)
        if(a[i]!=b[i])        //如果有元素值不相等 
            flag=0;            //将标志值改为0 
    return flag;
}

int main()
{
    for(int i=100000;i<=200000;i++)
    {
        int a[10]={0};        //定义含有10个元素的数组,初始值都为0 
        tj(a,i);            //将i的各个数字出现的次数,分解到数组a中 
        int flag=1;            //定义了一个标志 
        for(int j=2;j<=6;j++)        //将i分别乘以2到6 
        {
            int k=i*j;            //得到乘积 
            int b[10]={0};
            tj(b,k);            //将乘积分解到数组b中 
            if(db(a,b)!=1)        //判断数组a与数组b是否不相等 
                flag=0;
        }
        if(flag)            //标志依然为1,表明,两个数组是完全相等的 
        {
            for(int k=2;k<=6;k++)        //输出结果 
                printf("%d*%d=%d\n",i,k,i*k);
        }
    }
    return 0;    
}

我的另外的思路:

//有一个六位数,由6个不同的数字组成,该数分别乘以2,3,4,5,6将分别得到另外5个不同的六位数,并且依然是这6个数字组成的6位数。
//问有几个符合条件的6位数,它们分别等于多少?
//1.用一个数组统计一个整数每个数字出现的次数。
//2.对于两个数组是否一样。(函数返回为1则表示一样)
#include<stdio.h>
int oy(int n,int k)
{
	int a[1000]={0},b[1000]={0};
	int o=n*k,i,j;
	while(n)
	{
		i=n%10;
		a[i]++;
		n/=10;
	}
	while(o)
	{
		j=o%10;
		b[j]++;
		o/=10;
	}
	for(int l=0;l<=9;l++)
	{
		if(a[l]!=b[l])
			return 0;
	}
	return 1;
}
int main()
{
	int u=0;
	for(int k=100000;k<=999999;k++)
	{
		if(oy(k,2)&&oy(k,3)&&oy(k,4)&&oy(k,5)&&oy(k,6))
		{	
			u++;
			printf("%d",k);	
		}
	}
	printf("总共有%d个",u);
	return 0; 
}

二、高精度算法

1.求和

在做题是我们会做到比如1+1这种加法运算,但也经常会遇到几十位,甚至几百位的数字 的计算问题,也可能会遇到小数点后几十位,几百位的情况,而我们面对这样的情况下,long long 和 double 的数据范围显然是不够使用 的了(在有符号定义的情况下,int型为2的31次方减1;在无符号定义的情况下,lint型为2的32次方。)。因此这时,我们就需要是使用一个新的算法,叫做高精度算法 .

我们知道char是不用考虑精度的,所以我们就像如果对于10000000000000000000我们直接一位一位打不就行吗,每位范围为【0,9】,故我们在用高精度算法的时候输入是以字符串的形式,用字符串 模拟数字进行计算,再利用类似于数学里的竖式的形式,进行进位和错位。

以666+888为例

输入形式

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
int max(int a, int b)
{
	if(a > b)
		return a;
	return b;
}
int main()
{
	int a[1000]={0}, b[1000]={0}, c[1000] = {0};//用于计算
	char ch1[1000], ch2[1000];//创建两个字符数组来接纳输入的超级大值,c用来存放答案
	scanf("%s",&ch1);
	scanf("%s",&ch2);//获取
	int len1 = strlen(ch1), len2 = strlen(ch2);//测量
	int len3 = max(len1, len2) + 1;
	for (int i = 0; i < len1; i++)
	{
		a[len1 - i] = ch1[i] - '0';//将字符串转成数字,然后将其倒置方便计算
	}
	for (int i = 0; i < len2; i++)//同理
	{
		b[len2 - i] = ch2[i] - '0';//ASCII代码的相减
	}
	//高精度加法主体
	for (int i = 1; i <= len3; i++)
	{
		c[i] = c[i] + a[i] + b[i];//正常加法//这就是前面为什么要倒置的原因
		c[i + 1] = c[i] / 10;//进位0,1或多
		c[i] = c[i] % 10;//剩下
	}
	if (c[len3] == 0 && len3 > 0)   len3--;//判断数组最后一位是否为0,是的不输出,而且len3还应大于0(当输入为0时),否则后面不输出
	for(int i=len3;i>0;i--){
		printf("%d",c[i]);
	}
	
	
	return 0;
}

好吧,大家可以试试看,其中字符串起的作用是接受作用,而高精度算法是一位一位去算,去输出,所以都是在【0,9】不会爆精度!!

2.0打印特殊方阵

2.1.特殊方阵1-回型方阵(蛇形方阵)

首先是题目

从左上角填上 1开始,顺时针方向依次填入数字。(具体题目如下)

那其实思路很简单,我们可以将画出这个方阵看成四步完成

1.横向1234停止,然后向下

2.向下567,然后向左

3.左8,9,10然后向上

4.上去11 12然后向右(是不是跟第一步是一样的呀)

所以简单就知道要1.递推

画出这个表显然需要2.二维数组

利用这两个工具,我们不妨设一个数组b[20][20](可以再大点)

利用while函数判断

1.越界了吗?(1234到4就得停)

2.下一个数被填了没有(比如第三步12后面的1就被填了,需要判定)

那只要满足这些条件,就可以把1234....的值分别赋到相应的位置;

则此题得解

代码如下:

cpp 复制代码
//特殊矩阵1-回型矩阵
#include<bits/stdc++.h>
using namespace std;
int main()
{
	int a,y=0,k=1,x=1;//a代表我们输入的数,x是行,y是列
	int b[100][100];
	scanf("%d",&a);
	while(k<=a*a)//其实只起到一个退出的作用 
	{
		while(y<a&&!b[x][y+1])//1.越界判定变量,2.判断下一个位置有没有有填了的数;
			b[x][++y]=k++;//k++好好体会!! 第一步 ;++y,y值一开始是0,判断未触界后立马+1
						// 当y=3判定时,执行完后y=4退出 
		while(x<a&&!b[x+1][y])//此时的y已经确定在最后一排了
			b[++x][y]=k++;//第二步 
						//同理,x为什么一开始为1,第二步后面判定成功后要直接下一位,故初始值为1; 
		while(y>1&&!b[x][y-1]) 
			b[x][--y]=k++;//第三步
		while(x>1&&!b[x-1][y])
			b[--x][y]=k++; //第四步 
	} 
	for(int i=1;i<=a;i++)
	{
		for(int j=1;j<=a;j++)
			{
			printf("%d ",b[i][j]);
		}
		printf("\n"); 
	}
	return 0;	
} 

2.2特殊方阵2---魔方阵

特殊方阵2-魔方阵

魔方阵是指一个N×N矩阵(在本题中N仅为奇数,且N>1),以自然数1,2,..., N^2为元素进行填充,每个位置上分别放置一个元素,使每行、每列以及主、副对角线上的元素之和都相等。一般的构造方法如下:

  1. 将1填在第一行的中间一列。
  2. 从2开始,按照以下规则填数: a. 每个数填在上一个数的右上方。 b. 如果上一个数在第一行,则下一个数填在最后一行同一列。 c. 如果上一个数在最后一列,则下一个数填在第一列同一行。 d. 如果上一个数的右上方已经有数,则下一个数填在上一个数的正下方。
  3. 重复步骤2,直到填满所有的位置。
  4. 检查每行、每列以及主、副对角线上的元素之和是否相等,如果相等,则构造成功,否则失败。

比如输入3(即3*3的魔方阵)

图像如下:

不难发现每次1都填充在第一行中间位置

1的相对位置规律寻找:

3*3:第二个

5*5:第三个

7*7:不难推出第四个(即本身加1除以2)

注意:由于数组的排序由0开始,所以实际在运用1的列变量y=(n+1)/2后面我们需要手动减1;

再研究5*5图像

可以看见那个右上方的操作可以用

x=(x1+1)%n;表示

所以代码如下:

cpp 复制代码
//魔方阵
#include<stdio.h>
int main()
{
	int n,x=0,y=0,a[100][100]={0},i;
	scanf("%d",&n);//输入界
	y=(n+1)/2-1;
	a[0][y]=1;
	for(i=2;i<=n*n;i++)
	{
		int x1=x,y1=y;//用于找到上一个坐标
		x=(x+(n-1))%n;//向下移动两格,除尽了取余数//这里实现了在右上方
		y=(y+1)%n;//向右一格
		if(a[x][y]!=0)//如果下一个不为0,向下填充!!!!
		{
			x=(x1+1)%n;
			y=y1;
		}
		a[x][y]=i;
	}
	for(int j=0;j<n;j++)
	{
		for(int k=0;k<n;k++)
		{
			printf("%5d",a[j][k]);
		}
		printf("\n");
		
	}
	return 0;
	
	
}

如果对您有帮助,我不胜荣幸!!

3.0猜数字小游戏和冒泡排序

一点灵感代码

1.冒泡排序(数字排序)

2.猜数字

猜数字的游戏可以是随机生成一个随机数,以时间为种子,一定程度上增加了随机性,防止在某些软件中无法实现随机

后面以输入的数为基础用if判断即可

冒泡排序

随机生成一堆随机数,将其排序;;

便于理解冒泡排序的定义

cpp 复制代码
//#include<bits/stdc++.h>
//int main()
//{
//	srand(time(NULL));              //以时间为种子;
//	int a=rand()%1000,n;    //这里是使生成的随机数在0-1000之间
//	printf("欢迎来到王者猜数字!\n游戏开始!!\n请在0-1000猜一个数字:\n");
//	scanf("%d",&n);
//	while(1)
//	{
//	
//		if(n>a)
//		{
//			printf("好像有点大,往小的猜:");
//			scanf("%d",&n);
//		}
//		if(n<a)
//		{
//			printf("好像有点小,往大猜:");
//			scanf("%d",&n);
//		}
//		if(n==a)
//		{
//			printf("哈哈,猜对了,你跟我想得一样!!!");
//			break;
//		}
//	}
//	return 0;
//}


//数字排序--------便于理解冒泡排序
#include<bits/stdc++.h>//包含所有的头文件 
int main()
{
	srand(time(NULL));
	int a,b[10000],p,l=0;
	scanf("%d",&a);//输入冒泡数字量 
	for(int i=1;i<=a;i++)
	{
		b[i]=rand()%100;
	}
	printf("由于您已是vip,自动为您生成随机数:\n");
	for(int i=1;i<=a;i++)
		printf("%4d",b[i]);//%4d适合人看 
	printf("\n");
	for(int j=1;j<=a;j++)//进行几轮冒泡 
	{
		for(int k=1;k<=a;k++)
		{
			if(b[k]>b[k+1])
			{
				p=b[k];
				b[k]=b[k+1];
				b[k+1]=p;
			}
		}	
		printf("第%d轮:",j);
		for(int k=1;k<=a;k++)
		printf("%4d",b[k]);//%4d适合人看 
	printf("\n");
		
	}
} 

4.0:12/7洗牌程序以及全排列的另外一种思路

一.全排列

全排列想必大家已经不陌生了,在中我提供了一个较为简单的思路,现在我们用另外一个方式来写,两者的思维其实一样,但这个方法倾向于选择fa

先上题目

1.全排列

题目描述

输入一个数 N, 求 1到 N 的全排列。

输入格式

输入一个 N,N<12。

输出格式

输出 N 的全排列,每个数字占 4 个位置。

样例1

输入

3

输出

   1   2   3
   1   3   2
   2   1   3
   2   3   1
   3   1   2
   3   2   1

为方便我们顺便在末尾写个这个全排列的组合有多少种!!

不多说,一切都在代码里,干了!!!

cpp 复制代码
//全排列递归
#include <stdio.h>

int table[1000];  //存放一维数组
int count=0;  //记录一维数组的总数

void Change(int &a,int &b)  //将a和b进行交换
{
	int temp=a;
	a=b;
	b=temp;
}


void DispTable(int a)   //在屏幕上输出当前一维数组,函数中的a表示元素个数
{
	int i;
	for(i=0;i<=a;i++)  //输出
		printf("%d  ",table[i]);
	printf("\n");
}

void Tab(int table[],int a,int b)  //从a到b进行值的交换
{
	int i;
	if(a==b)  //交换到最后一个
	{
			DispTable(b);  //输出当前一维数组
			count++;  //一维数组总数加1
	}
	else
	{
		for(i=a;i<=b;i++)  //从a到b进行循环
		{
			Change(table[a],table[i]);  //两两交换
			Tab(table,a+1,b);  //递归调用到下一层,重复进行交换
			Change(table[a],table[i]);  //复原交换数
		}
	}
}

int main()
{ 
	int i,n;
	scanf("%d",&n);
	
	for(i=0;i<n;i++)  //为一维数组赋初值
		table[i]=i+1;

	Tab(table,0,n-1);  //在0~n-1之间进行值的交换

	printf("%d\n",count);   
	return 0;
}

为了确保大家看得懂,这里举几个样例(非代码,仅用于解说)

//当n=4
Tab(table,0,3); 
for(i=a;i<=b;i++)  //从a到b进行循环
		{
			Change(table[a],table[i]);  //两两交换
			Tab(table,a+1,b);  //递归调用到下一层,重复进行交换
			Change(table[a],table[i]);  //复原交换数
		}


当i=0;
Change(table[0],table[0]);  //两两交换
Tab(table,1,3);  //递归调用到下一层,重复进行交换
Change(table[0],table[0]);  //复原交换数


当i=1;
Change(table[0],table[1]);  //两两交换
Tab(table,1,3);  //递归调用到下一层,重复进行交换
Change(table[0],table[1]);  //复原交换数

当i=2;
Change(table[0],table[2]);  //两两交换
Tab(table,1,3);  //递归调用到下一层,重复进行交换
Change(table[0],table[2]);  //复原交换数

当i=3;
Change(table[0],table[3]);  //两两交换
Tab(table,1,3);  //递归调用到下一层,重复进行交换
Change(table[0],table[3]);  //复原交换数

二、洗牌程序

由此我们可以写出一个类似的洗牌程序

cpp 复制代码
/洗牌程序//1000ms延迟 
#include <stdio.h>//
#include <stdlib.h>
#include <time.h>//随机数的头文件 
#include<windows.h>//Sleep函数的头文件 
void jh(int &x,int &y)//交换函数 
{	
	int temp=x;
	x=y;
	y=temp;
}
int rand1(int x,int y) //  产生x---y之间的随机数
{
	srand(time(NULL));			//随机函数初始化 
	return rand()%(y-x+1)+x;    //返回一个x-y之间的数,y-x求出相差,5-3为2,共3个数,故生成%3数为0,1,2,加上3正好在3-5之间
}
int main()
{
	int a[10]={0};
	for(int i=0;i<10;i++)
		a[i]=i;
	for(int j=1;j<=20;j++)//直接生成20组
		{
			for(int i=9;i>=1;i--)//从后面开始,观察rand1就知道为什么从后面开始
				jh(a[i],a[rand1(0,i)]);//将最后一个数与含有本身的任意一个位置交换,
			for(int i=0;i<10;i++)//打印出来
				printf("%d ",a[i]);
			printf("\n");
			Sleep(1000);//1000ms的延迟,这是为了使时间种子大一些,使生成的随机数不会出现相同的情况!!
		}
	return 0;
}

更多补充待续.....

相关推荐
机器视觉知识推荐、就业指导6 分钟前
Qt/C++事件过滤器与控件响应重写的使用、场景的不同
开发语言·数据库·c++·qt
muyierfly10 分钟前
34.贪心算法1
算法·贪心算法
孤寂大仙v14 分钟前
【C++】STL----list常见用法
开发语言·c++·list
咩咩大主教1 小时前
C++基于select和epoll的TCP服务器
linux·服务器·c语言·开发语言·c++·tcp/ip·io多路复用
时光飞逝的日子1 小时前
多重指针变量(n重指针变量)实例分析
c语言·指针·多重指针·双重指针·n重指针·指针变量
luthane3 小时前
python 实现average mean平均数算法
开发语言·python·算法
静心问道3 小时前
WGAN算法
深度学习·算法·机器学习
Ylucius3 小时前
动态语言? 静态语言? ------区别何在?java,js,c,c++,python分给是静态or动态语言?
java·c语言·javascript·c++·python·学习
是店小二呀3 小时前
【C++】C++ STL探索:Priority Queue与仿函数的深入解析
开发语言·c++·后端
杰九3 小时前
【算法题】46. 全排列-力扣(LeetCode)
算法·leetcode·深度优先·剪枝