有序数组查找具体数
一、题目概述
在一个指定的有序数组中,查找具体的一个数
二、解题思路
第一种方法:一个指定的有序数组中,查找一个具体的数,我们可以直接遍历,代码看三
第二种方法:二分查找。
二分查找原理:二分查找针对的是一个有序的数据集合,每次都通过跟区间的中间元素对比,将待查找的区间缩小为之前的一半,直到找到要查找的元素,或者区间被缩小为 0
- 针对的是有序的数据集合,无序的不能用二分查找
二分查找如何实现:如果中间值大于查找值,则往数组的左边继续查找,如果小于查找值这往右边继续查找,如下图
三、代码实现
直接遍历
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
int k = 0;
int flag = 0;
int sz = sizeof(arr) / sizeof(arr[0]);
int i = 0;
scanf("%d", &k);
for (i = 0; i < sz; i++)
{
if (arr[i] == k)
{
flag = 1;
printf("找到了,下标是%d", i);
break;
}
}
if (flag == 0)
{
printf("没找到");
}
return 0;
}
二分查找(折半查找)
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
int i = 0;
int flag = 0;
int sz = sizeof(arr) / sizeof(arr[0]);
int k = 0;
int left = 0;
int right = sz - 1;
int mid = 0;
scanf("%d", &k);
while (left <= right)
{
//mid = (left + right) / 2;
mid = left + (right - left) / 2; //(1)
if (arr[mid] > k)
{
right = mid - 1;
}
else if (arr[mid] < k)
{
left = mid + 1;
}
else
{
flag = 1;
printf("找到了,下标是:%d", mid);
break;
}
}
if (flag == 0)
{
printf("找不到。");
}
return 0;
}
- (1)之所以不用注释计算平均值,是因为如果两个数很大,加起来可能会超过整数最大值,就会导致溢出。所以计算两个值的平均值,只需要计算右边比左边多出来的差值,再把一半给left即可。
猜数字游戏
一、题目概述
随机生成1-100数字,玩家通过猜大猜小得到正确答案
二、解题思路
要完成猜数字游戏,就要先学习随机数知识
1.rand
C语言提供了一个函数rand,可以生成随机数,函数原型如下:
int rand(void);
rand函数会返回一个伪随机数,这个随机数的范围是0-RAND_MAX之间,RNAD_MAX的大小是依赖编译器实现的,大部分是32657
rand函数需要包含头文件<stdlib.h>
rand函数返回的是伪随机数,是通过某种算法生成的随机数,rand函数是对一个叫“种子”的基准值进行运算生成的随机数,而rand函数的种子默认值为1,也就是他每次生成的随机数序列是一样的,想要让他生成不一样的随机数序列,就要去改变这个种子
如何去改变种子?用到srand()函数
2.srand
C语言提供了一个函数srand,用来初始化随机数的生成器,函数原型如下:
void srand(unsigned int seed);
seed其实就是种子,我们可以通过改变seed的参数用来设置rand函数生成的随机数的种子。当种子在变化,rand函数生成的随机数序列也会发生变化,也就是说:我们可以在rand函数调用之前来调用srand函数,通过改变种子去改变rand函数的随机数序列
但是如果种子也需要随机,才能获得rand的随机数序列,就显得有点奇怪,我们到底应该选用什么来作为我们的种子呢?用time函数
3.time
C语言提供了一个函数time,用来通过使用程序运行的时间作为种子,因为时间每时每刻都在变化 函数原型如下
time_t time(time_t* timer)
time 函数会返回当前的日历时间,其实返回的是1970年1月1日0时0分0秒到现在程序运行时间之间的差值,单位是秒。返回的类型是time t类型的,time t类型本质上其实就是32位或者64位的整型类型(本质上是int类型或者是long long类型)。
time函数的参数timer如果是非NULL的指针的话,函数也会将这天返回的差值放在timer指向的内存中带回去。
如果 timer 是NULL,就只返回这个时间的差值。time函数返回的这个时间差也被叫做: 时间戳
时间戳:表示某一刻的时间
time函数的时候需要包含头文件: time.h
如何用time函数返回时间戳?我们可以
time(NULL);//调用time函数返回时间戳,这里没有返回值
这个时候,我们就知道如何随机生成数字了,那么我们应该如何设置随机数的范围呢?
若生成0-99之间的随机数
rand() % 100;//余数的范围是99
如果要生成1-100之间的随机数
rand()%100+1//%100余数是0~99,+1 = 1~100
如果生成100~200的随机数
100 + rand()%(200-100+1)//余数的范围是0~100,加100是100~200
如果我们要生成a~b的随机数,方法如下:
a + rand() % (b - a + 1);
b-a只是公式
三、源码剖析
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
void menu()
{
printf("**********************\n");
printf("********1.play********\n");
printf("********0.exit********\n");
printf("**********************\n");
}
void game()
{
int guess = 0;
int ret = rand() % 100 + 1;
while (1)
{
scanf("%d", &guess);
if (guess > ret)
{
printf("猜大了\n");
}
else if (guess < ret)
{
printf("猜小了\n");
}
else
{
printf("恭喜你猜对了\n");
break;
}
}
}
int main()
{
int input = 0;
srand((unsigned int)time(NULL));//(1)
do
{
menu();
printf("请选择:");
scanf("%d", &input);
switch (input)
{
case 1:
game();
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("输入错误,请重新输入\n");
break;
}
} while (input);
return 0;
}
- (1)time(NULL)直接返回差值,因为srand函数返回的是unsigned int类型,所以time要强制类型转换成unsigned int
搞一个有挑战次数的
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
void menu()
{
printf("**********************\n");
printf("********1.play********\n");
printf("********0.exit********\n");
printf("**********************\n");
}
void game()
{
int guess = 0;
int ret = rand() % 100 + 1;
int count = 0;
printf("请选择挑战次数:");
scanf("%d", &count);
while (1)
{
printf("你还有%d次机会\n", count);
printf("请开始猜数字:");
scanf("%d", &guess);
if (guess > ret)
{
printf("猜大了\n");
}
else if (guess < ret)
{
printf("猜小了\n");
}
else
{
printf("恭喜你猜对了\n");
break;
}
count--;
if (count == 0)
{
printf("挑战失败,正确答案是%d\n", ret);
}
}
}
int main()
{
int input = 0;
srand((unsigned int)time(NULL));
do
{
menu();
printf("请选择:");
scanf("%d", &input);
switch (input)
{
case 1:
game();
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("输入错误,请重新输入\n");
break;
}
} while (input);
return 0;
}
多个字符从两端移动,向中间汇聚
一、题目概述
多个字符从两端移动,向中间汇聚
二、解题思路
创建两个数组,用有字的数组的一前一后去替换第二个星号数组,
①创建一个left和right变量,分别初始化为0和strlen(arr) - 1
- strlen(arr) - 1计算数组的大小,减去1就是数组最后一个元素的下标
②arr1把第一个字符和最后一个字符赋给arr2的第一个字符和最后一个字符,然后打印出来,打印出来之后left++right–,就能实现1变成2,2变成3… right就可以从数组最后一个元素到数组倒数第二个元素,从数组倒数第二个元素–变成数组倒数第三个元素…。不断循环到左边的数大于右边的数,就证明循环结束。
三、源码剖析
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <string.h>
#include <windows.h>
int main()
{
char arr1[] = "yuanshen! qi dong !";
char arr2[] = "*******************";
int left = 0;
int right = strlen(arr1) - 1;
while (left <= right)
{
arr2[right] = arr1[right];
arr2[left] = arr1[left];
Sleep(1000); //(1)
system("cls"); //(3)
printf("%s\n", arr2);
left++;
right--;
}
return 0;
}
-
(1)Sleep()函数是用来休眠的,单位是毫秒,
-
(2)system()函数是执行命令的
喝汽水问题
一、题目概述
喝汽水,1瓶汽水1元,2个空瓶可以换一瓶汽水,给20元,可以喝多少汽水(编程实现)。
二、解题思路
假设我们只买五瓶汽水,那么会得到如下图片:
可以看出,一开始买了多少瓶就会有多少空瓶,然后两个空瓶换一瓶汽水,5个空瓶能换2个,2个汽水就是2个空瓶,(即5/2= 2余1)2汽水还能换一个,1个汽水还有一个空瓶,还余下一个空瓶,剩下的2再换一个汽水,汽水还剩下一个空瓶,如此类推
所以代码如下:
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int main()
{
int total = 0;
int money = 0;
int empty = 0;
scanf("%d", &money);
total = money;
empty = money;
while (empty > 1)
{
total += empty / 2;
empty = empty / 2 + empty % 2;
}
printf("%d",total);
return 0;
}
-
empty只要剩下1个,就无法再换汽水了。
-
我们来看一下规律,
6块- 11汽水
5块 - 9汽水
3块 - 5汽水
-
得出公式 汽水= 2 * money - 1
最终的代码如下
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int main()
{
int total = 0;
int money = 0;
int empty = 0;
scanf("%d", &money);
total = money;
empty = money;
total = 2 * money - 1;
printf("%d",total);
return 0;
}