ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

C语言程序设计题|有序数组插入数字冒泡排序

C语言程序设计题|有序数组插入数字冒泡排序

C语言程序设计题|有序数组插入数字冒泡排序

题目

有一个已经排好序的数组a[11] = {1,5,6,7,13,22,27,37,38,45}(原有10个升序元素,预留1个位置)。
输入一个数,将数字放到数组末尾,再使用冒泡排序,实现整体升序,最后输出数组。

说明:题目本意是“找到位置插入”;如果你要求用冒泡排序实现,思路是:先把数字放到数组最后,再对全部11个元素冒泡升序。

完整代码

#include<stdio.h>intmain(){inta[11]={1,5,6,7,13,22,27,37,38,45};intnum,i,j,temp;printf("请输入要插入的整数:");scanf("%d",&num);// 第一步:把输入的数放到数组最后一个位置a[10]=num;// 第二步:冒泡排序,对全部11个元素升序排列for(i=0;i<10;i++){for(j=0;j<10-i;j++){if(a[j]>a[j+1]){temp=a[j];a[j]=a[j+1];a[j+1]=temp;}}}// 第三步:输出插入排序后的数组printf("处理后的有序数组:\n");for(i=0;i<11;i++){printf("%d ",a[i]);}printf("\n");return0;}

代码逐行讲解(小白版)

下面把这段代码拆成几块,一块一块地看,看完你就能自己写出来了。

1. 头文件与变量声明

#include<stdio.h>intmain(){inta[11]={1,5,6,7,13,22,27,37,38,45};intnum,i,j,temp;
  • #include <stdio.h>:告诉编译器“我要用输入输出功能”,printf和scanf都来自这里。
  • int main():程序的入口,C 程序从main的第一行开始执行。
  • int a[11] = {...}:定义一个能装 11 个整数的数组,前 10 个位置填好了升序数字,第 11 个位置(下标10)暂时是0,留给新数字。
  • num存用户输入的数,i、j是循环计数器,temp是交换两个数时的“临时中转站”。

小知识:C 语言数组下标从0开始,所以 11 个元素的下标是0 ~ 10,最后一个就是a[10]。

2. 读入要插入的数字

printf("请输入要插入的整数:");scanf("%d",&num);
  • printf只是在屏幕上打印一句提示,不影响逻辑。
  • scanf("%d", &num)从键盘读一个整数存进num。注意&不能丢,它表示“把值放到这个变量的地址里”。

3. 把新数字放到数组末尾

a[10]=num;

这一步就是题目要求的“放到数组末尾”。此时数组变成 11 个元素,但顺序可能被打乱——比如输入3,数组就是1,5,6,7,13,22,27,37,38,45,3,3明显不在正确位置。

4. 冒泡排序:把 11 个数重新排好

for(i=0;i<10;i++){for(j=0;j<10-i;j++){if(a[j]>a[j+1]){temp=a[j];a[j]=a[j+1];a[j+1]=temp;}}}

冒泡排序的核心思想:相邻两个数比较,大的往后挪,一轮下来最大的数就“冒”到了最后。

  • 外层i控制“跑几轮”。11 个数最多需要 10 轮,所以i < 10。
  • 内层j控制“这一轮比较到哪”。因为每跑完一轮,末尾就多一个已经排好的数,所以比较范围逐轮缩小:j < 10 - i。
  • if(a[j] > a[j+1]):如果前一个比后一个大,说明顺序反了,需要交换。
  • 交换三行是固定套路,必须借助temp:
temp=a[j];// 先把 a[j] 存起来a[j]=a[j+1];// 把小的挪到前面a[j+1]=temp;// 把存起来的大的放到后面

为什么不能直接a[j] = a[j+1]; a[j+1] = a[j];?因为第一句执行完,a[j]原来的值就被覆盖了,第二句拿到的已经是新值,等于没换。所以必须用temp暂存。

5. 输出结果

printf("处理后的有序数组:\n");for(i=0;i<11;i++){printf("%d ",a[i]);}printf("\n");return0;
  • 循环i从0到10,正好遍历 11 个元素。
  • printf("%d ", a[i])中%d是整数的占位符,后面跟一个空格,让数字之间分开。
  • 最后的printf("\n")换行,return 0表示程序正常结束。

6. 跑一遍看看

假设输入20:

步骤数组内容
初始1, 5, 6, 7, 13, 22, 27, 37, 38, 45, 0
放入末尾1, 5, 6, 7, 13, 22, 27, 37, 38, 45, 20
冒泡排序后1, 5, 6, 7, 13, 20, 22, 27, 37, 38, 45

输出:1 5 6 7 13 20 22 27 37 38 45

