一、知识要点、
插入排序是一种简单直观的排序算法,它的工作方式类似于我们整理扑克牌。
基本原理:
插入排序通过构建有序序列来工作。它每次从无序序列中取出一个元素,然后将其插入到已排序序列的适当位置。这个过程重复进行,直到所有元素都已插入到已排序序列中。
算法步骤:
-
初始化:假设数组的第一个元素已经是一个有序序列。
-
遍历数组:从第二个元素开始,依次取出当前元素。
-
比较和插入:将当前元素与已排序序列中的元素进行比较,找到合适的位置插入当前元素。
-
重复 :重复上述过程,直到所有元素都已插入到有序序列中。
详细步骤示例:
假设有一个数组:[5, 2, 4, 6, 1, 3]
-
初始状态 :已排序序列
[5]
,未排序序列[2, 4, 6, 1, 3]
。 -
取第二个元素 2 :
与已排序序列的 5 比较,发现 2 < 5,将 5 后移一位。
插入 2 到合适位置,已排序序列变为
[2, 5]
。 -
取第三个元素 4 :
与 5 比较,4 < 5,将 5 后移一位。
与 2 比较,4 > 2,插入到 2 和 5 之间,已排序序列变为
[2, 4, 5]
。 -
重复以上过程
性能分析:
时间复杂度:
-
最好情况:O(n)(当输入数组已经是有序的)
-
最坏情况:O(n²)(当输入数组是逆序的)
-
平均情况:O(n²)
空间复杂度:O(1)(只需要一个额外的临时变量)
稳定性:稳定排序(相同值的元素不会交换顺序)
优点
-
简单易实现:代码结构简单,容易理解和实现。
-
高效处理小规模数据:对于小规模数据,插入排序的性能较好。
-
适应性强:对于部分有序的数组,插入排序的性能表现优秀。
缺点
-
对大规模数据效率低:时间复杂度为 O(n²),在处理大规模数据时效率较低。
-
不适合逆序数据:当数据完全逆序时,需要最多的交换操作。
插入排序是一种简单且直观的排序算法,适用于小规模数据或部分有序的数据。尽管在大规模数据上效率不高,但它的简单性和稳定性使其在某些特定场景中仍然具有应用价值。
二、代码解析
1.结构体定义

int* array
:
这是一个指向整数的指针,用于存储用户输入的原始数据。
它指向一个动态分配的内存区域,该区域的大小由用户输入的数组元素数量决定。
int* sortedArray
:
这也是一个指向整数的指针,用于存储排序后的数据。
和 array
类似,它同样指向一个动态分配的内存区域,其大小与 array
相同。
在程序中,sortedArray
初始时会被复制 array
的内容,然后在排序过程中被修改。
int size
:
这是一个整数,用于存储数组的大小(即数组中元素的数量)。它定义了 array
和 sortedArray
所指向的内存区域的大小。
2. 初始化函数initSortSystem

参数 :SortSystem* sys
,这是一个指向 SortSystem
结构体的指针,表示函数将对这个结构体进行操作。
sys->array = NULL;
: 表示当前没有为原始数据分配内存。
sys->sortedArray = NULL;
: 表示当前没有为排序后的数据分配内存。
sys->size = 0;
: 表示当前数组的大小为 0,即没有数据。
3. 输入数组函数inputArray
3.1 函数定义:

返回类型 :void
,表示该函数不返回任何值。
参数 :SortSystem* sys
,这是一个指向 SortSystem
结构体的指针,表示函数将对这个结构体进行操作。
3.2 获取数组大小

提示用户输入:首先提示用户输入数组元素的数量。
读取输入 :使用 scanf_s
函数读取用户输入的整数,并将其存储到 sys->size
中。
3.2 动态内存分配

分配内存 :为 sys->array
动态分配内存,内存大小为 sys->size * sizeof(int)
。
检查分配是否成功 :如果 malloc
返回 NULL
,表示内存分配失败。此时输出错误信息并退出程序。
3.4. 用户输入数组元素

提示用户输入元素:提示用户输入指定数量的整数。
读取元素 :使用循环读取用户输入的每个整数,并将其存储到 sys->array
中。
3.5. 复制数组到排序数组

分配内存 :为 sys->sortedArray
动态分配内存,内存大小同样为 sys->size * sizeof(int)
。
检查分配是否成功 :如果 malloc
返回 NULL
,表示内存分配失败。此时输出错误信息,释放之前分配的 sys->array
内存,并退出程序。
复制数据 :使用循环将 sys->array
中的数据复制到 sys->sortedArray
中。
3.6 函数作用
初始化数组 :从用户那里获取数组元素的数量和具体元素,初始化 SortSystem
结构体中的 array
和 sortedArray
。
动态内存分配:根据用户输入的数组大小动态分配内存,确保程序能够处理不同大小的输入数据。
数据备份 :将原始数据复制到 sortedArray
,以便后续的排序操作不会影响原始数据。
后两个点也是该函数处理的优点。
4. 显示数组函数displayArray
4.1 函数定义

