数据结构——排序算法代码实现、包含注释易理解可运行(C语言,持续更新中~~)

news2024/9/27 23:29:20

一、排序

1.1 直接插入排序

1.1.1 思想

插入排序的核心操作是将待排序元素与已排序序列中的元素进行比较,并找到合适的位置进行插入。这个过程可以通过不断地将元素向右移动来实现。

插入排序的优势在于对于小规模或基本有序的数组,它的性能非常好。然而,对于大规模乱序的数组,插入排序的性能相对较差,时间复杂度为 O(n^2)。

1.1.2 排序过程演示

示例数组:{6, 3, 8, 2, 9, 1}

初始状态:

6 | 3 8 2 9 1
第一轮迭代(i=1):

3 6 | 8 2 9 1
在这一轮中,待插入元素为3,我们将3与前面的6进行比较,发现3小于6,所以将6后移一位,
然后将3插入到空出的位置。

第二轮迭代(i=2):

3 6 8 | 2 9 1
在这一轮中,待插入元素为8,我们将8与前面的6和3进行比较,发现8大于6和3,所以不需要
进行任何操作。

第三轮迭代(i=3):

2 3 6 8 | 9 1
在这一轮中,待插入元素为2,我们将2与前面的8、6和3进行比较,发现2小于8、6和3,所以
将8、6和3分别后移一位,然后将2插入到空出的位置。

第四轮迭代(i=4):

2 3 6 8 9 | 1
在这一轮中,待插入元素为9,我们将9与前面的8、6、3和2进行比较,发现9大于2、3、6和8,所以不需要进行任何操作。

第五轮迭代(i=5):

1 2 3 6 8 9 |
在这一轮中,待插入元素为1,我们将1与前面的9、8、6、3和2进行比较,发现1小于9、8、6、3和2,所以将9、8、6、3和2分别后移一位,然后将1插入到空出的位置。

最终排序结果为:{1, 2, 3, 6, 8, 9}

1.1.3 代码

void insertSort(int arr[], int n) {
    int i, j, temp;

    for (i = 1; i < n; i++) {
        // 待插入元素
        temp = arr[i];
        // 待插入元素前一个元素
        j = i - 1;

        // 将比待插入元素大的元素后移一位
        while (j >= 0 && arr[j] > temp) {
            arr[j + 1] = arr[j];
            j--;
        }

        // 插入待插入元素
        arr[j + 1] = temp;
    }
}

1.2 希尔排序

1.2.1 思想

希尔排序是一种改进的插入排序算法,它通过比较和交换不相邻的元素来加快排序速度。

希尔排序的基本思想是将待排序数组分成若干个子序列,然后对每个子序列进行插入排序。这样做可以让数组中距离较远的元素先进行比较和交换,从而加快排序速度。

希尔排序的优势在于对于小规模或基本有序的数组,它的性能非常好。通过使用递减的步长序列,希尔排序可以将大元素尽可能地向右移动,从而加快排序的速度。此外,希尔排序是一种原地排序算法,并且相对于其它 O(n^2) 排序算法,它的常数因子较小。然而,对于大规模乱序的数组,希尔排序的性能相对较差,时间复杂度为 O(n^2)。这是因为在这种情况下,即使使用较小的步长序列,元素仍然需要进行多次比较和交换,导致效率下降。

1.2.2 排序过程演示

对初始数据序列(8,3,9,11,2,1,4,7,5,10,6)进行希尔排序,两趟排序采用的增量(间隔)依次是5、3。

来源:408真题,王道

1.2.3 代码

void shellSort(int arr[], int n) {
    int i, j, gap, temp;

    // 使用 Knuth 序列确定初始步长,4,1
    for (gap = 1; gap < n / 3; gap = gap * 3 + 1) {}
    while (gap > 0) {
        printf("%d ", gap);
        // 对每个步长进行插入排序
        for (i = gap; i < n; i++) {
            temp = arr[i];
            j = i;

            // 插入排序
            while (j >= gap && arr[j - gap] > temp) {
                arr[j] = arr[j - gap];
                j -= gap;
            }
            
            arr[j] = temp;
        }

        // 更新步长
        gap = (gap - 1) / 3;
    }
}

1.3 简单选择排序

1.3.1 思想

简单选择排序也是一种基于比较的排序算法,其基本思想是每次从待排序的元素中选出最小(或最大)的一个元素,存放在序列的起始位置,然后再从剩余未排序的元素中继续选择最小(或最大)的元素,然后放到已排序的元素的末尾。以此类推,直到所有待排序的元素排完为止。

