一、数组
1. 数组的概念
数组是一种用于保存数据的数据结构。在 C 语言中,数组的元素在内存中连续存放。
数组的长度在定义时确定,定义后不能直接改变。
2. 数组的定义与初始化
(1)定义数组
数据类型 数组名[数组长度];
例如:
intarr[5];表示定义了一个名为arr的数组,可以存储 5 个int类型的数据。
(2)定义数组并初始化
intarr[5]={1,2,3,4,5};也可以省略数组长度:
intarr[]={1,2,3,4,5};此时,编译器会根据初始化列表确定数组长度。
(3)数组初始化的注意事项
intarr[5]={0};可以将数组中的所有元素初始化为0。
如果写成:
intarr[5]={1};则数组元素为:
1 0 0 0 0这是因为使用初始化列表时,未指定初始值的元素会被初始化为对应类型的零值。
如果希望数组中的所有元素都初始化为1,可以使用循环:
intarr[5];for(inti=0;i<5;i++){arr[i]=1;}注意:C 语言中,未初始化的局部数组元素没有确定的初始值,不能直接当作0使用。
3. 数组下标
数组下标从0开始。
如果数组长度为len,则下标范围为:
0 到 len - 1注意:C 语言数组越界时不一定报错。
4. 数组的存储与读取
(1)存储数据
数组名[下标] = 数据;
例如:
arr[0]=10;表示将10存入数组arr的第一个元素。
(2)读取数据
数据类型 变量名=数组名[下标];例如:
intx=arr[0];表示读取arr[0]中的数据,并将其赋值给变量x。
注意:[]只能写在数组名后面。
5. 数组遍历
数组遍历是指依次访问数组中的每个元素。
由于存储和读取数组元素通常是重复操作,因此一般使用循环完成。
例如:
intarr[5]={1,2,3,4,5};for(inti=0;i<5;i++){printf("%d ",arr[i]);}输出:
1 2 3 4 56. 计算数组长度
sizeof用于计算对象占用的内存大小,单位是字节。
例如:
intarr[5]={0};intsize=sizeof(arr);intlen=sizeof(arr)/sizeof(arr[0]);printf("size = %d\n",size);printf("len = %d\n",len);其中:
sizeof(arr):计算整个数组占用的字节数。sizeof(arr[0]):计算数组第一个元素占用的字节数。sizeof(arr) / sizeof(arr[0]):计算数组元素的数量。
假设int占用 4 个字节,则输出为:
size = 20 len = 5二、数组排序
排序是指按照一定的规则重新排列数组中的元素。
本次涉及三种排序算法:冒泡排序、选择排序和插入排序。
1. 冒泡排序
(1)基本思想
冒泡排序通过比较相邻的两个元素,根据大小关系决定是否交换位置。
以从小到大排序为例:
- 比较相邻的两个元素。
- 如果前一个元素大于后一个元素,就交换它们的位置。
- 不断比较后续的相邻元素。
- 一轮结束后,未排序部分中最大的元素会移动到末尾。
- 重复以上过程,直到排序完成。
(2)代码实现
for(intj=0;j<len-1;j++){for(inti=0;i<len-1-j;i++){if(arr[i]>arr[i+1]){inttemp=arr[i];arr[i]=arr[i+1];arr[i+1]=temp;}}}(3)代码分析
外层循环:
for(intj=0;j<len-1;j++)控制排序的轮数。
内层循环:
for(inti=0;i<len-1-j;i++)负责比较相邻元素。每完成一轮,末尾就会多一个已经排好序的元素,因此下一轮可以减少一次比较。
(4)交换两个元素
inttemp=arr[i];arr[i]=arr[i+1];arr[i+1]=temp;2. 选择排序
(1)基本思想
选择排序每一轮都在未排序区间中寻找最小值,记录它的下标,然后将它交换到未排序区间的最前面。
例如:
原数组:5 2 8 1 4 第一轮:1 2 8 5 4第一轮找到最小值1,将它与第一个元素5交换。
之后继续对剩余的未排序区间进行相同操作,最终完成排序。
(2)代码实现
for(inti=0;i<len-1;i++){intminIndex=i;for(intj=i+1;j<len;j++){if(arr[j]<arr[minIndex]){minIndex=j;}}if(minIndex!=i){inttemp=arr[i];arr[i]=arr[minIndex];arr[minIndex]=temp;}}(3)代码分析
i:当前未排序区间的起始位置。minIndex:记录当前找到的最小元素的下标。j:遍历未排序区间,寻找最小值。- 内层循环结束后,将最小元素交换到当前区间的最前面。
注意:minIndex保存的是元素的下标,而不是元素的值。
3. 插入排序
(1)基本思想
插入排序将数组分为已排序部分和未排序部分。
每次取出未排序部分的第一个元素,将已排序部分中比它大的元素向后移动,再将这个元素插入正确的位置。
(2)代码实现
for(inti=1;i<len;i++){intkey=arr[i];intj=i-1;while(j>=0&&arr[j]>key){arr[j+1]=arr[j];j--;}arr[j+1]=key;}(3)代码分析
intkey=arr[i];保存当前需要插入的元素。
intj=i-1;从当前元素前面的位置开始比较。
while(j>=0&&arr[j]>key)当下标没有越界,并且当前元素大于key时,继续循环。
arr[j+1]=arr[j];j--;将较大的元素向右移动一格,为key腾出位置。
arr[j+1]=key;将key放到正确的位置。
注意:j >= 0用于保证访问的下标不越界;&&具有短路求值特性,当j >= 0不成立时,不会继续计算右侧条件。
三、完整代码:输入、冒泡排序与输出
#include<stdio.h>// 冒泡排序voidbubbleSort(intarr[],intlen){for(intj=0;j<len-1;j++){for(inti=0;i<len-1-j;i++){if(arr[i]>arr[i+1]){inttemp=arr[i];arr[i]=arr[i+1];arr[i+1]=temp;}}}}// 选择排序voidselectSort(intarr[],intlen){for(inti=0;i<len-1;i++){intminIndex=i;// 记录最小值下标for(intj=i+1;j<len;j++){if(arr[j]<arr[minIndex]){minIndex=j;}}//交换最小值和当前i位置元素inttemp=arr[i];arr[i]=arr[minIndex];arr[minIndex]=temp;}}// 插入排序voidinsertSort(intarr[],intlen){for(inti=1;i<len;i++){intkey=arr[i];intj=i-1;while(j>=0&&arr[j]>key){arr[j+1]=arr[j];j--;}arr[j+1]=key;}}// 打印数组voidprintArray(intarr[],intlen){for(inti=0;i<len;i++){printf("%d ",arr[i]);}printf("\n");}intmain(){intarr[5]={0};intlen=sizeof(arr)/sizeof(arr[0]);printf("请输入5个整数:\n");for(inti=0;i<len;i++){scanf("%d",&arr[i]);}// 拷贝数组,保证每种排序使用原始数据intarr1[5],arr2[5],arr3[5];for(inti=0;i<5;i++){arr1[i]=arr[i];arr2[i]=arr[i];arr3[i]=arr[i];}printf("冒泡排序结果:");bubbleSort(arr1,len);printArray(arr1,len);printf("选择排序结果:");selectSort(arr2,len);printArray(arr2,len);printf("插入排序结果:");insertSort(arr3,len);printArray(arr3,len);return0;}四、重点总结
数组
- 数组用于保存多个相同类型的数据。
- 数组元素在内存中连续存放。
sizeof(arr) / sizeof(arr[0])用于计算数组长度。- C 语言不会自动保证数组越界时一定报错。
排序算法
- 冒泡排序:比较相邻元素,必要时交换。
- 选择排序:寻找未排序区间中的最小值,再交换到前面。
- 插入排序:将当前元素插入前面已排序部分的正确位置。