20223年11月第二题解---------数组
1. 问题H:【C语言训练】排序问题<1>
1.1. 解题思路
- 题目已经告诉你了,用排序
1.2. 解题方法
1.2.1. 冒泡排序
#include <stdio.h>
#define N 10
void bubberSort(int *a, int size);//冒泡排序,升序,即按从小到大的顺序排序
void swap(int *a, int *b);//交换两个数的值
int main()
{
int a[N],i,j;
for(i=0;i<N;i++)
scanf("%d",a+i);
bubberSort(a, N);
for(i=0;i<N;i++)
printf("%d ",a[i]);
return 0;
}
void bubberSort(int *a, int size)
{
if (size < 2 || a == 0)//如果数组的大小小于等于1,就不用排序,或者a没有存储空间,排不了序
{
return ;
}
for (int i = 0; i < size - 1; i++)//有n个数就要排n - 1趟,
//因为每排一次序,就有一个数排好位置了,n - 1趟之后就有n - 1个数排好了,那么最后一个数一定是在那个它需要在的位置
{
for (int j = 0; j < size - 1 - i; j++)//每排好一次序,就有一个数到了它需要在的位置,那么下一次就不用再排这个数了。
//排了n次序就有n个数已经在正确的位置,因此就要减i不再排这些已经拍好的数。
//当然也可以排这些已经拍好的数,但这会增加运行的时间复杂度,做了大部分重复的工作
if (a[j] > a[j + 1])//如果前面的数比后面的大,不满足升序的要求,因此交换它们的值
{
swap(&a[j], &a[j + 1]);//交换前面的值和后面的值
}
}
}
void swap(int *a, int *b)
{
int t = *a;
*a = *b;
*b = t;
}
1.2.2. 选择排序
#include <stdio.h>
#define N 10
void selectionSort(int *a, int size);
void swap(int *a, int *b);
int main()
{
int a[N],i;
for(i=0;i < N;i++)
scanf("%d",a+i);
selectionSort(a, N);
for(i=0;i < N;i++)
printf("%d ", a[i]);
}
void selectionSort(int *a, int size)
{
if (size < 2 || a == 0)//如果数组的大小小于等于1,就不用排序,或者a没有存储空间,排不了序
{
return ;
}
for (int i = 0; i < size - 1; i++)//这里排几趟跟冒泡排序是一样的,逻辑也是一样的
{
int min = i;//假设下标i位置的是最小的
for (int j = i + 1; j < size; j++)//看i后面的所有值
if (a[min] > a[j])//如果还有比最小的值还要小的数
{
min = j;//更新最小位置的下标
}
if (i != min)//下标i的值不是最小的,那么和最小的值交换
{
swap(&a[min], &a[i]);
}
}
}
void swap(int *a, int *b)
{
int t = *a;
*a = *b;
*b = t;
}
1.2.3. 插入排序
#include<stdio.h>
#define N 20
void insertSort(int *a, int size);
void swap(int *a, int *b);
int main()
{
int a[N],i;
for(i=0;i<N;i++)
{
scanf("%d", a + i);
}
insertSort(a, N);
for(i=0;i<N;i++)
{
printf("%d ", a[i]);
}
return 0;
}
void insertSort(int *a, int size)
{
if (size < 2 || a == 0)//如果数组的大小小于等于1,就不用排序,或者a没有存储空间,排不了序
{
return ;
}
for (int i = 1; i < size; i++)//从下标1开始,排多少趟跟前面两个排序一样的逻辑
{
for (int j = i - 1; j >= 0 && a[j] > a[j + 1]; j--)//看i前面的数是不是比i对应的值大,并且j的范围必须不能越界。
//大就交换,前面的数一定是有序的相当于在一个有序序列插入一个数并让这个序列仍然有序,不断的做这件事
{
swap(&a[j], &a[j + 1]);
}
}
}
void swap(int *a, int *b)
{
int t = *a;
*a = *b;
*b = t;
}
1.2.4. 快速排序
//快速排序的改进避免最坏情况
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <time.h>
#define N 10
void quickSort(int *a, int low, int high);
void swap(int *a, int low, int high);//交换a[low]和a[high]的值
int* partition(int *a, int low, int high);//把a中low到high的数分类,小于的在左边,等于的在中间,大于的在右边
int main(int argc, char *argv[])
{
int a[N];
srand(time(NULL));
for (int i = 0; i < N; i++) {
a[i] = rand() % 100;
}
for (int i = 0; i < N; i++) {
printf("%d ", a[i]);
}
putchar('\n');
quickSort(a, 0, N - 1);
for (int i = 0; i < N; i++) {
printf("%d ", a[i]);
}
putchar('\n');
return 0;
}
void quickSort(int *a, int low, int high)
{
int *p = NULL;//存储等于基准值的左右边界
if ( low >= high) {//如果只有一个值不用排序就直接结束排序
return ;
}
swap(a, low + rand() % (high - low + 1), high);//随机从数组里面找一个数,和最后一个数做交换
p = partition(a, low, high);//p指向等于基准值区间左右边界
quickSort(a, low, p[0] - 1);//只排小于基准值的部分
quickSort(a, p[1] + 1, high);//只排大于基准值的部分
free(p);//释放掉开辟的空间
}
void swap(int *a, int low, int high)
{
int t = 0;
t = a[low];
a[low] = a[high];
a[high] = t;
}
int* partition(int *a, int low, int high)
{
int l = low - 1;//左边界从low的左边,因为是把最后一个当作基准值
int r = high;//右边界从high开始,因为基准值是最后一个
int i = low;//从头开始遍历
int key = a[high];//把基准值赋值
while(i < r) {//只要没有到右边界
if (a[i] < key) {//下标i的数小于基准值,放在左边界里面
swap(a, l + 1, i);//把左边界的前一个数和下标i的值交换
i++;//去下一个数
l++;//左边界扩张
}
else if ( a[i] > key){//下标i的数大于基准值,放在右边界里面
swap(a, r - 1, i);//把右边界的前一个数和下标i的值做交换
r--;//右边界扩张,因为把一个没有访问的数移过来了,所有等下还要访问这个数看是在那个区间的,所以i不加1
}
else {//标i的数等于基准值,放在左右边界之间
i++;//直接加1
}
}
swap(a, r, high);//把基准值和右边界交换位置
int *p = (int *)malloc(sizeof(int ) * 2);//存放等于区间的左右边界
p[0] = l + 1;//左边界就是l + 1
p[1] = r;//右边界刚刚交换了值,所以它的值一定是基准值
return p;//返回这个区间
}
2. 问题 I: 【C语言训练】排序问题<2>
2.1. 解题思路
还是排序问题没有什么好说的跟上面的本质是一样的,只是升序降序的问题。
2.2. 解题方法
2.2.1. 插入排序
#include<stdio.h>
int main()
{
int a[10],i,j,m,*p=a;
for(i=0;i<10;i++)
{
scanf("%d",a+i);
}
for(i=1;i<10;i++)
{
for(j=i-1,m=a[i];j>=0&&m>a[j];j--)
{
*(p+j+1)=*(p+j);
}
*(p+j+1)=m;
}
for(p=a,i=0;i<10;i++)
{
printf("%d ",*(p+i));
}
return 0;
}
之前写的代码copy过来的,格式有点丑。
3. 问题 J: 简单排序
3.1. 解题思路
还是一样的思路,没有什么好说的。
3.2. 解题方法
3.2.1. 快速排序
//快速排序的改进避免最坏情况
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <time.h>
#define N 10
void quickSort(int *a, int low, int high);
void swap(int *a, int low, int high);//交换a[low]和a[high]的值
int* partition(int *a, int low, int high);//把a中low到high的数分类,小于的在左边,等于的在中间,大于的在右边
int main(int argc, char *argv[])
{
int a[N];
srand(time(NULL));
for (int i = 0; i < N; i++) {
a[i] = rand() % 100;
}
for (int i = 0; i < N; i++) {
printf("%d ", a[i]);
}
putchar('\n');
quickSort(a, 0, N - 1);
for (int i = 0; i < N; i++) {
printf("%d ", a[i]);
}
putchar('\n');
return 0;
}
void quickSort(int *a, int low, int high)
{
int *p = NULL;//存储等于基准值的左右边界
if ( low >= high) {//如果只有一个值不用排序就直接结束排序
return ;
}
swap(a, low + rand() % (high - low + 1), high);//随机从数组里面找一个数,和最后一个数做交换
p = partition(a, low, high);//p指向等于基准值区间左右边界
quickSort(a, low, p[0] - 1);//只排小于基准值的部分
quickSort(a, p[1] + 1, high);//只排大于基准值的部分
free(p);//释放掉开辟的空间
}
void swap(int *a, int low, int high)
{
int t = 0;
t = a[low];
a[low] = a[high];
a[high] = t;
}
int* partition(int *a, int low, int high)
{
int l = low - 1;//左边界从low的左边,因为是把最后一个当作基准值
int r = high;//右边界从high开始,因为基准值是最后一个
int i = low;//从头开始遍历
int key = a[high];//把基准值赋值
while(i < r) {//只要没有到右边界
if (a[i] < key) {//下标i的数小于基准值,放在左边界里面
swap(a, l + 1, i);//把左边界的前一个数和下标i的值交换
i++;//去下一个数
l++;//左边界扩张
}
else if ( a[i] > key){//下标i的数大于基准值,放在右边界里面
swap(a, r - 1, i);//把右边界的前一个数和下标i的值做交换
r--;//右边界扩张,因为把一个没有访问的数移过来了,所有等下还要访问这个数看是在那个区间的,所以i不加1
}
else {//标i的数等于基准值,放在左右边界之间
i++;//直接加1
}
}
swap(a, r, high);//把基准值和右边界交换位置
int *p = (int *)malloc(sizeof(int ) * 2);//存放等于区间的左右边界
p[0] = l + 1;//左边界就是l + 1
p[1] = r;//右边界刚刚交换了值,所以它的值一定是基准值
return p;//返回这个区间
}
4. 问题 K: 数组逆序
4.1. 解题思路
- 栈,因为栈有FILO(first in last out,先进后出)的特点。那么只要先把所以数组元素先压栈在出栈就实现了逆序
- 观察这组数,我们可以发现它可以是第一个交换和倒数第一个交换,第二个和倒数第二个交换,知道它们相遇
- 在用另一个数组存储,即第一个到倒数一个位置,第二个到倒数第二个位置,直到数组都访问过了
4.2. 解题方法
4.2.1. 栈
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <time.h>
#include <stdbool.h>
#define ll long long
#define sc scanf
#define pr printf
#define N 10
int main(int argc, char* argv[])
{
int top = 0;//初始化栈顶
int stack[N];
int num[N];
for (int i = 0; i < N; i++)
{
sc("%d", num + i);
stack[top++] = num[i];//压栈
}
for (; top > 0; top--)//出栈,当栈顶为0表示栈中已经没有元素了
{
pr("%d ", stack[top - 1]);
}
return 0;
}
4.2.2. 对称的特性
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <time.h>
#include <stdbool.h>
#define ll long long
#define sc scanf
#define pr printf
#define N 10
void swap(int *a, int i, int j);
int main(int argc, char* argv[])
{
int num[N];
for (int i = 0; i < N; i++)
{
sc("%d", num + i);
}
for (int i = 0; i < N / 2; i++)
{
swap(num, i, N - 1 - i);//把第i个和倒数第i个的值交换
}
for (int i = 0; i < N; i++)
{
pr("%d ", num[i]);
}
return 0;
}
void swap(int *a, int i, int j)
{
int t = a[i];
a[i] = a[j];
a[j] = t;
}
4.2.3. 辅助数组法
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <time.h>
#include <stdbool.h>
#define ll long long
#define sc scanf
#define pr printf
#define N 10
int main(int argc, char* argv[])
{
int num[N];
int res[N];//辅助数组
for (int i = 0; i < N; i++)
{
sc("%d", num + i);
}
for (int i = 0; i < N; i++)
{
res[N - 1 - i] = num[i];//把第i个数存放在倒数第i个位置
}
for (int i = 0; i < N; i++)
{
pr("%d ", res[i]);
}
return 0;
}
5. 最值
5.1. 解题思路
- 先找到最大最小值的下标
- 把最小值和和下标0的值交换
- 判断最大值是不是在下标0位置,如果在就把之前最小值的位置和最后一个数交换,如果不是,就把最大值的位置和最后一个数交换
5.2. 解题方法
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <time.h>
#include <stdbool.h>
#define ll long long
#define sc scanf
#define pr printf
void swap(int *a, int *b);
int main(int argc, char* argv[])
{
int n = 0;
int min = 0;//指向最小的位置
int max = 0;//指向最大的位置
sc("%d", &n);
int *num = (int*)malloc(sizeof(int) * n);//等价于num[n]
for (int i = 0; i < n; i++)
{
sc("%d", num + i);
if (num[max] < num[i])//如果不是最大值
{
max = i;//更新最大值的下标
}
else if (num[min] > num[i])//如果不是最小值
{
min = i;//更新最小值的下标
}
}
if (min != 0)//只要最小值的下标不是0,就交换
{
swap(&num[0], &num[min]);
}
if (max == 0)//如果最大值的下标是0,又因为刚刚最小值和下标0的位置的值交换了
//所以下标0位置是最小值,而最大值到了之前最小值的位置,所以把之前最小值的位置和最后一个数交换
{
swap(&num[min], &num[n - 1]);
}
else {//如果最大值的位置不是下标0的位置,代表max指向的位置就是是最大值所在的位置,直接和最后一个数交换
swap(&num[n - 1], &num[max]);
}
for (int i = 0; i < n; i++)
{
pr("%d ", num[i]);
}
free(num);
return 0;
}
void swap(int *a, int *b)
{
int t = *a;
*a = *b;
*b = t;
}
6. 问题 M: 数组最大值
6.1. 解题思路
- 假设下标0位置的数最大,然后从1开始遍历,如果找到更大的数,就更新最大值的下标
- 用分治的思想,先找到局部最大值,在合并结果
- 在输入的时候就开始记录最大数
6.2. 解题方法
6.2.1. 循环
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <time.h>
int find_max(int *p, int size);
int main(int argc,char *argv[])
{
int n = 0;
scanf("%d", &n);
int *p = (int*)malloc(sizeof(int) * n);
for (int i = 0; i < n; i++) {
scanf("%d", p + i);
}
int res = find_max(p,n);
printf("%d", p[res]);
return 0;
}
int find_max(int *p, int size)
{
int res = 0;
for (int i = 1; i < size; i++) {
if ( p[res] < p[i]) {
res = i;
}
}
return res;
}
6.2.2. 递归
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <time.h>
#include <stdbool.h>
int find_max(int *a, int left, int right);//在[left,right]区间上找到最大值,并返回最大值(数值不是下标)。
//这里是left和right下标,从0开始数
int main(int argc, char *argv[])
{
int n;
scanf("%d", &n);
int *a = (int*)malloc(sizeof(int) * n);//等价于a[n]
for (int i = 0; i < n; i++)
{
scanf("%d", a + i);
}
int max = find_max(a, 0, n - 1);//在[0,n - 1]上找到一个最大数
printf("%d\n", max);
free(a);
return 0;
}
int find_max(int *a, int left, int right)
{
int mid = left + ((right - left) >> 1);//求出中点坐标
if ((right - left + 1) == 1)//如果只有一个数,就返回这个数
{
return a[left];
}
int left_res = find_max(a, left, mid);//递归求解[left,mid]的最大值
int right_res = find_max(a, mid + 1, right);//递归求解[mid,right]的最大值
return left_res > right_res? left_res: right_res;//如果左边的数大于右边的数,最大值是左边的,否则是右边的
}
6.2.3. 插入思想
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <time.h>
#include <stdbool.h>
int main(int argc, char *argv[])
{
int n;
int max = 0; //假设下标是最大的数
scanf("%d", &n);
int *a = (int*)malloc(sizeof(int) * n);//等价于a[n]
for (int i = 0; i < n; i++)
{
scanf("%d", a + i);
if (a[max] < a[i])//如果后面进来的数比最大的数还要大
{
max = i;//更新最大的数的下标
}
}
printf("%d\n", a[max]);
free(a);
return 0;
}
7. 问题 N: 最大值和最小值
7.1. 解题思路
- 找到最大最小的位置,输出它们保留两位小数的结果
7.2. 解题方法
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <time.h>
#include <stdbool.h>
int main(int argc, char *argv[])
{
int n;
int max = 0;//假设下标0是最大的数
int min = 0;//假设下标0是最大的数
scanf("%d", &n);
double *a = (double*)malloc(sizeof(double) * n);//等价于a[n]
for (int i = 0; i < n; i++)
{
scanf("%lf", a + i);
if (a[max] < a[i])//后面的数比最大的数还要大
{
max = i;//更新最大值的下标
}
else if (a[min] > a[i])//后面的数比最小的数还要小
{
min = i;//更新最小值的下标
}
}
printf("%.2f\n", a[max] - a[min]);//输出保留2位小数的结果
free(a);
return 0;
}
8. 问题 O: 复制数组
8.1. 解题思路
- 这个题目只要知道数组的下标就能写出来
8.2. 解题方法
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <time.h>
#define N 7
int main(int argc, char *argv[])
{
int p[N];
int a[3];
for (int i = 0; i < N; i++) {
scanf("%d", p + i);
}
for (int i = 2; i < 5; i++)//下标2就是第三个数,因为下标从0开始数
a[i - 2] = p[i];
for (int i = 0; i < 3; i++)
printf("%d ", a[i]);
return 0;
}
9. 问题 P: 简单的二维数组
9.1. 解题思路
- 观察打印的图形,发现一共会打印n行,并且每行打印的字符个数是递增1的。
- 并且每行打印的字符个数等于当前行的数字。例如第一行打印一个字符,第二行打印两个字符。
9.2. 解题方法
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <time.h>
int main(int argc, char *argv[])
{
int n = 0;
scanf("%d", &n);
for (int i = 1; i <= n; i++) {//从1开始数,到n,一共打印n行
for (int j = 1; j <= i; j++)//通过观察我们发现打印的个数等于行数
printf("$");
putchar('\n');
}
return 0;
}
10. 问题 Q: 二维数组的简单应用
10.1. 解题思路
- 遍历数组就行了,没有什么好说的
10.2. 解题方法
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <time.h>
void copy(int (*p)[5],int (*a)[5]);//等价于p[][5]
int main(int argc, char *argv[])
{
int a[2][5],b[2][5];
for (int i = 0; i < 2; i++)
for(int j = 0; j < 5; j++)
scanf("%d", *(a + i) + j);
copy(a,b);
for (int i = 0; i < 2; i++){
for(int j = 0; j < 5; j++)
printf("%d ", b[i][j]);
putchar('\n');
}
return 0;
}
void copy(int (*p)[5], int (*a)[5])
{
//遍历二维数组
for (int i = 0; i < 2; i++){
for(int j = 0; j < 5; j++)
a[i][j] = p[i][j];
}
}
11. 问题 R: 数组的简单应用
11.1. 解题思路
- 遍历数组,然后加起来就行了
11.2. 解题方法
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <time.h>
int main(int argc, char *argv[])
{
int a[5],b[5];
int res[5];
for (int i = 0; i < 5; i++)
scanf("%d", a + i);
for (int i = 0; i < 5; i++)
scanf("%d", b + i);
for (int i = 0; i < 5; i++)
res[i] = a[i] + b[i];
for (int i = 0; i < 5; i++)
printf("%d ", res[i]);
return 0;
}
12. 问题 S: 数组的简单应用(2)
12.1. 解题思路
- 和上面的题一样,都是遍历数组
12.2. 解题方法
#include <stdio.h>
int main()
{
int a[2][5];
for (int i = 0; i < 2; i++)
for (int j = 0; j < 5; j++)
scanf("%d", &a[i][j]);
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 5; j++)
printf("%d ", a[i][j]);
putchar('\n');
}
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 5; j++)
a[i][j] = a[i][j] * 2;
}
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 5; j++)
printf("%d ", a[i][j]);
putchar('\n');
}
return 0;
}
13. 问题 T: 数组处理
13.1. 解题思路
- 输入数,并赋值到数组里面去
- 求出每行的平均值
- 计算整个数组的平均值
- 找到最大的并打印结果
13.2. 解题方法
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#define N 2
#define M 5
void scan(int (*a)[M], int size, int size1);//给二维数组a赋值
double average(int *a,int size);//计算平均值
int find_max(int *a, int size);//找到最大的值并返回
int main(void)
{
int a[N][M];
double aver[3];
int max = 0;
scan(a, N, M);
for(int i = 0; i < N; i++) {
aver[i] = average(a[i], M);
}
aver[2] = average(*a, N * M);
max = find_max(*a, N * M);
for (int i = 0; i < 3; i++) {
printf("%d ", (int)aver[i]);
}
printf("%d", max);
return 0;
}
void scan(int (*a)[M], int size, int size1)
{
for (int i = 0; i < size; i++) {
for (int j = 0; j < size1; j++) {
scanf("%d", a[i] + j);//等价于&a[i][j]
}
}
}
double average(int *a,int size)
{
double res = 0;
int sum = 0;
for (int j = 0; j < size; j++) {
sum += a[j];//求和
}
res = 1.0 * sum / size;//算平均值
return res;
}
int find_max(int *a, int size)
{
int max = 0;
for (int j = 1; j < size; j++) {
if (a[max] < a[j]) {//还有更大的
max = j;//更新最大值的下标
}
}
return a[max];
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· .NET10 - 预览版1新功能体验(一)