C语言学习(一)

C语言学习笔记

C语言也学习了一个多月了,从最开始的什么都不会到现在能简单写一些简单代码,感觉收获很多,也来总结一下最近遇到的一些题目吧。

数组的删除

[问题描述]
有5个整型数据存储在数组中,再输入一个数值key,删除数组中第1个等于key的元素,并将剩余的4个数据输出。如果key不是数组中的元素,则显示not found。

分析

本题中查找第一个重复元素并删除它,显然我们不能直接删除数组中的某个元素,但可以移动它,把目标移动到数组末尾,最后的输出不输出它即可。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include<stdio.h>
int main()
{
int a[5],k,i,j,temp,index=0;//temp为中间变量,index为初始值赋为0
for(i=0;i<5;i++)
{
scanf("%d",&a[i]);
}
scanf("%d",&k);
for(i=0;i<5;i++)
{
if(a[i]==k)//判断k值与数组中是否有重复
{
for(j=i;j<5;j++)
{
a[j]=a[j+1];//依次往后移动一个位置
index=-1;//改变初始值用于判断是否进入该循环
}
break;//跳出第一个循环,因为只删除第一个重复的数值
}
}
if(index==0)
printf("not found");
else
for(i=0;i<4;i++)//最多只输出到a[3]
printf("%d ",a[i]);
return 0;
}

斐波拉契数列(数组)

[问题描述]
如果1对兔子第三月开始每月能生一对小兔子,而每对小兔子在它出生后的第3个月开始,又能生1对小兔子,假定在不发生死亡的情况下,n个月后有多少对兔子? n值通过键盘输入。
‪‬‪‬‪‬‪‬‪‬‮‬‫‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‪‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‪‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‭‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‫‬‪‬‪‬‪‬‪‬‪ [输入输出示例]
输出在一行,每个数字占6位宽度。

分析

根据问题描述可知斐波拉契数列a1=a2=1,a3=2 a4=3 a5=5 a6=8……
经观察易得,从第三项起,每一项是前两项之和,即a3=a2+a1,a4=a3+a2,a5=a4+a3,根据这个规律即可用数组写出本题。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include<stdio.h>
int main()
{
int n,i;
scanf("%d",&n);
int a[100];
a[0]=a[1]=1; //a1=a2=1

{
for(i=2; i<n; i++) //从第三项起开始进入循环,直到i=n-1时退出循环
{
a[i]=a[i-2]+a[i-1]; //每一项都是前两项之和
}
for(i=0;i<n;i++)//从第一项开始进入循环
{
printf("%6d ",a[i]);//打印所有项
}
}
return 0;
}

查找数组的最大值与最小值

分析

想要找出数组中最大值最小值我们可以先将max,min赋值成任意数组内一个数,然后进入循环开始比较每一项,如果任意一项大于等于max,则重新将此时的数赋值给max,min同理直到比较完数组最后一个数时退出循环。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
 #include<stdio.h>
int main()
{
int a[10],i,max,min;
for(i=0;i<10;i++)
scanf("%d",&a[i]); //输入数字存入数组
max=min=a[0]; //将数组第一个数赋值给max和min
for(i=0;i<10;i++) //进入循环逐个比较与max,min大小关系
{
if(max<=a[i])
max=a[i]; //如果某一项大于等于max,则重新赋值给max
if(min>=a[i])
min=a[i];//如果某一项小于等于min,重新赋值
}
printf("max=%d\nmin=%d",max,min)
return 0;
}

约瑟夫问题

[问题描述]

模拟这个游戏。有n个人围成一圈,从第一个人开始沿顺时针方向报数(从1到3报数), 凡报到3的人退出圈子,问最后留下的是原来第几号的那个人?

分析

本题需要一个”计数”变量来计数,我们考虑用计数到3时把此时的a[i]赋值成0,下次计数时跳过0,不断循环直到数组中只有一个非零数时,该数的下标就是我们需要的。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include<stdio.h>
int main()
{
int n,a[100],i,count=0,x;
scanf("%d",&n);
x=n;//x判断最终数组内还有几个非零元素
for(i=1; i<=n; i++)
{
a[i]=i;//让数组按照123456排好
}
while(x>1)
{
for(i=1; i<=n; i++)
{

if(a[i]!=0)//跳过0
count++;//计数
if(count==3)
{
a[i]=0;//每次到3时就“删除”这个数组
count=0;//计数归零
x--;//数组非零元素-1,最终循环到x=1时结束。
}
}

}
for(i=1; i<=n; i++)
{
if(a[i]!=0)
printf("%d",i);
}
return 0;
}

选择排序法(升序)

交换排序发顾名思义就是不断交换从而排序

分析

若干个数,若想排序我们可以只考虑相邻两个数的大小,如果所有相邻的俩个数都是小数在前大数在后那么整个数组都是按照升序排列了。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include<stdio.h>
int main()
{
int a[10],i,j,temp;//temp为中间值,目的是交换两个数组
for(i=0;i<10;i++)
{
scanf("%d",&a[i]);
}
for(i=0;i<10;i++)
{
for(j=i+1;j<10;j++)
{
if(a[i]>a[j])//前后两个数进行比较,如果后面的数大就交换他们
{
temp=a[j];
a[j]=a[i];
a[i]=temp;//用temp值做中间值
}
}

}
for(i=0;i<10;i++)
{
printf("%d ",a[i]);
}
return 0;
}

