【C语言刷题】分支与循环系列

简介: 【C语言刷题】分支与循环系列

一、计算n的阶乘

1.一般解法

这道题目比较简单,下面就是我们的代码实现

#include<stdio.h>
int main()
{
  int i, ret = 1;
  int n;
  scanf("%d", &n);
  for (i = 1; i <=n; i++)
  {
    ret = ret * i;
  }
  printf("%d", ret);
}

但是我们说这还不够。因为如果我们输入的数据比较大,就很可能会发生溢出,因为int类型最多有32个比特位,也就是最大能表示2的三十二次方的大小,那么如何表达更大类型的数呢,答案是将int改为double,这样最大就可以表示2的64次方的大小了。

2.优化不能表示出较大数的阶乘

#include<stdio.h>
int main()
{
  int i;
  double ret = 1;
  int n;
  scanf("%d", &n);
  for (i = 1; i <=n; i++)
  {
    ret = ret * i;
  }
  printf("%.0f", ret);
}

计算 1!+2!+3!+……+10!

1.循环嵌套解法

这道题是第一题的一个拓展。既然我们已经有了第一道题的基础,这第二道题相信大家也应该有思路,那便是循环嵌套一层。下面是代码实现

#include<stdio.h>
int main()
{
  int i, j;
  int ret = 1;
  int sum = 0;
  for (i = 1; i <= 10; i++)
  {
    ret = 1;
    for (j = 1; j <= i; j++)
    {
      ret = ret * j;
    }
    sum = sum + ret;
  }
  printf("%d", sum);
  return 0;
}

这样确实是实现了我们的代码,但是我们说这还不够好,因为效率太低,试想一下,如果这个数很大呢,让加到100,1000呢,那这些阶乘运算中出现了大量的重复性计算,使得我们的计算出答案所需的时间增加,所以为了优化,我们可以只需使用一次for循环就可以得出答案。

2.一次循环解法(优化计算时间)

#include<stdio.h>
int main()
{
  int i;
  int ret = 1;
  int sum = 0;
  for (i = 1; i <= 3; i++)
  {
    ret = ret * i;
    sum = sum + ret;
  }
  printf("%d", sum);
  return 0;
}

这样的话,我们的时间复杂度也大大降低。时间复杂度的概念将在以后的文章中详细讲到。这里读者暂时不用深究。

三、在一个有序数组中查找具体的某个数字n

1.遍历查找

比如说我们在一个从1--10的数组中找出7,最简单的方法当然是遍历了,代码实现如下

#include<stdio.h>
int main()
{
  int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
  int k = 7;//要找它
  int i;
  int flag = 0;
  for (i = 0; i < 10; i++)
  {
    if (arr[i] == k)
    {
      printf("找到了,下标是%d",i);
      flag = 1;
      break;
    }
  }
  if (flag == 0) 
  {
    printf("找不到");
  }
  return 0;
}

但是,这效率太低了,因为我们最坏要找n次,n为数组的个数。那么有没有什么更高效的方法呢?我们说,是有的,接下来给大家介绍一个二分查找算法,也叫折半查找算法。

2.二分查找算法(优化了查找时间)

如下图所示,这是一个数组,如果我们想找到7这个元素,如何找呢?

首先我们先确定左下标和右下标,方便我们知道查找到了那个位置,此时我们所查找的范围为[left,right]这个闭区间,如下图所示

紧接着,我们引入一个中间量mid作为一个下标,mid这个数组下标为左下标与右下标之和除以2,取出商的部分,忽略掉余数。即mid=(left+right)/2,如下图所示,为第一次二分。

查找之后我们发现,arr[mid]<7,也就是说,7在arr[mid]的右侧,所以此时[left,mid]这个闭区间就不在我们的查找范围内了,我们新的查找范围为(mid,right]这个左开右闭区间,为了和前面统一,都为闭区间,我们不妨令新的区间为[mid+1,right]这个闭区间。在这个闭区间上,我们令left=mid+1,这样我们要查找的闭区间为[left,right]了,这样一来,我们就会发现,这好像可以用一个循环,通过一个循环,让它来一直执行下去,我们就能很高效的找出所需要查找的闭区间了。但是,为了大家更好的理解,我们继续画图往下执行。

上图中,这是我们第二次找出中间值的图解,为图中紫颜色部分,我们发现arr[mid]>7,那说明[mid,right]这个闭区间中没有7,于是我们所需要查找的新区间为[left,mid-1]这个闭区间。我们同样令right=mid-1,这样我们的新的需要查找的区间为[left,right]了

