08_排序

基本概念与分类

假设含有n个记录的序列为 { r 1 , r 2 , . . . , r n } \{r_1,r_2,...,r_n\} {r1,r2,...,rn},其相应的关键字分别为 { k 1 , k 2 , . . . , k n } \{k_1,k_2,...,k_n\} {k1,k2,...,kn},需确定1,2,…,n的一种排列 p 1 , p 2 , . . . , p n p_1,p_2,...,p_n p1,p2,...,pn,使其相应的关键字满足 k p 1 ≤ k p 2 ≤ . . . ≤ k p n k_{p1}\leq k_{p2}\leq ... \leq k_{pn} kp1kp2...kpn(非递减或递增)关系,即使得序列成为一个按关键字有序的序列 { r p 1 , r p 2 , . . . , r p n } \{r_{p1},r_{p2},...,r_{pn}\} {rp1,rp2,...,rpn},这样的操作称为排序。

排序的稳定性

假设 r i = r j ( 1 ≤ i ≤ n , i ≤ j ≤ n , i ≠ j ) r_i=r_j(1 \leq i \leq n,i \leq j \leq n,i \neq j) ri=rj(1in,ijn,i=j),且在排序前的序列中 r i r_i ri领先与 r j r_j rj。如果排序后 r i r_i ri仍然领先与 r j r_j rj,则称所用的排序方法是稳定的;反之则是不稳定的。

内排序与外排序

内排序是在排序整个过程中,待排序的所有记录全部被就置在内存中 。外排序是由于排序的记录个数太多 , 不能同时放置在内存,整个排序过程需要在内外存之间多次交换数据才能进行。

排序用到的结构与函数

#define MAXSIZE 10    /* 用于要排序数组个数最大值,可以根据需要修改 */
typedef struct
{
    int r[MAXSIZE+1]; /* 存储要排序的数组,r[0]用作哨兵或临时变量 */
    int length;       /* 用于记录顺表的长度 */
}SqList;
/* 交换L中数组r的下标为i和j的值 */
void swap(SqList * L,int i,int j) 
{
    int temp=L->r[i];
    L->r[i]=L->r[j];
    L->r[j]=temp;
}

冒泡排序

冒泡排序(Bubble Sort)一种交换排序,它的基本思想是:两两比较相邻记录的关键字,如果反序则交换,直到没有反序的记录为止。

/* 对顺序表L作交换排序(冒泡排序初级版) */
void BubbleSort0(SqList *L)
{
    int i,j;
    for(i=1;i<L->length;i++)
    {
        for(j=i+1;j<L->length;j++)
        {
            if(L->r[i]>L->r[j])
            {
                swap(L,i,j);
            }
        }
    }
}
/* 对顺序表L作交换排序(冒泡排序改进版) */
void BubbleSort(SqList *L)
{
    int i,j;
    for(i=1;i<L->length;i++)
    {
        for(j=L->length-1;j>=i;j--) /* 注意j是从后向前循环 */
        {
            if(L->r[j]>L->r[j+1])   /* 若前者大于后者(注意这里与上一算法的差异) */
            {
                swap(L,j,j+1);
            }
        }
    }
}
/* 对顺序表L作交换排序(冒泡排序优化版) */
void BubbleSort2(SqList *L)
{
    int i,j;
    bool flag = true;				/* flag用来作为标记 */
    for(i=1;i<L->length && flag ;i++) /* flag为false,则退出循环 */
    {
        flag = false;				/* 初始化false */
        for(j=L->length-1;j>=i;j--) 
        {
            if(L->r[j]>L->r[j+1])   
            {
                swap(L,j,j+1);
                flag = true; /* 如果有数据交换,则flag为true */
            }
        }
    }
}

