这个作业属于哪个班级 | C语言--网络2011/2012 |
---|---|
这个作业的地址 | C博客作业04--数组 |
这个作业的目标 | 学习数组相关内容 |
姓名 | 林进源 |
0.展示PTA总分
-
数组
-
字符数组
1.本章学习总结
1.1 学习内容总结
1. 数组基础知识(包括字符数组、字符串特点及编程注意事项)
-
数组定义一般形式
类型名 数组名 [数组长度] -
数组长度是一个常量
-
数组名是一个地址常量,存放数组内存空间的首地址
-
数组引用
数组名[下标]
其合理的取值范围是[0,数组长度-1] -
一维数组的初始化
(1)类型名 数组名 [数组长度]={初值表}
例:- int a[10]={1,2,3,4,5,6,7,8,9,10}
- 针对部分元素:int b[3]={1},此时b[1]b[2]不确定
(2)静态初始化
例:- static int b[5]={1,2,3,4,5}
- static int b[5]等价于static int b[5]={0,0,0,0,0}
- 针对部分元素:static int b[3]={1,2},此时b[2]=0
-
二维数组的初始化
(1)分行赋值法
例:- int a[3][3]={{1,2,3},{4,5,6},{7,8,9}}
- 针对部分元素:static int a[3][3]={{1,2,3,},{4,5},{}},没有具体赋值的部分为0
(2)顺序赋值法
例:- int a[3][3]={1,2,3,4,5,6,7,8,9,}
- int a[3][3]={1,1,1,0,0,0,1,1,1,}等价于static int a[3][3]={{1,1,1},{},{1,1,1,}}
-
字符串
- ' '为字符串的结束符
例: static char a[6]={'h','a','p','p','y',' '},' '也有占一个字符 - 字符串的输入格式
字符串带空格:
- ' '为字符串的结束符
/*while输入方法*/
int i=0;
char str[10];
while((str[i]=getchar())!='
')
{
i++;
}
str[i]=' ';//需要给字符数组加上结束符号
/*fgets输入方法*/
fets(i,n,stdin);//n为设定的数组字符长度
字符串不带空格:
scanf("%s",str);
- 字符数组的输出格式:
for(i=0;str[i]!=' '&&str[i]!='
';i++)
{
printf("%c",str[i]);
}
2. 数组中如何查找数据
- for循环查找
例:
题目:本题要求从输入的N个整数中查找给定的X。如果找到,输出X的位置(从0开始数);如果没有找到,输出“Not Found”。
代码:
#include <stdio.h>
int main()
{
int N;//要输入N个整数
int X;//要查找的数
int i;
scanf("%d %d", &N, &X);
int Number[20];
for (i = 0; i <= N-1; i++)
{
scanf("%d", &Number[i]);
if(X==Number[i])//输入的同时判断是否相等符合
{
printf("%d",i);
break;
}
else if(i==N-1&&X!=Number[i]) //最后一组数的判断
{
printf("Not Found");
}
}
return 0;
}
- 哈希数组查找
例:
题目:在一大堆数据中找出重复的是一件经常要做的事情。现在,我们要处理许多整数,在这些整数中,可能存在重复的数据。你要写一个程序来做这件事情,读入数据,检查是否有重复的数据。如果有,输出“YES”这三个字母;如果没有,则输出“NO”。
代码:
#include <stdio.h>
int main()
{
int A[100000];
static int count[100000];//引入新数组作为哈希数组,全部初始化
int n;
int i;
scanf("%d", &n);
for ( i = 0; i <= n-1; i++)//输入数组
{
scanf("%d", &A[i]);
}
for ( i = 0; i <= n - 1; i++)
{
count[A[i]]++;//统计重复字母的个数
if(count[A[i]]>=2)//当字母重复2次出现立刻跳出
{
printf("YES");
break;
}
}
if(count[A[i]]<=1)//当字母都没有重复
{
printf("NO");
}
return 0;
}
- 二分法查找数组(仅适用于已按大小排布)
核心代码展示:
int a[n];
int left=0;//左界
int right=n-1;//右界
int flag=0;//判断是否是要查找的数的变量
int number;//要查找的数
if(number<a[0]||number>a[n-1])//判断要查找的数是否在数组里面
{
flag=-1;
}
while((left==0)&&(left<=right))//循环条件
{
min=(right+left)/2;//二分法核心公式
if(number==a[min])
{
flag=min
printf("数在数组的第%d个",flag+1);
break;
}
else if(number<a[min]//数比中间数小
{
right=min-1;//改右界
}
else//数比中间数大
{
letf=min+1;//改左界
}
}
方法总结:对于数组长度相对较短的题目查找某个元素,可以用for循环来解决问题,然而如果数组长度过长,例如例题二,若用for循环则需要用到循环嵌套,最后循环次数偏大,会导致运行超时。但如果用哈希数组来做,将一列数组的值引入哈希数组的下标里面,只要利用一次for循环就可以统计该哈希数组的值,通过他们的值找到重复的元素。对于已经进行排序的系列数,可用二分法进行查找,不断取一半来缩小查找范围,最后缩小到一个位置,需要定义一个左界和右界,通过不断判断与中间数的关系,对左右界进行调整,最后实现数的查找。
3. 数组中如何插入数据
例题:本题要求编写程序,将一个给定的整数插到原本有序的整数序列中,使结果序列仍然有序。
伪代码:
for(条件)
{
输入数组
}
scanf("%d",a[n])//输入要插入的数,将其放在数组[n],可实现插入的数放在最后面
int flag=a[n]//需要一个中间变量进行判断
for(int i=0;i<=n-1;i++)
{
if(在中间输入的判断条件)
{
for(条件)
{
从后往前都向右移一位
}end for
插入数据
break;
}end if
if(在首位插入)
{
for(条件)
{
全部右移一位
}
插入数据
}end if
}
end for
本题代码:
#include <stdio.h>
int main()
{
int N;
int flag;
scanf("%d", &N);
int number[10];
for (int i = 0; i <= N - 1; i++)
{
scanf("%d", &number[i]);
}
scanf("%d", &number[N]);//使number[N]有意义,同时也可以数最大时放在满足在最后
flag = number[N];//中间变量转换
for (int i = 0; i <= N - 1; i++)
{
if (flag > number[i] && flag < number[i + 1])//数在中间换
{
for (int j = N; j >= i + 1; j--)//从后往前向右移
{
number[j] = number[j - 1];
}
number[i + 1] = flag;//插入数
break;
}
if (flag < number[0])//数一下子最小
{
for (int j = N; j >= 1; j--)
{
number[j] = number[j - 1];//从后往前向右移
}
number[0] = flag;//插入数据
break;
}
}
for (int k = 0; k <= N; k++)
{
printf("%d ", number[k]);
}
return 0;
}
方法总结:插入数据这种题目,一般都只会直接考虑到从中间插入,但是要考虑全面,有三种情况,分别在首 中 未插入数据,考虑到这三种情况以后,先想怎么满足中间插入的情况又可以实现首尾插入,如插入一个数据,数组必会多一个数据,可在a[n]原本没有赋值将其赋值为要插入的数据,可满足直接在尾部插入。接着用for循环将数组每一个元素与要插入的数比较,同时又要满足后一个元素的数大于或者小于插入的数(看题目要求大小排列顺序),判断之后需要从后面开始将数据都逐个往右移动,再另外用if来判断是不是直接在首插入。
4.数组中如何删除数据
- 循环移动覆盖法
例题:完成数组元素的移动功能:假设数组有n个元素,输入一个数x,把数组的第x个位置的元素删除了,后面的元素依次前进一个位置。 重复若干次这样的删除,得到最后的结果。
代码:
#include <stdio.h>
int main()
{
int n;
int number[100];
scanf("%d", &n);//数组长度
for (int i = 0; i <= n - 1; i++)
{
scanf("%d", &number[i]);
}
int m;//删除的个数
int a;//要删除第几个
scanf("%d", &m);
int j;
for (int i = 1; i <= m; i++)
{
scanf("%d", &a);//输入要删除第几个
for (int j = a - 1; j <= n - 2; j++)//利用循环左移,覆盖数据
{
number[j] = number[j + 1];
}
n--;//删除减少一位
}
for (int i = 0; i <= n - 1; i++)//输出数组
{
if (i == 0)//控制空格的输出
{
printf("%d", number[i]);
}
else
{
printf(" %d", number[i]);
}
}
return 0;
}
- 哈希数组删除重复数据
例题:本题要求编写程序,将给定字符串去掉重复的字符后,按照字符ASCII码顺序从小到大排序后输出。
代码:
#include <stdio.h>
int main()
{
char str[500];
static int A[256];//256个字符
int i=0;
int a;
while ((str[i] = getchar()) != '
')//输入字符串
{
i++;
}
str[i] = ' ';//给字符串加上结束符号
for (a = 0; str[a] != '
'&&str[a] != ' '; a++)
{
A[str[a]] = 1;//标记重复的字符
}
for (a = 0; a<256; a++)
{
if (A[a] == 1)//判断是否是重复的字符
{
printf("%c", a);
}
}
return 0;
}
方法总结:对于删除数组某个数据这种类型题目,循环移动覆盖这种方法是通用的(前提是数组长度不长),通过循环不断左移,单独判断某个数组元素是否满足条件,若为要删除的数,便再套用一轮循环,将后面的元素不断左移,思路简单,如果遇到数组长度相对较长的题目,这种方法可能会超时。哈希数组删除方法适用于已知要删除的哪些元素或者是删除数组的重复数据这类题目,因为已经要删的数,便可只用一轮循环,将要删的数放入哈希数组,判断要删数组每个元素是否与哈希数组内的元素相同即可。
5.数组中目前学到排序方法
- 冒泡法排序
例题:将N个整数按从小到大排序的冒泡排序法是这样工作的:从头到尾比较相邻两个元素,如果前面的元素大于其紧随的后面元素,则交换它们。通过一遍扫描,则最后一个元素必定是最大的元素。然后用同样的方法对前N−1个元素进行第二遍扫描。依此类推,最后只需处理两个元素,就完成了对N个数的排序本题要求对任意给定的K(<N),输出扫描完第K遍后的中间结果数列。
代码:
#include <stdio.h>
int main()
{
int N;//数组长度
int K;//外圈交换次数
int temp;//交换数
scanf("%d %d", &N, &K);
int number[100];
for (int i = 0; i <= N - 1; i++)//输入数组
{
scanf("%d",&number[i]);
}
for (int j = 1; j <= K; j++)
{
for (int l = 0; l <= N - 2-j+1; l++)//注意和j的关系,此时l<N-2
{
if (number[l] >= number[l + 1])//判断是否大于后面的数交换
{
temp = number[l];
number[l] = number[l+1];
number[l + 1] = temp;
}
}
}
for (int m = 0; m <= N - 1; m++)
{
if (m == 0)//控制空格输出
{
printf("%d", number[0]);
}
else
{
printf(" %d", number[m]);
}
}
return 0;
}
- 选择法排序
例题:本题要求将给定的n个整数从大到小排序后输出。
代码:
#include <stdio.h>
int main()
{
int n;//数组长度
scanf("%d", &n);
int number[10];
int temp;//交换数
for (int i = 0; i <= n - 1; i++)//输入数组
{
scanf("%d", &number[i]);
}
for (int j = 1; j <= n; j++)//进行的轮次,注意j为1
{
for (int l = j - 1; l <= n-1; l++)//此处为l为j-1
{
if (number[j - 1] < number[l])//左边的固定为number[j-1],右边为number[l],l可变.进行判断并交换
{
temp = number[j - 1];
number[j - 1] = number[l];
number[l] = temp;
}
}
}
for (int m = 0; m <= n - 1; m++)
{
if (m == 0)//判断空格输出
{
printf("%d", number[0]);
}
else
{
printf(" %d", number[m]);
}
}
return 0;
}
冒泡法总结:冒泡法排序是以两个元素两两配对,通过循环以两个为一组,不断向后移动,并判断两个元素哪个较大或者较小并进行交换,一轮过后,可实现最后一个数是最大或者最小,第二轮后,可实现倒数第二个数是次大或者次小,以此类推。
选择法总结:选择法排序是利用循环,将一个元素与后面的所有元素逐个进行判断对比并进行交换,运用了循环嵌套,要判断的元素顺序轮下去。
6.哈希数组用法
- 删除数组中给定元素
因为题目较少,且前面已经展示过,故展示伪代码(若为字符型数组,输入则换为while并附上结束符号)
伪代码:
int a[n];//原数组
int b[n];//给定要删除的元素
int flag[n];//哈希数组
for(条件)
{
输入数组a[n];
}end for
for(条件)
{
输入数组b[n]
flag[b[n]]=1;//记录要删除的元素
}end for
for (条件)
{
if(flag[a[n]] != 1)//判断是否为要删除的元素
{
输出
}end if
}end for
- 查找数组中的重复元素
因为题目较少,且前面已经展示过,故展示伪代码(若为字符型数组,输入则换为while并附上结束符号)
伪代码:
int a[n];//原函数
static int flag[n]=0;//哈希数组
for(条件)
{
输入数组a[n];
flag[a[n]]++;//记录已有的元素
}end for
for(条件)
{
if(flag[a[n]]>1)
{
证明有重复
break;
}end if
if(flag[a[n]]==1&&为最后一个元素)
{
证明没有重复
}end if
}end for
- 统计元素出现的次数
伪代码:
static count[n]=0;//初始化进行统计
int a[n];
for(条件)
{
输入a[n];
count[a[n]]++
}end for
for(条件)
{
输出count[n]
}end for
哈希数组方法总结:可用哈希数组来完成的题目,都会出现重复这个词,需要已知元素来放入哈希数组里面,再与原数组进行配对,题目若为要删除给定的元素,则将给定的删除元素放入哈希数组里面,再将原函数与其配对判断输出。题目若需要数组内判断是否有重复,则可统计数组内每个元素出现的次数,利用循环输入的同时,通过哈希数组累加次数,最后判断出现次数。
7. 进制转换
核心代码:
int base;//转换的进制数
char a[n];//要装转换的数
int n;//要转换的数
char b[16]="0123456789ABCDEF";//较大进制数需要用到
输入base
输入a[n]
int n,i=0;
do
{
c[i]=n%base;
i++;
n=n/base
}while(n!=0);
for(--i;i>=0;--i)//需要逆序输出
{
输出
}
2.PTA实验作业
2.1大数加法
题目:输入2个大数,每个数的最高位数可达1000位,求2数的和。
2.1.1
- 伪代码
char a[i]//第一个大数
char b[j]//第二个大数
char c[g]//装大数相加后的字符串
while(条件)
{
输入a[i];
}
while(条件)
{
输入b[j]
}
//需要用while来记录i和j的值,最后要加上结束符号
int m=i-1;//数组a的长度
int n=j-1;//数组b的长度
int flag=0;//进制数
int b;
int a;
if(m>=n)//数组a的长度大于数组b的长度
{
for(条件)//从数组末位开始往前
{
if(b还有元素)
{
b=0
}
then
{
数组b元素转换为数字
}end if
n--;//数组b自减
数组a元素转换为数字
if(a+b<10)
{
if(a+b+flag>=10)//若后一位进一后可能会导致又要进一次一
{
数字减10并再进一并转字符装进c
}
then
{
转字符装进c
}
}
then
{
数字减10并进一位转字符装进c
}end if
g++//c字符自加
}
then
{
重复上述的类似操作,m和n互换位置
}end if
- 数据处理
- 数据表达:char a[i],b[j],c[g](数组a b为大数,c为要装的数组),int a,b(两数组在某个位置的十进制数),int flag(处理十进制),int m,n(处理数组a,b的下标)
- 数据处理:
- 输入两个大数字符串以后,先判断两个字符串哪个元素个数更多
- 再利用循环从两字符数组末位开始往前,还需要判断元素个数较少的那个数组是否还有元素
- 将两个元素转换为数字,累加看是否要进一,同时还要判断之前进一累加的是否还会导致其继续累加
- 再将数转为字符装入新的字符里面
2.1.2 代码截图
2.1.3
- 同学代码
#include<stdio.h>
#include<string.h>
int main()
{
char s1[1005], temp1[1005];
char s2[1005], temp2[1005];
int m, n;
scanf("%s", s1);
scanf("%s", s2);
int a[1005], k = 0;
int i = strlen(s1) - 1;//计算最后下标
int j = strlen(s2) - 1;//计算最后下标
int r;
int ans = 0;
while (i >= 0 || j >= 0 || ans != 0) //三者成立条件
{
int x = i >= 0 ? s1[i] - '0' : 0;
int y = j >= 0 ? s2[j] - '0' : 0;
r = x + y + ans;
a[k++] = r % 10;
ans = r / 10;
i--;
j--;
}
for (i = k - 1; i >= 0; i--)
{
printf("%d", a[i]);
}
return 0;
}
- 各自代码特点
我的代码方法属于很土的那种,一般人都可以想得到,在两数组长度的判断方面,我将两种情况分开讨论,也导致了代码长而重复,同学的代码利用while (i >= 0 || j >= 0 || ans != 0)这一步可以不用考虑到底哪个数组长度大导致要什么时候停止,三者条件并列就是停止标志。内部进一的步骤我考虑到了两次进一,导致代码需要多个if来限制,而他只用了几步且不用考虑多后位进一带来的影响,他的代码简短且思路清晰易懂。
2.2找鞍点
题目:一个矩阵元素的“鞍点”是指该位置上的元素值在该行上最大、在该列上最小。本题要求编写程序,求一个给定的n阶方阵的鞍点。
2.2.1
- 伪代码
int a[6][6]
int flag=1;//判断鞍点
for(条件)
{
输入数组
}end for
for(条件)
{
找到每行的最大元素
for(条件)
{
判断是否为所在列最小
}end for
}end for
- 数据处理
- 数据表达:int flag(判断是否为鞍点的中间变量),int (矩阵)
- 数据处理:
- 定义输入矩阵
- 利用for循环找到每一行的最大元素
- 再利用for循环将该最大元素与其所在列的每个元素进行比较,判断是否为该列最小
2.2.2 代码截图
2.2.3
大体思路和超星视频的一样,且方法类似,不同点在于超星视频运用了函数分装,以及最后在找是否为列最小时,判断最后成立条件的if是放在循环外面,而我则是将if放入循环并用中间变量flag来判断是否为鞍点,一些细小的方面不同而已。
2.3切分表达式
2.3.1
- 2.3.1 伪代码
char a[n];
while(条件)
{
if(是必须要切分的符号)
{
输出
i++;
continue;
}end if
if(是不用切分的符号)
{
if(后面是不用切分)
{
输出
}
then
{
输出并换行
}
i++;
continue;
}
if(是+和-)
{
if(前面是(或者i=0)
{
输出
}
then
{
输出并换行
}
i++;
}
- 数据处理
- 数据表达:cahr an,int i(控制下标变化)
- 数据处理:
- 输入数组并进入循环
- 先判断必定要切分的
- 再判断不用切分的,再判断其后面是否需要继续切分,若不要则不用换行,若要则换行
- 最后判断+和-,再判断其前面是否为(或者其为首字母,若是则不换行,若不是则换行
2.3.2 代码截图
2.3.3
嗯嗯嗯,其实我想了挺久最后去看了超星的视频,模仿他的方法,一开始是卡在+和-号这种情况不知道要怎么才可以单独输出,因为只考虑后面的元素情况,漏考虑了前面的元素情况,看了视频之后恍然大悟。