如上图所示,红色部分为新下标示意图,由于arr[mid]<7,所以根据上面的原理可得,[left+1,right]为新区间。我们继续进行查找。

如上图所示,此时我们的arr[mid]=7,也就是说找到了,我们就可以返回这个mid,就是我们所找到的下标。

以上就是我们二分查找算法的图解,相信大家都已经看懂了吧,有人说,那么既然这是个循环实现的,那么循环里面的条件应该填什么呢?其实很简单,我们根据上面的图解也能发现,只有left<=right时,也就是说,左下标小于等于右下标时候,因为不可能右下标小于左下标,这样我们的程序才能执行下去,这也就是我们的判断条件。

那么我们将上面的代码实现以下吧

#include<stdio.h>
int main()
{
  int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
  int k = 7;//要找它
  int left = 0;
  int right = 9;
  int flag = 0;
  int mid = 0;
  while (left <= right)
  {
    mid = (left + right) / 2;
    if (arr[mid] > k)
    {
      right = mid - 1;
    }
    else if (arr[mid] < k)
    {
      left = mid + 1;
    }
    else
    {
      printf("找到了,下标为%d", mid);
      flag = 1;
      break;
    }
  }
  if (flag == 0)
  {
    printf("找不到");
  }
  return 0;
}

四、编写代码,演示多个字符从两端移动,向中间汇聚。

1.一般解法

我们先直接给出代码

#include<stdio.h>
#include<string.h>
int main()
{
  char arr1[] = "welcome to world";
  char arr2[] = "****************";
  int left = 0;
  int right = strlen(arr2) - 1;
  while (left <= right)
  {
    arr2[left] = arr1[left];
    arr2[right] = arr1[right];
    printf("%s\n", arr2);
    left++;
    right--;
  }
  return 0;
}

在这个代码中,我们给出两个字符数组并且进行初始化,arr1是需要被慢慢显现出来的,arr2是需要被打印出来的,以此来展示出效果,我们采用和二分查找类似的思想,使用一个左下标,和一个右下标。我们右下标是直接采用一个库函数strlen计算出来的,因为计算出来的是长度,所以我们需要减1,来代表下标。然后我们逐步将arr1的数组赋值给arr2,并且打印出arr2。然后一直循环,循环条件也与二分查找类似,只需要我的左下标小于等于右下标,我就可以继续执行下去

运行截图为

但是我们可不可以对它在优化一点呢。比如说我们想要在加上两个需求,一个需求是使得它打印以此,停顿一秒钟,然后继续打印。另外一个需求是,打印一次,清屏一次呢?我们说,是可以的。在这里我们就需要使用到两个库函数了。

2.优化后的解法(提高用户体验感)

Sleep()//作用是休眠,单位是毫秒    需要调用头文件include<window.h>

system("cls") //作用是清屏,需要调用头文件include<stdlib.h>

以下就是我们最终的代码了。读者可以自行去运行

#include<stdio.h>
#include<string.h>
#include<windows.h>
#include<stdlib.h>
int main()
{
  char arr1[] = "welcome to world";
  char arr2[] = "****************";
  int left = 0;
  int right = strlen(arr2) - 1;
  while (left <= right)
  {
    arr2[left] = arr1[left];
    arr2[right] = arr1[right];
    printf("%s\n", arr2);
    left++;
    right--;
    Sleep(1000);
    system("cls");
  }
    printf("%s\n", arr2);
  return 0;
}