简单选择排序的优点在于实现简单,代码易于理解,而且不需要占用额外的内存空间,是一种原地排序算法。同时,由于它在每一轮中只交换一次元素,因此交换的次数相对较少,适用于数据移动较为敏感的排序场景。然而,简单选择排序的缺点也非常明显,即时间复杂度较高。在最坏情况下,简单选择排序的时间复杂度为 O(n^2),因此对于大规模的数据排序时,效率比较低。

1.3.2 排序过程演示

示例数组:{6, 3, 8, 2, 9, 1}

1、首先,找到最小的元素是 1,与数组的第一个元素 6 交换位置,得到数组 {1, 3, 8, 2, 9, 6}。

2、接着,在剩余的未排序部分 {3, 8, 2, 9, 6} 中,找到最小的元素是 2,与数组的第二个元素 3 交换位置,得到数组 {1, 2, 8, 3, 9, 6}。

3、然后,在剩余的未排序部分 {8, 3, 9, 6} 中,找到最小的元素是 3,与数组的第三个元素 8 交换位置,得到数组 {1, 2, 3, 8, 9, 6}。

4、继续,在剩余的未排序部分 {8, 9, 6} 中,找到最小的元素是 6,与数组的第四个元素 8 交换位置,得到数组 {1, 2, 3, 6, 9, 8}。

5、再次,在剩余的未排序部分 {9, 8} 中,找到最小的元素是 8,与数组的第五个元素 9 交换位置,得到数组 {1, 2, 3, 6, 8, 9}。

6、最后,在剩余的未排序部分 {9} 中,只剩下一个元素,无需比较。

1.3.3 代码

void selectionSort(int arr[], int n) {
    int i, j, minIndex, temp;

    for (i = 0; i < n - 1; i++) {
        minIndex = i;

        // 在未排序部分找到最小元素的索引
        for (j = i + 1; j < n; j++) {
            if (arr[j] < arr[minIndex]) {
                minIndex = j;
            }
        }

        // 将最小元素与未排序部分的第一个元素交换位置
        temp = arr[minIndex];
        arr[minIndex] = arr[i];
        arr[i] = temp;
    }
}

1.4 冒泡排序

1.4.1 思想

冒泡排序的基本思想是重复地走访需要排序的元素序列,一次比较两个元素,如果它们的顺序错误就交换它们的位置,直到序列排序完成。

冒泡排序的时间复杂度为 O(n^2),空间复杂度为 O(1),算法简单易懂,实现也较为简单,是入门级别的排序算法。但是,冒泡排序的性能较差,在大多数情况下效率低下,不适合处理大规模数据集。

1.4.2 排序过程演示

1.4.3 代码


void bubbleSort(int arr[], int n) {
    int i, j, temp;

    for (i = 0; i < n - 1; i++) {
        for (j = 0; j < n - i - 1; j++) {
            // 比较相邻两个元素,将大的元素往后移
            if (arr[j] > arr[j + 1]) {
                temp = arr[j];
                arr[j] = arr[j + 1];
                arr[j + 1] = temp;
            }
        }
    }
}

二、全部代码的源文件

#include <stdio.h>

// 插入排序函数
void insertSort(int arr[], int n) {
    int i, j, temp;

    for (i = 1; i < n; i++) {
        // 待插入元素
        temp = arr[i];
        // 待插入元素前一个元素
        j = i - 1;

        // 将比待插入元素大的元素后移一位
        while (j >= 0 && arr[j] > temp) {
            arr[j + 1] = arr[j];
            j--;
        }

        // 插入待插入元素
        arr[j + 1] = temp;
    }
}


// 冒泡排序函数
void bubbleSort(int arr[], int n) {
    int i, j, temp;

    for (i = 0; i < n - 1; i++) {
        for (j = 0; j < n - i - 1; j++) {
            // 比较相邻两个元素,将大的元素往后移
            if (arr[j] > arr[j + 1]) {
                temp = arr[j];
                arr[j] = arr[j + 1];
                arr[j + 1] = temp;
            }
        }
    }
}


// 简单选择排序函数
void selectionSort(int arr[], int n) {
    int i, j, minIndex, temp;

    for (i = 0; i < n - 1; i++) {
        minIndex = i;

        // 在未排序部分找到最小元素的索引
        for (j = i + 1; j < n; j++) {
            if (arr[j] < arr[minIndex]) {
                minIndex = j;
            }
        }

        // 将最小元素与未排序部分的第一个元素交换位置
        temp = arr[minIndex];
        arr[minIndex] = arr[i];
        arr[i] = temp;
    }
}