7. 几个新手常踩的坑

  • 数组越界:a[11]只有下标0~10,写a[11]就越界了,可能崩溃或输出乱码。
  • 循环边界写错:内层写成j < 11 - i会访问a[11],同样越界;正确是j < 10 - i。
  • 忘了&:scanf("%d", num)会读不到值甚至崩溃。
  • 交换不用temp:两个数会变成一样,排序结果错误。
  • 只排 10 个元素:如果循环写成i < 9或输出只到i < 10,最后一个数就漏掉了。

8. 不用冒泡排序的解题思路

如果题目没有强制要求冒泡排序,其实这道题的本质是「有序数组插入」,不需要把 11 个数重新排一遍。核心思路只有一句话:从后往前找位置,边找边把元素往后挪,找到空位就把新数字放进去。

思路拆解
  1. 确定起点:原数组有 10 个有效元素,下标是0 ~ 9,新数字最终要放到下标10的位置,所以从i = 9开始往前看。
  2. 比较并后移:只要a[i]比num大,说明num应该排在它前面,于是把a[i]往后挪一位(a[i+1] = a[i]),然后i--继续往前比。
  3. 找到空位:当遇到一个不大于num的元素,或者i已经减到-1(说明num比所有元素都小),循环结束,此时a[i+1]就是num该待的位置。
  4. 放入新数字:执行a[i+1] = num,插入完成,数组依然保持升序。
用图理解

是

否

输入 num

i = 9(从最后一个有效元素开始)

i >= 0 且 a[i] > num ?

a[i+1] = a[i](元素后移一位)

i--

a[i+1] = num(放入空位)

输出 11 个元素

举个例子

原数组1,5,6,7,13,22,27,37,38,45,输入20:

步骤i比较动作数组变化
1945 > 2045 后移...,38,45,45
2838 > 2038 后移...,37,38,45
3737 > 2037 后移...,27,37,38
4627 > 2027 后移...,22,27,37
5522 > 2022 后移...,13,22,27
6413 > 20不成立停止空位在下标 5
7——a[5] = 201,5,6,7,13,20,22,27,37,38,45

整个过程只比较了 6 次、移动了 5 次,比冒泡排序快得多。

为什么这样是对的

因为原数组已经有序,所有比num大的元素一定连续地排在数组尾部。把它们整体后移一位,中间自然就空出一个位置,而这个位置恰好满足「左边都不大于num,右边都不小于num」,插入后数组仍然有序。

需要注意的边界
  • num比所有元素都小:i会一路减到-1,循环因i >= 0不成立而退出,此时a[0] = num,正确。
  • num比所有元素都大:第一次比较就不成立,a[10] = num,相当于直接放到末尾,也正确。
  • i >= 0不能省:少了它,当num最小时会访问a[-1],属于越界,可能崩溃或产生乱码。
三种写法怎么选
写法时间复杂度适用场景
放到末尾 + 冒泡排序O(n²)题目明确要求练习排序
从后往前找位置插入O(n)有序数组插入的标准解法
找到位置后整体后移(先找再移)O(n)思路更直观,但要多写一个循环

小结:这道题的关键不是「排序」,而是「插入」。只要抓住「数组有序」这个条件,就能把 O(n²) 的排序优化成 O(n) 的一趟扫描。

8. 更简洁的方案(推荐掌握)

题目要求用冒泡排序,时间复杂度是 O(n²)。但既然原数组已经有序,其实没必要全部重排——从后往前找位置,边找边后移,一趟就能搞定,时间复杂度 O(n)。

#include<stdio.h>intmain(){inta[11]={1,5,6,7,13,22,27,37,38,45};intnum,i;printf("请输入要插入的整数:");scanf("%d",&num);// 从最后一个元素开始,比 num 大的都往后挪一位i=9;while(i>=0&&a[i]>num){a[i+1]=a[i];i--;}// 空出来的位置放 numa[i+1]=num;printf("处理后的有序数组:\n");for(i=0;i<11;i++){printf("%d ",a[i]);}printf("\n");return0;}

核心就三行:

while(i>=0&&a[i]>num)// 从后往前找第一个不大于 num 的位置{a[i+1]=a[i];// 比 num 大的元素整体后移一位i--;}a[i+1]=num;// 空位就是 num 该待的地方

对比一下两种写法:

对比项冒泡排序版插入版(本方案)
时间复杂度O(n²)O(n)
比较次数约 55 次最多 10 次
移动次数大量交换最多 10 次后移
代码长度较长更短
适用场景练习循环与交换有序数组插入的标准解法

注意:while里的i >= 0不能省。如果输入的数比所有元素都小(比如0),i会一路减到-1,此时a[i+1]正好是a[0],把num放在最前面,逻辑依然正确;但少了这个判断就会越界访问a[-1]。

如果题目没有强制要求冒泡排序,这个写法更符合“有序数组插入”的本意,也更值得记住。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进