返回类型 :void
,表示该函数不返回任何值。
参数:
const int* array
:指向整数数组的指针,表示要显示的数组。
int size
:数组的大小。
int currentStep
:当前排序步骤。
int currentElem
:当前正在操作的元素的索引。
4.2 函数体:

4.3 代码分析
① 清屏(注释掉)
system("cls")
是 Windows 系统下的清屏命令。在 Unix/Linux 系统中,应使用 system("clear")
。
由于 system("cls")
可能导致程序依赖于特定的操作系统,或者在某些环境下不可用,因此被注释掉了。
②显示当前排序步骤

作用:输出当前排序步骤的编号,帮助用户了解排序的进度。
③遍历并显示数组元素

遍历数组 :使用 for
循环遍历数组的每个元素。
高亮当前元素:
当前操作的元素(currentElem
)使用红色显示,以便于用户观察。
使用了 ANSI 转义序列 \033[1;31m
设置文本颜色为红色,\033[0m
重置颜色。
{
ANSI 转义序列兼容性 :\033[1;31m
和 \033[0m
是 ANSI 转义序列,可能不被所有终端支持。在不支持的终端中,颜色显示可能无效。
}
④换行和暂停(注释掉)

换行:在输出完成后添加两个空行,使输出更易读。
暂停(注释掉) :sleep(1)
会使程序暂停 1 秒,以便用户有时间观察每一步的变化。由于可能需要额外的头文件(如 <unistd.h>
),因此被注释掉了。
5. 插入排序操作的实现
5.1 函数定义:

返回类型 :void
,表示该函数不返回任何值。
参数 :SortSystem* sys
,这是一个指向 SortSystem
结构体的指针,表示函数将对这个结构体中的数组进行排序。
5.2 变量声明:

key
:用于存储当前要插入的元素。
j
:用于标记当前正在比较的元素的位置。
5.3 外层循环

循环变量 :i
从 1 开始,遍历整个数组。
作用:从数组的第二个元素开始,依次将每个元素插入到前面已排序的子数组中。
5.4 内层循环:将大于key的元素向右移动

条件判断 :当 j
不小于 0 且当前元素大于 key
时,执行循环体。
元素移动 :将当前元素向右移动一位,为插入 key
腾出位置。
更新 j
:j
减 1,继续比较前一个元素。
显示中间状态 :调用 displayArray
函数显示当前数组状态,便于观察排序过程。
5.5 插入操作

将 key
插入到正确的位置。
5.6 显示交换后的状态

再次调用 displayArray
函数显示插入后的数组状态。
在排序完成后输出提示信息。
6. 显示函数displayResult
用于显示排序系统的原始数据和排序后的结果。

6.1 函数定义:
参数 :const SortSystem* sys
,这是一个指向 SortSystem
结构体的指针,表示函数将读取这个结构体中的数据但不会修改它。
6.2 函数体:
① 显示标题
输出一个标题,用于分隔和标识排序结果部分,使输出更清晰。
② 检查数组大小

检查 SortSystem
结构体中的 size
是否为 0。
如果 size
为 0,表示用户尚未输入数据,输出提示信息并退出函数。
③ 显示原始数据

输出原始数据。
使用 for
循环遍历 sys->array
,并依次输出每个元素。
每个元素之间以空格分隔,最后换行。
④ 显示排序结果

输出排序后的结果。
使用 for
循环遍历 sys->sortedArray
,并依次输出每个元素。
每个元素之间以空格分隔,最后换行。
7. 运行runSortSystem
的函数
- 初始化排序系统

定义一个 SortSystem
类型的变量 sys
,并调用 initSortSystem
函数对其进行初始化。
确保 sys
结构体的成员变量处于初始状态,避免未定义行为。
使用 switch
语句处理不同的用户选择,让代码逻辑变得清晰。
该函数是整个排序系统的主控制中心,负责显示菜单、获取用户输入并调用相应的功能函数。
通过循环持续运行,直到用户选择退出。
三、完整代码
cs
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
// 定义结构体存储排序系统所需信息
typedef struct
{
int* array; // 存储用户输入的数组
int* sortedArray; // 存储排序后的数组
int size; // 数组大小
} SortSystem;
// 函数声明
void initSortSystem(SortSystem* sys);
void inputArray(SortSystem* sys);
void displayArray(const int* array, int size, int currentStep, int currentElem);
void insertionSort(SortSystem* sys);
void menu();
void runSortSystem();
void displayResult(const SortSystem* sys);
void menu()
{
printf("\n===== 排序系统主菜单 =====\n");
printf("1. 输入数据\n");
printf("2. 执行插入排序\n");
printf("3. 查看原始数据\n");
printf("4. 查看排序结果\n");
printf("5. 退出系统\n");
printf("请选择操作: ");
}
int main()
{
printf("===== 基于顺序表的插入排序系统 =====\n");
runSortSystem();
return 0;
}
// 初始化排序系统
void initSortSystem(SortSystem* sys)
{
sys->array = NULL;
sys->sortedArray = NULL;
sys->size = 0;
}
// 输入数组
void inputArray(SortSystem* sys)
{
printf("请输入数组元素的数量: ");
scanf_s("%d", &sys->size);
// 分配内存
sys->array = (int*)malloc(sys->size * sizeof(int));
if (sys->array == NULL)
{
printf("内存分配失败!\n");
exit(1);
}
printf("请输入 %d 个整数:\n", sys->size);
for (int i = 0; i < sys->size; i++)
{
scanf_s("%d", &sys->array[i]);
}
// 复制一份原始数组到排序数组
sys->sortedArray = (int*)malloc(sys->size * sizeof(int));
if (sys->sortedArray == NULL)
{
printf("内存分配失败!\n");
free(sys->array);
exit(1);
}
for (int i = 0; i < sys->size; i++)
{
sys->sortedArray[i] = sys->array[i];
}
}
// 显示数组
void displayArray(const int* array, int size, int currentStep, int currentElem)
{
// system("cls"); // 清屏
printf("\n排序步骤 %d:\n", currentStep);
for (int i = 0; i < size; i++)
{
if (i == currentElem)
{
printf("\033[1;31m[%d]\033[0m ", array[i]); // 红色显示当前元素
}
else
{
printf("[%d] ", array[i]);
}
}
printf("\n\n");
// sleep(1); // 暂停1秒,便于观察
}
// 插入排序实现
void insertionSort(SortSystem* sys)
{
int key = 0;
int j = 0;
for (int i = 1; i < sys->size; i++)
{
key = sys->sortedArray[i];
j = i - 1;
// 将大于key的元素向右移动
while (j >= 0 && sys->sortedArray[j] > key)
{
sys->sortedArray[j + 1] = sys->sortedArray[j];
j--;
displayArray(sys->sortedArray, sys->size, i, j + 1); // 显示中间状态
}
sys->sortedArray[j + 1] = key;
displayArray(sys->sortedArray, sys->size, i, j + 1); // 显示交换后的状态
}
printf("\n排序完成!\n\n");
}
// 运行排序系统
void runSortSystem()
{
SortSystem sys;
initSortSystem(&sys);
int choice = 0;
while (1)
{
menu();
scanf_s("%d", &choice);
switch (choice)
{
case 1:
inputArray(&sys);
printf("数据输入完成!\n");
break;
case 2:
if (sys.size == 0)
{
printf("尚未输入数据,请先选择1 输入数据!\n");
}
else
{
insertionSort(&sys);
}
break;
case 3:
if (sys.size == 0)
{
printf("尚未输入数据,请先选择1 输入数据!\n");
}
else
{
printf("原始数据:\n");
for (int i = 0; i < sys.size; i++)
{
printf("%d ", sys.array[i]);
}
printf("\n");
}
break;
case 4:
if (sys.size == 0)
{
printf("尚未输入数据,请先选择1 输入数据!\n");
}
else
{
printf("排序结果: ");
for (int i = 0; i < sys.size; i++)
{
printf("%d ", sys.sortedArray[i]);
}
printf("\n");
}
break;
case 5:
if (sys.array != NULL)
free(sys.array);
if (sys.sortedArray != NULL)
free(sys.sortedArray);
printf("感谢使用插入排序系统,再见!\n");
return;
default:
printf("无效的选择,请重新输入!\n");
}
}
}
// 显示结果
void displayResult(const SortSystem* sys)
{
printf("\n===== 排序结果 =====\n");
if (sys->size == 0)
{
printf("尚未输入数据\n");
}
else
{
printf("原始数据: ");
for (int i = 0; i < sys->size; i++)
{
printf("%d ", sys->array[i]);
}
printf("\n排序结果: ");
for (int i = 0; i < sys->size; i++)
{
printf("%d ", sys->sortedArray[i]);
}
printf("\n");
}
}
用C语言实现了------一个基于顺序表的插入排序演示系统,具有交互式菜单和可视化排序过程。
-
系统结构
使用
SortSystem
结构体统一管理数据,包含原始数组、排序数组和数组大小,通过动态内存分配实现灵活的数据存储。 -
核心功能
-
用户交互:提供菜单选项(输入数据、执行排序、查看数据、退出等),支持多次操作。
-
插入排序实现 :通过
insertionSort
函数完成排序,并在每一步移动元素时调用displayArray
,用红色高亮显示当前操作的元素,直观展示排序过程。 -
数据可视化:支持查看原始数据和排序结果,排序过程中每一步的中间状态会被实时打印。
-
-
技术细节
-
动态内存管理:使用
malloc
分配数组内存,退出时通过free
释放内存,避免泄漏。 -
跨平台兼容性:使用
scanf_s
(需注意编译器兼容性)和ANSI颜色代码(部分终端可能不支持)。
-
-
适用场景
适合用于算法教学或排序过程演示,用户可通过交互式操作观察插入排序的逐步执行逻辑。