// 希尔排序函数
void shellSort(int arr[], int n) {
    int i, j, gap, temp;

    // 使用 Knuth 序列确定初始步长,4,1
    for (gap = 1; gap < n / 3; gap = gap * 3 + 1) {}
    while (gap > 0) {
        printf("%d ", gap);
        // 对每个步长进行插入排序
        for (i = gap; i < n; i++) {
            temp = arr[i];
            j = i;

            // 插入排序
            while (j >= gap && arr[j - gap] > temp) {
                arr[j] = arr[j - gap];
                j -= gap;
            }
            
            arr[j] = temp;
        }

        // 更新步长
        gap = (gap - 1) / 3;
    }
}

int main() {
    int arr[] = {6, 3, 8, 2, 9, 1};
    int n = sizeof(arr) / sizeof(arr[0]);
    int i;

    printf("排序前数组的元素:");
    for (i = 0; i < n; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");

    // insertSort(arr, n);  // 使用直接插入排序
    // bubbleSort(arr, n); // 使用冒泡排序
    // selectionSort(arr, n); // 使用简单选择排序
    shellSort(arr, n); // 使用希尔排序


    printf("排序后数组的元素:");
    for (i = 0; i < n; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");

    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1408102.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【经验分享】豆瓣小组的文章/帖子怎么删除?

#豆瓣小组的文章/帖子怎么删除&#xff1f;# 第一步&#xff1a; 手机登录豆瓣app ↓ 点右下角“我” ↓ 然后在页面点击我的小组 ↓ 点我发布的 ↓ ↓ 再任意点开一个帖子 ↓ 在文章和帖子的右上角有一个笔状的图标&#xff0c;切记不是右上角的横三点… ↓ ↓ 最后点下边的…

odoo 一日一技 owl Registry示例 在用户菜单增加开发者模式开关

# 示例介绍 在Odoo中&#xff0c;开发者模式是一个非常有用的工具&#xff0c;它允许开发人员对系统进行调试。如果每次都要去设置中打开调试模式将非常麻烦&#xff0c;上篇文章讲述了如何使用 owl registry&#xff0c;这篇我们来进行实操。 本文将介绍如何在Odoo的用户菜单…

令人感动的创富故事编号001:27岁Python程序员年入$600万+

27岁Python程序员年入$600万 27岁的你&#xff0c;在做什么&#xff1f; 为家庭生计而努力搬砖&#xff0c;辛勤工作&#xff1f; 还是放弃挣扎&#xff0c;选择躺平呢&#xff1f; 当我们还在为未来道路感到困惑之际&#xff0c;年仅27岁的Reilly已经迈向了财富自由的大门…

Socket 文件描述符

文件描述符的作用是什么&#xff1f; 每一个进程都有一个数据结构 task_struct&#xff0c;该结构体里有一个指向「文件描述符数组」的成员指针。该数组里列出这个进程打开的所有文件的文件描述符。数组的下标是文件描述符&#xff0c;是一个整数&#xff0c;而数组的内容是一…

用VR技术让党建“活起来”,打造党建知识科普新体验

随着现在工作、生活的信息化、网络化持续加深&#xff0c;传统的党建科普对年轻党员的吸引力日益降低&#xff0c;不管是面授讲课还是实地观摩的方式&#xff0c;都会受到时间和空间上的限制。因此&#xff0c;VR数字党建的出现为党建知识科普提供了新的可能&#xff0c;VR党建…

STM32 USB CDC协议的应用与优化技巧

STM32微控制器提供了使用USB CDC&#xff08;Communications Device Class&#xff09;协议来实现虚拟串口通信的功能。USB CDC协议可以将STM32设备模拟为一个虚拟串口设备&#xff0c;并通过USB接口与计算机进行通信。在本文中&#xff0c;我们将介绍USB CDC协议的应用与优化技…

elment-plus如何引入scss文件实现自定义主题色

elment-plus如何引入scss文件实现自定义主题色&#xff01;如果您想修改elementPlus的默认主题色调&#xff0c;使用自定义的色调&#xff0c;可以考虑使用官方提供的解决办法。 第一步你需要在项目内安装sass插件包。 npm i sass -D 如图&#xff0c;安装完成后&#xff0c;你…

[pytorch入门] 6. 神经网络

基本介绍 torch.nn&#xff1a; Containers&#xff1a;基本骨架Convolution Layers&#xff1a; 卷积层Pooling layers&#xff1a;池化层Non-linear Activations (weighted sum, nonlinearity)&#xff1a;非线性激活Normalization Layers&#xff1a;正则化层 Container…

边缘计算及相关产品历史发展

边缘计算及相关产品历史发展 背景边缘计算的历史CDN&#xff08;Content Delivery Network&#xff09;Cloudlet雾计算MEC&#xff08;Multi-Access Edge Computing&#xff0c;MEC&#xff09; 边缘计算的现状云计算厂商硬件厂商软件基金会 背景 最近&#xff0c;公司部分业务…

基于springboot+vue的社区医院信息平台系统(前后端分离)

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战 主要内容&#xff1a;毕业设计(Javaweb项目|小程序等)、简历模板、学习资料、面试题库、技术咨询 文末联系获取 研究背景…

阿赵UE学习笔记——解决UE资源不能正常显示缩略图的问题

阿赵UE学习笔记目录 大家好&#xff0c;我是阿赵。   这里分享一个虚幻引擎使用小技巧。在使用虚幻引擎的过程中&#xff0c;经常会遇到有些资源在重新打开项目的时候&#xff0c;会看不到缩略图&#xff0c;而是显示默认资源的图标&#xff1a; 这个时候&#xff0c;第一种…

应用app的服务器如何增加高并发

增强服务器的高并发能力是现代网络应用非常关键的需求。面对用户数量的不断增长和数据量的膨胀&#xff0c;服务器必须能够处理大量并发请求。以下是一些提高服务器高并发能力的常用方法和具体实施细节&#xff1a; 优化服务器和操作系统配置 服务器和操作系统的默认配置不一定…

快速上手的AI工具-文心一言绘画达人

前言 大家好&#xff0c;现在AI技术的发展&#xff0c;它已经渗透到我们生活的各个层面。对于普通人来说&#xff0c;理解并有效利用AI技术不仅能增强个人竞争力&#xff0c;还能在日常生活中带来便利。无论是提高工作效率&#xff0c;还是优化日常任务&#xff0c;AI工具都可…

【模拟通信】AM、FM等的调制解调

调制相关的概念 调制&#xff1a;控制载波的参数&#xff0c;使载波参数随调制信号的规律变化 已调信号&#xff1a;受调载波&#xff0c;含有调制信号的全部特征 调制的作用: 提高发射效率多路复用&#xff0c;提高信道利用率提高系统抗干扰能力 两种调制方式 线性调制&a…

网络协议与攻击模拟_08DHCP协议

技术学习要了解某项技术能干什么&#xff1f;它的详细内容&#xff1f;发展走向&#xff1f; 一、DHCP协议 1、DHCP基本概念 dhcp动态主机配置协议&#xff0c;广泛应用于局域网内部 主要是为客户机提供TCP/IP 参数&#xff08;IP地址、子网掩码、网关、DNS等&#xff09;…

STL第四讲

第四讲 万用Hash Function 左侧的是设计为类并重载调用运算符&#xff0c;右侧是一般函数的形势&#xff1b; 但是右侧形势在创建容器时更麻烦&#xff1b; 具体例子&#xff1a; 第三种形势&#xff1a;struct hash 偏特化形式 tuple 自C03引入&#xff1b; 关于源码解读的…

Linux服务器系统修改SSH端口教程

修改端口号是通过修改SSH的配置文件实现的&#xff0c;在服务器终端先激活root用户&#xff0c;然后输入&#xff1a; vim /etc/ssh/sshd_config找到#Port 22这个位置 键盘按i进入编辑模式 删除掉Port 22前面的#&#xff0c;然后键盘按一下回车键&#xff08;如果没有#可不必…

软件产品为什么要测试才能上线?测试可以发现所有bug吗?

在现如今信息时代&#xff0c;软件产品已经成为人们生活中不可或缺的一部分。无论是在工作中还是在娱乐休闲时&#xff0c;我们都需要依赖各种软件来完成各种任务。然而&#xff0c;你是否注意到了身边的软件产品都是经过严格的测试才能上线的呢?那么为什么软件产品必须要经过…

JS之歌词滚动案例

让我为大家带来一个歌词滚动的案例吧&#xff01; 详细的介绍都在代码块中 我很希望大家可以自己动手尝试一下&#xff0c;如果需要晴天的mp3音频文件可以私信我 上代码&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset&quo…

【开源】基于JAVA语言的图书管理系统

目录 一、 系统介绍二、 功能模块2.1 登录注册模块2.1 图书馆模块2.2 图书类型模块2.3 图书模块2.4 图书借阅模块2.5 公告模块 三、 源码解析3.1 图书馆模块设计3.2 图书类型模块设计3.3 图书模块设计3.4 图书借阅模块设计3.5 公告模块设计 四、 免责说明 一、 系统介绍 图书管…