五、编写代码实现,模拟用户登录情景,并且只能登录三次。(只允许输入三次密码,如果密码正确则提示登录成功,如果三次均输入错误,则退出程序。

1.一个经典的错误,标准的零分

我们先给出一段代码,并且尝试分析一下,判断是否正确?

#include<stdio.h>
int main()
{
  int i;
  int flag = 0;
  char password[20] = {0};
  for (i = 0; i < 3; i++)
  {
    printf("请输入密码:");
    scanf("%s", password);
    if (password == "123456")
    {
      printf("密码正确\n");
      flag = 1;
      break;
    }
    else 
    {
      printf("密码第%d次输入错误\n", i + 1);
    }
  }
  if (flag == 0)
  {
    printf("密码三次输入错误,退出程序");
  }
  return 0;
}

当我们想要输入一个密码时候,我们首先得定义一个字符数组来存放密码。接着我们使用一个循环,用来记录三次密码的上限,在循环中,我们输入密码,然后使用一个if语句来判断,我们直接使用一个==来进行判断,然后如果对,就跳出循环,不对,则继续循环。这个逻辑似乎听着没问题,但是事实真的是这样吗?我们运行一下试试

我输入了123456,居然提示我密码错误?怎么回事?哪里出问题了?其实这里犯了一个经典的错误,标准的零分。我们说,判断两个字符串相等不是这样判断的,这样判断就是经典的错误标准的零分。

那我们应该怎么判断呢?,其实c语言中提供了一个库函数,叫做strcmp(  ,),这个库函数用于比较字符串。

那么如何比较呢?是这样比较的

//判断两个字符串是否相等,不能直接使用==
 int ret = strcmp(password,"123456");
//如果两个字符串相等,则返回0
//如果password小于"123456",也就是第一个字符串小于第二个字符串,则返回小于0的一个数字
//如果password大于"123456",也即是第一个字符串大于第二个字符串,则返回大于0的一个数字

有的人可能有疑惑了,两个字符串咋比较的?是比较他们的长度吗?我们说不是的,字符串的比较是一个一个往下比较的,也就是说,第一个字符串的第一个字符与第二个字符串的第一个字符进行比较,比较的是他们的ASCII值,如果第一位能比较出来谁大,则就是哪个字符串大,如果第一位都相等,则判断两个字符串的第二位,如此循环下去进行判断,直到遇到\0。也就代表着字符串的结束。关于字符串的一些库函数,我们在后面还会更加详细的讲解,读者暂时只需要了解到,我目前所讲解到的即可,注意使用这个库函数需要引用头文件<string.h>

所以最终的代码实现为,

#include<stdio.h>
#include<string.h>
int main()
{
  int i;
  int flag = 0;
  char password[20] = {0};
  for (i = 0; i < 3; i++)
  {
    printf("请输入密码:");
    scanf("%s", password);
    if (0 == strcmp(password, "123456")) 
    {
      printf("密码正确\n");
      flag = 1;
      break;
    }
    else 
    {
      printf("密码第%d次输入错误\n", i + 1);
    }
  }
  if (flag == 0)
  {
    printf("密码三次输入错误,退出程序");
  }
  return 0;
}

六、求最大公约数

1.一般解法

缺点:计算量太过于复杂。

#include<stdio.h>
int main()
{
  int m = 24;
  int n = 18;
  int max = m > n ? m : n;
  while (max>0)
  {
    if (m % max == 0 && n % max == 0)
    {
      printf("%d", max);
      break;
    }
    max--;
  }
  return 0;
}

2.辗转相除法

这种方法不需要掌握原理,因为涉及到数学方面的知识

我们的想法是这样的,m和n这两个数,用m对n取模,并记录结果t,如果结果不为0,则把n给m,t给n,如此循环下去。知道结果为0,最终答案为n

#include<stdio.h>
int main()
{
  int m = 24;
  int n = 18;
  int ret;
  while (m % n != 0)
  {
    ret = m % n;
    m = n;
    n = ret;
  }
  printf("%d", n);
  return 0;
}
相关文章
|
16天前
|
C语言
C语言分支和循环语句
分支语句由`if-else`构成,用于根据不同条件执行相应代码。`else`会与最近未配对的`if`结合,多个条件可用`else if`实现。若连续使用`if`,各条件互不影响。嵌套结构可在`if`中再加入`if-else`。此外,`switch`语句适用于多分支选择(注意表达式不能为浮点数,`case`后需加`break`)。循环语句包括`for`、`while`和`do...while`,注意`do...while`末尾需加分号。循环中,`break`直接终止循环,`continue`跳过当前循环剩余部分,但`for`的语句三仍会执行,而`while`中位置影响效果。
|
8月前
|
C语言
初识C语言2——分支语句和循环语句
初识C语言2——分支语句和循环语句
172 5
|
4月前
|
人工智能 Java 程序员
一文彻底搞清楚C语言的循环语句
本文介绍了C语言中的三种循环语句:`while`、`do-while`和`for`,并详细解释了它们的语法格式、执行流程及应用场景。此外,还讲解了循环控制语句`break`和`continue`的使用方法。希望这些内容能帮助你在编程道路上不断进步,共同成长!
225 0
一文彻底搞清楚C语言的循环语句
|
5月前
|
C语言
【C语言程序设计——循环程序设计】枚举法换硬币(头歌实践教学平台习题)【合集】
本文档介绍了编程任务的详细内容,旨在运用枚举法求解硬币等额 - 循环控制语句(`for`、`while`)及跳转语句(`break`、`continue`)的使用。 - 循环嵌套语句的基本概念和应用,如双重`for`循环、`while`嵌套等。 3. **编程要求**:根据提示在指定区域内补充代码。 4. **测试说明**:平台将对编写的代码进行测试,并给出预期输出结果。 5. **通关代码**:提供完整的代码示例,帮助理解并完成任务。 6. **测试结果**:展示代码运行后的实际输出,验证正确性。 文档结构清晰,逐步引导读者掌握循环结构与嵌套的应用,最终实现硬币兑换的程序设计。
100 19
|
5月前
|
算法 C语言
【C语言程序设计——循环程序设计】求解最大公约数(头歌实践教学平台习题)【合集】
采用欧几里得算法(EuclideanAlgorithm)求解两个正整数的最大公约数。的最大公约数,然后检查最大公约数是否大于1。如果是,就返回1,表示。根据提示,在右侧编辑器Begin--End之间的区域内补充必要的代码。作为新的参数传递进去。这个递归过程会不断进行,直到。有除1以外的公约数;变为0,此时就找到了最大公约数。开始你的任务吧,祝你成功!是否为0,如果是,那么。就是最大公约数,直接返回。
171 18
|
5月前
|
Serverless C语言
【C语言程序设计——循环程序设计】利用循环求数值 x 的平方根(头歌实践教学平台习题)【合集】
根据提示在右侧编辑器Begin--End之间的区域内补充必要的代码,求解出数值x的平方根;运用迭代公式,编写一个循环程序,求解出数值x的平方根。注意:不能直接用平方根公式/函数求解本题!开始你的任务吧,祝你成功!​ 相关知识 求平方根的迭代公式 绝对值函数fabs() 循环语句 一、求平方根的迭代公式 1.原理 在C语言中,求一个数的平方根可以使用牛顿迭代法。对于方程(为要求平方根的数),设是的第n次近似值,牛顿迭代公式为。 其基本思想是从一个初始近似值开始,通过不断迭代这个公式,使得越来越接近。
126 18
|
5月前
|
C语言
【C语言程序设计——循环程序设计】统计海军鸣放礼炮声数量(头歌实践教学平台习题)【合集】
有A、B、C三艘军舰同时开始鸣放礼炮各21响。已知A舰每隔5秒1次,B舰每隔6秒放1次,C舰每隔7秒放1次。编程计算观众总共听到几次礼炮声。根据提示,在右侧编辑器Begin--End之间的区域内补充必要的代码。开始你的任务吧,祝你成功!
130 13
|
5月前
|
存储 C语言
【C语言程序设计——循环程序设计】利用数列的累加和求 sinx(头歌实践教学平台习题)【合集】
项的累加和,一般会使用循环结构,在每次循环中计算出当前项的值(可能基于通项公式或者递推关系),然后累加到一个用于存储累加和的变量中。在C语言中推导数列中的某一项,通常需要依据数列给定的通项公式或者前后项之间的递推关系来实现。例如,对于一个简单的等差数列,其通项公式为。的级数,其每一项之间存在特定的递推关系(后项的分子是其前项的分子乘上。,计算sinx的值,直到最后一项的绝对值小于。为项数),就可以通过代码来计算出指定项的值。对于更复杂的数列,像题目中涉及的用于近似计算。开始你的任务吧,祝你成功!
160 6
|
5月前
|
C语言
【C语言程序设计——循环程序设计】鸡兔同笼问题(头歌实践教学平台习题)【合集】
本教程介绍了循环控制和跳转语句的使用,包括 `for`、`while` 和 `do-while` 循环,以及 `break` 和 `continue` 语句。通过示例代码详细讲解了这些语句的应用场景,并展示了如何使用循环嵌套解决复杂问题,如计算最大公因数和模拟游戏关卡选择。最后,通过鸡兔同笼问题演示了穷举法编程的实际应用。文中还提供了编程要求、测试说明及通关代码,帮助读者掌握相关知识并完成任务。 任务描述:根据给定条件,编写程序计算鸡和兔的数量。鸡有1个头2只脚,兔子有1个头4只脚。
336 5
|
8月前
|
C语言
【c语言】分支语句
C语言通过三种基本结构——顺序、选择和循环,构建复杂的程序逻辑。本文主要介绍了C语言的选择结构,即if-else语句及其变体,包括简单的if语句、if-else组合、else if多分支判断、嵌套if以及解决悬空else问题的方法。此外,还详细讲解了逻辑运算符和关系运算符的使用,以及如何利用条件操作符简化逻辑判断。最后,文章对比了if-else与switch语句在实现多分支逻辑时的应用,并解释了switch语句中的break和default关键字的作用。
119 8