数组
1.排序
1.1冒泡排序
过程:
(1)比较第一个数与第二个数,若为逆序a[0]>a[1],则交换;然后比较第二个数与第三个数;依次类推,直至第n-1个数和第n个数比较为止,第一趟冒泡排序,结果最大的数被安置在最后一个元素位置上。
(2)对前n-1个数进行第二趟冒泡排序,结果使次大的数被安置在第n-1个元素位置
(3)重复上述过程,共经过n-1趟冒泡排序后,排序结束
原理:
第一遍每一个数都会被比较到,总会排到最大的数,那么最大的数肯定会排到最后面,因为只要比前面数大就会排到后面。后面排序同理。
两两比较,第i个和i+1个比较
例如:int a[5]={5,4,3,2,1};
第一轮 | 第二轮 | 第三轮 | 第四轮 |
45321 | 34215 | 23145 | 12345 |
43521 | 32415 | 21345 | |
43251 | 32145 | ||
43215 |
i=0: 第一轮:5-1=4次排序
i=1: 第二轮:5-2=3次排序
i=2: 第三轮:5-3=2次排序
i=3: 第四轮:5-4=1次排序
外层轮数 = 个数 - 1 = N - 1 (i=0;i<N-1;i++)
每轮排序次数= 个数-轮数 (=N-i-1)
例:
#include <stdio.h>
#include <string.h>
int main()
{
int a[10];
int b;
printf("请输入数");
for (int c = 0; c < 10; c++)
{
scanf("%d", &a[c]);
}
for (int i = 0; i < 9; i++)
{
for (int j = 0; j < 10 - i - 1; j++)
{
if (a[j] > a[j + 1])
{
b = a[j];
a[j] = a[j + 1];
a[j + 1] = b;
}
}
}
for (int i = 0; i < 10; i++)
{
printf("%d\n", a[i]);
}
return 0;
}
1.2选择排序
过程:
(1)首先通过n-1次比较,从n个数中找出最小的, 将它与第一个数交换—第一趟选择排序,结果最小的数被安置在第一个元素位置上。
(2)再通过n-2次比较,从剩余的n-1个数中找出关键字次小的记录,将它与第二个数交换—第二趟选择排序
(3)重复上述过程,共经过n-1趟排序后,排序结束
第一次排序存取最小值,然后与第一个元素做交换,以此类推。
轮数i:个数-1 = N-1 (同冒泡排序)
每轮比较次数:从a[i]和它后一个a[i+1]开始比较,一直到最后一个a[N-1]
(只要有更小的就记录其下标)
#include <stdio.h>
#define N 5
int main()
{
int a[N] = {5, 4, 3, 2, 1};
int b, man;
for (int i = 0; i < N - 1; i++)
{
man = i;
for (int j = i + 1; j < N; j++)
{
if (a[man] > a[j])
{
man = j;
}
}
if (i!= man)
{
b = a[i];
a[i] = a[man];
a[man] = b;
}
}
for (int i = 0; i < N; i++)
printf("%d ", a[i]);
printf("\n");
return 0;
}
2.二维数组
2.1格式
存储类型 数据类型 数组名[行数][列数]
int a[2][3];
2.2访问元素
数组名[行下标][列下标];(下标都是从0开始)
a[0][0] : 第一行第一列的元素
a[i-1][j-1]: 最后一行最后一列的元素
注意:
- 行下标和列下标都不能越界。
- 行数可以省略,列数不能省略。
- 数组名代表的是第一行的地址
2.3二维数组数组名
二维数组组名代表第一行地址
例:int a[][3]={1,2,3,4,5,6};
a:第一行地址
a+1:第二行地址
2.4数组元素个数和二维数组大小
元素个数:行数*列数
二维数组大小:
1.数据类型大小*行数*列数
2.sizeof(数组名);
2.5初始化
定义时全部初始化
int a[2][3] = {1,2,3,4,5,6}; //顺序赋值
int a1[2][3] = {{1,2,3},{4,5,6}}; //按行赋值
定义时部分初始化, 未初始化元素值为0
int a2[2][3] = {1,2,3,4}; //顺序赋值 1 2 3 4 0 0
int a3[2][3] ={{1,2},{3,4}}; //按行赋值 1 2 0 3 4 0
未初始化
随机值,需要单独赋值 a[i][j]=
2.6遍历二维数组
循环嵌套,外层循环行数,内存循环列数。
int a[M][N]={};
for(i=0;i<M;i++) //行下标循环
{
for(j=0;j<N;j++) //列下标
{
scanf/prinf
}
}
例:
#include <stdio.h>
int main()
{
int a[3][3] = {1, 2, 3, 4, 5, 6};
// printf("%d %d %d\n",a[0][0],*a[0],*(*(a)));
// printf("%d %d %d\n",a[0][1],*(a[0]+1),*(*a+1));
// printf("%d %d %d\n",a[1][1],*(a[1]+1),*(*(a+1)+1));
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
{
printf("%d ", a[i][j]);
printf("%d ", *(a[i] + j));
printf("%d ", *(*(a + i) + j));
}
printf("\n");
}
}
2.7内分配
行地址
1、二维数组中,数组名a本质是第一行地址,其数值还是数组a首元素a[0][0]的地址,即&a[0][0],第一行第一个元素的地址;
2、二维数组中,数组名a+1本质是第二行地址,其数值还是数组a的元素a[1][0]的地址,即&a[1][0],第二行第一个元素的地址;
也可以在行地址前面加*表示将行地址降级成为列地址
列地址
1、二维数组中,a[0]的值,即该数组的首元素a[0][0]的地址,即&a[0][0];
2、二维数组中,a[0]+1的值,是数组元素a[0][1]的值,即&a[0][1];
总结:二维数组i行j列表示元素和地址的方式
地址:
&a[i][j]
a[i]+j
*(a+i)+j
内容:
a[i][j]
*(a[i]+j)
*(*(a+i)+j)
例:有一个3x4的矩阵(元素值不相同),要求输出其中最大值以及它的行号和列号
#include <stdio.h>
int main()
{
int a[3][4] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 98, 58, 63};
int x = 0, y = 0;
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 4; j++)
{
if (a[i][j] > a[x][y])
{
x = i;
y = j;
}
}
}
printf("%d %d %d", a[x][y], x + 1, y + 1);
return 0;
}
#include<stdio.h>
int main(int argc, char const *argv[])
{
int a[3][4]={1,2,3,4,5,6,7,8};
int max=a[0][0],h=0,l=0;
for(int i=0;i<3;i++)
{
for(int j=0;j<4;j++)
{
if(max<a[i][j])
{
max=a[i][j];
h=i;
l=j;
}
}
}
printf("%d %d %d\n",max,h,l);
return 0;
}
例:杨辉三角
#include<stdio.h>
int main(){
int a[10][10];
for(int i=0;i<10;i++){
a[i][0]=1;
a[i][i]=1;
}
for(int i=2;i<10;i++){
for(int j=1;j<i;j++){
a[i][j]=a[i-1][j]+a[i-1][j-1];
}
}
for(int i=0;i<10;i++){
for(int j=0;j<=i;j++){
printf("%d ",a[i][j]);
}
printf("\n");
}
}