冒泡排序算法的时间复杂度:KaTeX parse error: Expected group after '_' at position 5: \sum_̲\limits{i=2}^{n…,总的时间复杂度为 O ( n 2 ) O(n^2) O(n2)

简单选择排序

简单选择排序法(Simple Selection Sort)就是通过 n − i n-i ni 次关键字间的比较,从 n − i + 1 n-i+1 ni+1 记录中选出关键字最小的记录,并和第 i ( 1 ≤ i ≤ n ) i(1\leq i \leq n) i(1in) 个记录交换。

/* 对顺序表L作简单选择排序 */
void SelectSort(SqList * L) {
    int i,j,min;
    for(i=1;i<L->length;i++){
    	min = i;     				   /* 将当前下标定义为最小值下标 */
        for(j = i+1;j<=L->length;j++){ /* 循环之后的数据 */
            if(L->r[min]>L->r[j])      /* 如果有小于当前最小值的关键字 */
                min = j;   			   /* 将此关键字的下标赋值给min */
        }
        if(i != min)				   /* 若min不等于i,说明找到最小值,交换 */
            swap(L,i,min)			   /* 交换L->r[i]与L->r[min]的值 */
    }
}

简单选择排序算法的时间复杂度:KaTeX parse error: Expected group after '_' at position 5: \sum_̲\limits{i=1}^{n…,总的时间复杂度为 O ( n 2 ) O(n^2) O(n2)

尽管与冒泡排序同为 O ( n 2 ) O(n^2) O(n2),但简单选择排序的性能上还是略优于冒泡排序。

直接插入排序

直接插入排序(Straight Insertion Sort)的基本操作是将一个记录插入到已经排好序的有序表中,从而得到一个新的、记录数增加1的有序表。

/* 对顺序表L作直接插入排序 */
void InsertSort(SqList * L) {
    int i,j;
    for(i=2;i<L->length;i++){
        if(L->r[i] < L->r[i-1]){ /* 需将L->r[i]插入有序子表 */
            L->r[0]=L->r[i];	 /* 设置哨兵 */
            for(j=i-1;L->r[j]>L->r[0];j--)
                L->r[j+1] = L->r[j]; /* 记录后移 */
            L->r[j+1] = L->r[0];     /* 插入到正确位置 */
        }
    }
}

最好情况(有序表本身有序)下的算法复杂度: n − 1 ( ∑ i = 2 n 1 ) n-1(\sum_{i=2}^n1) n1(i=2n1) ,时间复杂度为O(n)

最坏情况(有序表是逆序)下的算法复杂度:比较 KaTeX parse error: Expected group after '_' at position 5: \sum_̲\limits{(i=2)}^…次,记录移动KaTeX parse error: Expected group after '_' at position 5: \sum_̲\limits{i=2}^{n…

如果排序记录是随机的,那么根据概率相同的原则,平均比较和移动次数约为 n 2 4 \frac{n^2}4 4n2。直接插入排序法的时间复杂度为 O ( n 2 ) O(n^2) O(n2) ,直接插入排序法比冒炮和简单选择排序的性能要好一些。

希尔排序算法

  1. 将原本有大量记录数的记录进行分组,分割成若干个子序列。

  2. 在这些子序列内进行插入排序,当整个序列基本有序时,再对全体记录进行一次直接插入排序

    所谓的基本有序,就是小的关键字基本在前面,大的基本在后面,不大不小的基本在中间。

/* 对顺序表L作希尔排序 */
void ShellSort(SqList * L)
{
    int i,j;
    int increment = L->length;
    do
    {
        increment = increment/3 +1;  /*增量序列*/
        for(i = increment +1;i<=L->length;i++)
        {
            if(L->r[i] < L->r[i-increment])
            {
                /* 需将L->r[i] 插入有序增量子表 */
                L->r[0] = L->r[i]; /* 暂存在L->r[0] */
                for(j=i-increment;j>0 && L->r[0]< L->r[j];j-=increment)
                    L->r[j+increment] = L->r[j]; /* 记录后移,查找插入位置 */
                L->r[j+increment] = L->r[0]; /* 插入 */
            }
        }        
    }
    while(increment > 1);
}

希尔排序的关键并不是随便分组后各自排序,而是将相隔某个"增最’'的记录组成一个子序列, 实现跳跃式的移动,使得排序的效率提高 。

这里"增量"的选取就非常关键,当增量序列为 d l t a [ k ] = 2 t − k + 1 − 1 ( 0 ≤ k ≤ t ≤ [ l o g 2 ( n + 1 ) ] ) dlta[k] = 2^{t-k+1}-1 (0\leq k \leq t \leq [log_2(n+1)]) dlta[k]=2tk+11(0kt[log2(n+1)]) 时,可以获得不错的效率。

希尔排序并不是一直稳定排序,时间复杂度为 O ( n 3 / 2 ) O(n^{3/2}) O(n3/2)

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Docker逃逸CVE-2019-5736、procfs云安全漏洞复现,全文5k字,超详细解析!

Docker容器挂载procfs 逃逸 procfs是展示系统进程状态的虚拟文件系统&#xff0c;包含敏感信息。直接将其挂载到不受控的容器内&#xff0c;特别是容器默认拥有root权限且未启用用户隔离时&#xff0c;将极大地增加安全风险。因此&#xff0c;需谨慎处理&#xff0c;确保容器环…

迅捷PDF编辑器合并PDF

迅捷PDF编辑器是一款专业的PDF编辑软件&#xff0c;不仅支持任意添加文本&#xff0c;而且可以任意编辑PDF原有内容&#xff0c;软件上方的工具栏中还有丰富的PDF标注、编辑功能&#xff0c;包括高亮、删除线、下划线这些基础的&#xff0c;还有规则或不规则框选、箭头、便利贴…

VRPTW(MATLAB):常春藤算法(IVY)求解带时间窗的车辆路径问题VRPTW,MATLAB代码

详细介绍 VRPTW&#xff08;MATLAB&#xff09;&#xff1a;常春藤算法&#xff08;Ivy algorithm&#xff0c;IVY&#xff09;求解带时间窗的车辆路径问题VRPTW&#xff08;提供MATLAB代码&#xff09;-CSDN博客 ********************************求解结果******************…

SpringBoot 生产实践:没有父 starter 的打包问题

文章目录 前言一、搜索引擎二、Chat GPT三、官方文档四、小结推荐阅读 前言 今天刚准备写点文章&#xff0c;需要 SpringBoot 项目来演示效果。一时心血来潮&#xff0c;没有采用传统的方式&#xff08;即通过引入 spring-boot-starter-parent 父工程的方式&#xff09;。 &l…

昇思25天学习打卡营第15天|linchenfengxue

Pix2Pix实现图像转换 Pix2Pix概述 Pix2Pix是基于条件生成对抗网络&#xff08;cGAN, Condition Generative Adversarial Networks &#xff09;实现的一种深度学习图像转换模型&#xff0c;该模型是由Phillip Isola等作者在2017年CVPR上提出的&#xff0c;可以实现语义/标签到…

16-JS封装:extend方法

目录 一、封装需求 二、实现1&#xff1a;jQuery.extend 三、实现2&#xff1a;通过原型jQuery.fn.extend 四、优化 一、封装需求 封装需求&#xff1a; $.extend&#xff1a; var obj{ name:"xxx",age:18} var obj3{ gender:"女"} var obj2{}; 将obj、…

如何注册微信公众号

如何注册微信公众号 如何注册一个微信公众号 &#x1f60a;&#x1f4f1;摘要引言正文内容1. 准备工作内容定位和受众群体公众号名称和头像 2. 网页注册流程第一步&#xff1a;访问微信公众平台第二步&#xff1a;选择账户注册类型第三步&#xff1a;填写基本信息第四步&#x…

单/多线程--协程--异步爬虫

免责声明:本文仅做技术交流与学习... 目录 了解进程和线程 单个线程(主线程)在执行 多线程 线程池 协程(爬虫多用) 假异步:(同步) 真异步: 爬虫代码模版 异步-爬虫 同步效果--19秒 异步效果--7秒 了解进程和线程 ​ # --------------------> # ------> # …

Multisim仿真-交流数字电压表

下图为整体的原理框图&#xff0c;交流电源经过整流滤波电路转换后&#xff0c;送入模数转换电路&#xff0c;经译码给到显示电路&#xff0c;由其显示交流电源的有效值。 信号发生器XFG1输出正弦波信号(峰峰值)&#xff0c;XMM1测量有效值&#xff0c;U6数码管显示有效值。仿真…

基于星火大模型的群聊对话分角色要素提取挑战赛

赛事任务与数据 2024 iFLYTEK A.I.开发者大赛-讯飞开放平台 (xfyun.cn) 从给定的<客服>与<客户>的群聊对话中, 提取出指定的字段信息&#xff0c;待提取的全部字段见下数据说明。 赛题方提供了184条真实场景的群聊对话数据以及人工标注后的字段提取结果&#xf…

eBPF 指令宏

linux 6.9.7 指令宏 /* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ /* eBPF instruction mini library */ #ifndef __BPF_INSN_H #define __BPF_INSN_Hstruct bpf_insn;/* ALU ops on registers, bpf_add|sub|...: dst_reg src_reg */ // BPF_ALU64_REG&am…

Jmeter使用JSON Extractor提取多个变量

1.当正则不好使时&#xff0c;用json extractor 2.提取多个值时&#xff0c;默认值必填&#xff0c;否则读不到变量

代码随想录算法训练营第4天|LeetCode24,19,02,07,142

24.交换链表结点 题目链接&#xff1a;24. 两两交换链表中的节点 - 力扣&#xff08;LeetCode&#xff09; 文章链接&#xff1a;代码随想录 (programmercarl.com) 视频链接&#xff1a;代码随想录算法公开课 | 最强算法公开课 | 代码随想录 第一想法 正常模拟&#xff0c;先画…

47.HOOK引擎优化支持CALL与JMP位置做HOOK

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 上一个内容&#xff1a;46.修复HOOK对代码造成的破坏 以 46.修复HOOK对代码造成的破坏 它的代码为基础进行修改 优化的是让引擎支持从短跳JMP&#xff08;E9&…

JUC(java.util.concurrent)中的常见类

文章目录 Callable接口ReentrantLockReentrantLock 和 synchronized 的区别:如何选择使用哪个锁? 信号量SemaphoreCountDownLatch多线程环境使用ArrayList多线程使用 哈希表相关面试题 JUC放了和多线程有关的组件 Callable接口 和Runnable一样是描述一个任务,但是有返回值,表…

leetcode-每日一题

3101. 交替子数组计数https://leetcode.cn/problems/count-alternating-subarrays/ 给你一个 二进制数组 nums 。 如果一个 子数组 中 不存在 两个 相邻 元素的值 相同 的情况&#xff0c;我们称这样的子数组为 交替子数组 。 返回数组 nums 中交替子数组的数量。 示例 …

Linux字符设备驱动

一、字符设备驱动结构 1. cdev结构体 在Linux内核中&#xff0c;使用cdev结构体来描述一个字符设备 struct cdev {struct kobject kobj; //内嵌kobject对象struct module *owner; //所属的模块const struct file_operations *ops; //该设备的文件操作结构体struct list_head…

确认下单:购物车页面点击 去结算 按钮发起两个请求trade(显示购物车的商品信息和计算商品的总金额)findUserAddressList

文章目录 1、确认下单&#xff1a;购物车页面点击去结算1.1、在OrderController类中创建 trade 方法1.2、在CartController类中创建 checkedCartInfos1.3、CartServiceImpl 实现 checkedCartInfos的业务功能1.4、在service-cart-client模块下定义远程openFeign接口1.5、在SpzxO…

Java - 程序员面试笔记记录 实现 - Part3

4.1 线程与进程 线程是程序执行的最小单元&#xff0c;一个进程可以拥有多个线程&#xff0c;各个线程之间共享程序的内存空间以及一些进程级资源&#xff0c;但拥有自己的栈空间。 4.3 Java 多线程 方法一&#xff1a;继承 Thread 类&#xff0c;重写 run 方法&#xff1b;…

qt QGridLayout 简单实验1

1.概要 2.实验 2.1 实验1 简单实验跨行 2.1.1 代码 #ifndef WIDGET_H #define WIDGET_H#include <QWidget>QT_BEGIN_NAMESPACE namespace Ui { class Widget; } QT_END_NAMESPACEclass Widget : public QWidget {Q_OBJECTpublic:Widget(QWidget *parent nullptr);~W…