冒泡排序法

待补充

快速排序法

待补充

杨辉三角(二维数组)

杨辉三角在我们高中时已经学习过,我们都知道它是个类金字塔型,但为了简单化我们将其变形为等腰直角三角形,此时的图形如下图所示。
杨辉三角

分析

观察可知,这个等腰直角三角形的竖直的腰和斜边都是1,剩下的数总是它上方的及上方左边数之和,根据次规律考虑使用二维数组来进行编程。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include<stdio.h>
int main()
{
int a[100][100],n,i,j;//n为键盘输入,限定杨辉三角的腰长
scanf("%d",&n);
for(i=0;i<n;i++)
{
for(j=0;j<=i;j++)//小于等于是因为最后一行和第一竖列个数相等
{
if(i==j||j==0)//判断竖直的腰和斜边
a[i][j]=1;//赋值为1
else
a[i][j]=a[i-1][j]+a[i-1][j-1];//其余的为上方数加上方左边数
}
}
for(i=0;i<n;i++)
{
for(j=0;j<=i;j++)
printf("%4d",a[i][j]);//打印
printf("\n");
}
return 0;
}

九九乘法表

小学我们一定背过九九乘法表,我们用已学知识将其打印出来也是件非常有意思的事情。

九九乘法表

分析

观察上图可知竖列从1X1一直到1x9,横列从1xa一直到aXa.

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include<stdio.h>
int main()
{
int a[9],i,j,s,n; //s为a*b的和,n为最高输入到n*n结束
scanf("%d",&n);
for(i=1;i<=n;i++)//从1开始,因为是1*a
{
for(j=1;j<=i;j++)
{
s=i*j;//求出和方便后面输出
printf("%d*%d=%d",j,i,s);
if(j!=i)//每一行最后一个不需要空格
printf(" ");
}
if(i!=n)//最后一行下面没有换行。
printf("\n");
}
}

顺序查找法

在含有10个数的数列{11,22,5,16,8,3,19,20,23,52}中查找key值,若找到key则输出其在数组中对应的下标,否则输出not found

分析

顺序查找顾名思义就是按照顺序挨个查找数组中的每一个元素,直到找到时输出即可,若找完整个数组还没找到就是not found。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include<stdio.h>
int main()
{
int a[10]={11,22,5,16,8,3,19,20,23,52},i,k,index=-1; //k为需要查找的值,index为初始值,方便后面判断
scanf("%d",&k);
for(i=0;i<10;i++)
{
if(a[i]==k)//判断数组每个元素与k值是否相等
{
printf("%d",i);//判断成立输出数组下标
index=0;//改变初始值,代表判断成立已经找到
break;
}
}
if(index!=0)//仅当上方判断语句从未成立时,代表数组中不存在要查找的值
printf("not found");
return 0;

}

二分(折半)查找法

接着我们学习了效率更高的二分(折半)查找法,假如有1,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,56这么一组数,我们尝试使用该方法查找。注意,二分查找只能用于有序的数组进行查找。这里用升序数组举例,降序也是一个道理。

二分查找原理用文字很难讲清楚,我引用网络上的一张动图方便理解,也可以对比一下顺序查找和二分查找效率。

二分查找

图片来源于水印,仅用于学习交流,不用于商业用途,如侵权请联系我删除。

分析

按照动图为例查找37;刚开始不确定37在哪,所以整个数组都是查找区,low=0,high=16,mid=8;因为8对应的a[8]=23<37,所以37在a[8]右边,此时low=mid+1=9,查找区由整个数组变为a[9]-a[16];mid=12*(mid为整型)*,a[12]=41>37;所以high变成了11;查找区也变成了a[9]-a[11];mid=10;a[10]=31<37,low=11,mid=11,a[11]=37,,于是我们就找到了查找数37.处于数组11号。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include<stdio.h>
int main()
{
int a[17]= {135711131719232931374143475356},k,low,mid,high,index;//k值为需要查找的值,low,mid,high分别为查找区最小,中间,最大下标。index为初始值方面后面判断是否查找到。
scanf("%d",&k);//输入需要查找的数
low = 0;
high = 15;//刚开始是查找区为整个数组,所以最小和最大为0与1
index = -1;//初始值赋值为-1防止与下标冲突
while(low<=high)//当low个high值错位时,退出循环(此时查找区为空,要么找到了要么不存在)
{
mid=(low+high) / 2;//计算中间下标
if (a[mid]==k)//如果查找区的中间的那个数等于k说明已经找到
{
index = mid;//初始值赋值成找到的那个数组下标
break;//跳出循环
}
if (a[mid]>k)//如果查找区中间值的数大于查找的数,说明查找数在中间值左侧,考虑缩小查找区进一步确定查找数位置
high = mid - 1;//缩小查找区
if (a[mid]<k)//如果查找区中间值的数小于查找的数,说明查找数在中间值右侧,考虑缩小查找区进一步确定查找数位置
low = mid + 1;//缩小查找区
}
if (index!=-1)//如果初始值一直都为-1。说明上方判断语句不成立,说明待查找的数不在数组中,输出not found,如果不等于-1。,说明判断语句成立,此时index值就为数组中该查找数的下标
printf("%d",mid);
else
printf("not found");
return 0;

}