用C语言实现了——一个基于顺序表的插入排序演示系统

一、知识要点、

插入排序是一种简单直观的排序算法,它的工作方式类似于我们整理扑克牌。

基本原理:

插入排序通过构建有序序列来工作。它每次从无序序列中取出一个元素,然后将其插入到已排序序列的适当位置。这个过程重复进行,直到所有元素都已插入到已排序序列中。

算法步骤:

  1. 初始化:假设数组的第一个元素已经是一个有序序列。

  2. 遍历数组:从第二个元素开始,依次取出当前元素。

  3. 比较和插入:将当前元素与已排序序列中的元素进行比较,找到合适的位置插入当前元素。

  4. 重复 :重复上述过程,直到所有元素都已插入到有序序列中。

详细步骤示例:

假设有一个数组:[5, 2, 4, 6, 1, 3]

  1. 初始状态 :已排序序列 [5],未排序序列 [2, 4, 6, 1, 3]

  2. 取第二个元素 2

    与已排序序列的 5 比较,发现 2 < 5,将 5 后移一位。

    插入 2 到合适位置,已排序序列变为 [2, 5]

  3. 取第三个元素 4

    与 5 比较,4 < 5,将 5 后移一位。

    与 2 比较,4 > 2,插入到 2 和 5 之间,已排序序列变为 [2, 4, 5]

  4. 重复以上过程

性能分析:

时间复杂度

  • 最好情况:O(n)(当输入数组已经是有序的)

  • 最坏情况:O(n²)(当输入数组是逆序的)

  • 平均情况:O(n²)

空间复杂度:O(1)(只需要一个额外的临时变量)

稳定性:稳定排序(相同值的元素不会交换顺序)

优点

  1. 简单易实现:代码结构简单,容易理解和实现。

  2. 高效处理小规模数据:对于小规模数据,插入排序的性能较好。

  3. 适应性强:对于部分有序的数组,插入排序的性能表现优秀。

缺点

  1. 对大规模数据效率低:时间复杂度为 O(n²),在处理大规模数据时效率较低。

  2. 不适合逆序数据:当数据完全逆序时,需要最多的交换操作。

插入排序是一种简单且直观的排序算法,适用于小规模数据或部分有序的数据。尽管在大规模数据上效率不高,但它的简单性和稳定性使其在某些特定场景中仍然具有应用价值。

二、代码解析

1.结构体定义

int* array:

这是一个指向整数的指针,用于存储用户输入的原始数据。

它指向一个动态分配的内存区域,该区域的大小由用户输入的数组元素数量决定。

int* sortedArray:

这也是一个指向整数的指针,用于存储排序后的数据。

array 类似,它同样指向一个动态分配的内存区域,其大小与 array 相同。

在程序中,sortedArray 初始时会被复制 array 的内容,然后在排序过程中被修改。

int size:

这是一个整数,用于存储数组的大小(即数组中元素的数量)。它定义了 arraysortedArray 所指向的内存区域的大小。

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 结构体中的 arraysortedArray

动态内存分配:根据用户输入的数组大小动态分配内存,确保程序能够处理不同大小的输入数据。

数据备份 :将原始数据复制到 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 腾出位置。

更新 jj 减 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 的函数

  1. 初始化排序系统

定义一个 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语言实现了------一个基于顺序表的插入排序演示系统,具有交互式菜单和可视化排序过程。

  1. 系统结构

    使用SortSystem结构体统一管理数据,包含原始数组、排序数组和数组大小,通过动态内存分配实现灵活的数据存储。

  2. 核心功能

    • 用户交互:提供菜单选项(输入数据、执行排序、查看数据、退出等),支持多次操作。

    • 插入排序实现 :通过insertionSort函数完成排序,并在每一步移动元素时调用displayArray,用红色高亮显示当前操作的元素,直观展示排序过程。

    • 数据可视化:支持查看原始数据和排序结果,排序过程中每一步的中间状态会被实时打印。

  3. 技术细节

    • 动态内存管理:使用malloc分配数组内存,退出时通过free释放内存,避免泄漏。

    • 跨平台兼容性:使用scanf_s(需注意编译器兼容性)和ANSI颜色代码(部分终端可能不支持)。

  4. 适用场景

    适合用于算法教学或排序过程演示,用户可通过交互式操作观察插入排序的逐步执行逻辑。

相关推荐
水水沝淼㵘2 分钟前
嵌入式开发学习日志(数据结构--双链表)Day21
c语言·数据结构·学习·算法·排序算法
qqxhb9 分钟前
零基础学Java——第十一章:实战项目 - 微服务入门
java·开发语言·spring cloud·微服务
CodeCraft Studio26 分钟前
国产化Word处理控件Spire.Doc教程:通过C# 删除 Word 文档中的超链接
开发语言·c#·word
martian66539 分钟前
麒麟系统下Tomcat部署Java Web程序(WAR包)及全链路问题排查指南
开发语言·tomcat·系统安全
ai.Neo39 分钟前
牛客网NC22012:判断闰年问题详解
开发语言·c++·算法
好吃的肘子1 小时前
ElasticSearch进阶
大数据·开发语言·分布式·算法·elasticsearch·kafka·jenkins
NaclarbCSDN1 小时前
Java集合框架
java·开发语言·前端
ElseWhereR1 小时前
反转链表 - 简单
数据结构·链表
xiaohanbao091 小时前
day26 Python 自定义函数
开发语言·python·学习·机器学习·信息可视化·numpy
jie188945758661 小时前
c++,windows,多线程编程详细介绍
开发语言·c++