排序算法大总结

深入理解排序算法与大O表示法 本文详细介绍了搜索和排序算法的基本概念及其效率分析方法——大O表示法。通过比较线性搜索、二分搜索、选择排序、插入排序和归并排序等算法的效率和应用场景,加深了对算法运行时间增长趋势的理解。文章还探讨了Java集合框架的基础知识和如何使用其提供的数据结构和工具进行高效编程。 阅读详情

选择排序

思路:

从最左边的元素开始,逐个遍历,找到这一趟中的最小值,存到minIndex里面,最后这一趟结束,将它和这一趟开始遍历的位置i上的元素swap,直到最后一个位置上也就位。相当于选择出每一趟最小的元素,然后把它放到这一趟开始的地方。

基础版:
void selectionSort(int arr[], int n){

    for(int i = 0 ; i < n ; i ++){
        // 寻找[i, n)区间里的最小值
        int minIndex = i;
        for( int j = i + 1 ; j < n ; j ++ )
            if( arr[j] < arr[minIndex] )
                minIndex = j;

        swap( arr[i] , arr[minIndex] );
    }

}

插入排序

思路:

由于第一个元素可以默认为已排好序,因此可以从第二个元素开始遍历,每一趟使一个元素正确的插入到前面已排好序的数组中。如果这个元素比它前面的元素小,则swap一下,如果大于等于它前面的元素,说明它以及它前面的元素已经排好序了,这一趟结束。

插入排序和选择排序一个很大的区别就是插入排序每一趟有可能提前结束,即它只要到达一个位置大于等于它前面的元素,那么这一趟就已经排好了;而选择排序每一趟必须遍历完这一趟所有的元素,找到最小的那个,然后再把最小的那个和这一趟开始的元素进行swap,是不能提前结束的。

对于近乎有序的数组,适合用插入排序。
对于完全有序的数组,插入排序复杂度为O(n)O(n)。

基础版:
void insertionSort(T arr[], int n){

    for( int i = 1 ; i < n ; i ++ ) {

        // 寻找元素arr[i]合适的插入位置
        // 写法1
        for( int j = i ; j > 0 ; j-- ) //注意这里j遍历到下标为1的位置就好了,因为下面是将位置j和位置j-1的元素进行比较
            if( arr[j] < arr[j-1] )
                swap( arr[j] , arr[j-1] );
            else
                break;

        // 写法2
       // for( int j = i ; j > 0 && arr[j] < arr[j-1] ; j -- )
       //     swap( arr[j] , arr[j-1] );

    }

    return;
}
改进版:

将原本一次次的swap操作,变成一次次比较,而在一趟的最后进行赋值。

插入排序算法针对完全排好序的数组是O(n)级别的算法,每次判断一下当前数就是正确位置,这一趟就退出了

改进后的插入排序避免了很多次unnecessary copy,由此非常适合基本排好序而不需要很多次变动的数组。

void insertionSort(T arr[], int n){

    for( int i = 1 ; i < n ; i ++ ) {
        // 写法3
        T e = arr[i];// 声明一个变量保存要插入的元素
        int j; // j保存元素e应该插入的位置
        for (j = i; j > 0 && arr[j-1] > e; j--)//如果这个元素前面一个元素比它要大且未遍历到边界
            arr[j] = arr[j-1];把这个位置前面一个元素往这个位置挪
        arr[j] = e;//找到位置,赋值
    }

    return;
}

冒泡排序

思路:

i从最左边的元素开始遍历,一共要遍历n-1趟,因为第n-1趟遍历完成后,最后一个元素也就位了。在每一趟里面,j用来从第二个元素开始遍历到这一趟的最后一个元素,然后将它与它前面的元素比较,如果比前面的元素小就交换,然后j++;如果大于等于前面的元素就不交换,然后j++。直到遍历到这一趟的最后一个元素为止。
如,
第一趟:i = 0, j下标从1遍历到n-1,最后一个元素就位;
第二趟:i = 1, j从1遍历到n-2,最后一个元素就位
…
第m趟:i = m-1, j从1遍历到n-1-i
…
第n-1趟:i = n-2, j从1遍历到n-1-n+2=1

基础版:
void bubbleSort(T arr[], int n){
    for(int i = 0; i < n-1 ; i++){ // n-1趟即可
        for(int j = 1; j < n-i; j++){
            if(arr[j] < arr[j-1])
                swap(arr[j], arr[j-1]);
        }
    }
}

希尔排序

思路:

希尔排序的思路实际上是插入排序的延伸。插入排序中每一次都和之前的一个元素比较,而希尔排序每一次对之前的第h个元素进行比较,这样通过将h一个很大的值,逐渐变成一个很小的值,直到等于1,此时整个数组也排好了。

基础版:
void shellSort(T arr[], int n){

    // 计算 increment sequence: 1, 4, 13, 40, 121, 364, 1093...
    int h = 1;
    while( h < n/3 )
        h = 3 * h + 1;

    while( h >= 1 ){

        // h-sort the array
        for( int i = h ; i < n ; i ++ ){

            // 对 arr[i], arr[i-h], arr[i-2*h], arr[i-3*h]... 使用插入排序
            T e = arr[i];
            int j;
            for( j = i ; j >= h && e < arr[j-h] ; j -= h )
                arr[j] = arr[j-h];
            arr[j] = e;
        }

        h /= 3;
    }
}

// 比较SelectionSort, InsertionSort和BubbleSort和ShellSort四种排序算法的性能效率
// ShellSort是这四种排序算法中性能最优的排序算法
上面的排序算法都是O(n2)O(n2)级别的算法,下面介绍的归并排序和快速排序是O(nlogn)O(nlogn)级别的,那么O(n2)O(n2)和O(nlogn)O(nlogn)有什么不同呢?

这里写图片描述

归并排序

思路:

归并排序利用递归的思想,把数组分成两组,而后再在组内再分成两组,以此类推直到每组只有一个元素,此时每组都是排好序的。之后再两组两组进行merge操作。
需要申请额外空间,使得归并的时候时间复杂度是O(n)。
注意数组越界和范围定义的问题。

基础版:
template<typename T>

void mergeSort(T arr[], int l, int r){ //递归使用归并排序,对arr[l...r]范围进行排序

    if(l >= r)
        return;

    int mid = l + (r-l)/2;
    mergeSort(arr,l,mid);
    mergeSort(arr,mid+1,r);

    merge(arr, l, mid, r);
}

void merge(T arr[], int l, int mid, int r){ // 将arr[l...mid]和arr[mid+1,r]两部分进行归并

    T aux[r-l+1];
    for(int i = l ; i <= r; i++)
        aux[i-l] = arr[i]; //aux数组和arr数组的偏移量是l

    int i =  l, j = mid + 1;
    for(int k = l; k <= r; k++){

        //要考虑数组越界:越界情况是i>mid和j>r
        if(i > mid){
            arr[k] = aux[j-l];
            j++;
        }
        else if ( j > r){
            arr[k] = aux[i-l];
            i++;
        }

        //都没有越界的情况
        if(aux[i-l] < aux[j-l]){
            arr[k] = aux[i-l];
            i++;
        }

        else{
            arr[k] = aux[j-l];
            j++;
        }
    }
}
改进版:
  1. 对于近乎有序的数组,适合用插入排序,此时用归并排序反而效率很低,因此我们要对它进行优化。在mergeSort函数里,当两个子数组都sort了之后,且arr[mid]<=arr[mid+1],则无需进行merge操作,因为arr[l…mid]和arr[mid+1…r]都已经排好序了,而arr[mid]又小于等于arr[mid+1],此时整个数组就已经排好序了。在代码中只需加一行判断即可。
void mergeSort(T arr[], int l, int r){

    if(l >= r)
        return;
    int mid = l + (r-l)/2;

    mergeSort(arr, l, mid);
    mergeSort(arr, mid+1, r);

    if(arr[mid] > arr[mid+1])//merge之前判断
        merge(arr,l,mid,r);
}
  1. 当subarray比较小的时候,我们可以转而使用插入排序而非归并排序来提高性能,这是因为此时很大概率这个subarray是近乎有序的数组。
void mergeSort(T arr[], int l, int r){

    if(r - l <= 15){//数组元素少的时候采用插入排序
        insertionSort(arr, l, r);
        return;
    }
    int mid = l + (r-l)/2;

    mergeSort(arr, l, mid);
    mergeSort(arr, mid+1, r);

    if(arr[mid] > arr[mid+1])//merge之前判断
        merge(arr,l,mid,r);
}

之前的插入排序是从0…n-1进行排序的,这里的插入排序是从l到r进行排序的,细节上略有不同:

void insertionSort(T arr[], int l, int r){

    for(int i = l+1; i <= r; i++){
        T e = arr[i];
        int j;
        for(j = i; j > l && arr[j-1] > e; j--)
            arr[j] = arr[j-1];
        arr[j] = e;
    }
    return;
}

总结

这里写图片描述
需要注意的是,快速排序的空间复杂度是O(logn)O(logn),这是因为它使用递归需要开辟额外的栈空间来存储上一状态,递归的次数是lognlogn级别的。

C++软件异常分析概述 本文将详细讲述Windows系统中软件异常的分类以及常用的排查方法,给大家提供一个借鉴与参考。 阅读详情

相关推荐

永久关闭Windows更新的5种方法

很多家用电脑,如果系统自动更新的话,会变得越来越卡顿,且硬件型号兼容也并不完美。那么我们该如何彻底关闭Win11的自动更新呢?以下准备了5种方法,您可以根据自身实际情况选择合适的方法!

qq_43652793的博客 1万+

八大排序算法

八大排序算法1.冒泡排序 冒泡排序是一种交换排序, 就是两两比较待排序的元素, 若次序不满足要求则交换, 知道整个数组有序 基本思想 : 每次找到最大或最小值, 然后放到首位或最后一位 对于长度为n 的数组, 因为只需要找到n-1个数的位置, 最后一个就已经确定了. 所以我们外部循环需要从0 ~ n-2. 内部循环从 n-1到 i+1, 内部循环每次将最大值或最小值推到i的位置(即选出第i小或第i大的数). 往复n-1次, 就完成了排序 public void bubbleSort(int[...

柒七的博客 1551

PostgreSQL+PostGIS空间数据入库实战:从矢量栅格到GeoServer发布全流程

本文详细介绍了将矢量与栅格空间数据导入PostgreSQL并利用PostGIS扩展进行管理的完整流程。内容涵盖环境搭建、使用shp2pgsql和raster2pgsql工具进行数据入库、基础空间查询验证,以及最终通过GeoServer发布为地图服务的实战步骤,为构建空间数据平台提供清晰指引。

weixin_29268267的博客 289

各种排序算法

1、插入排序 遍历所有的值,每一个都插入到之前已经排好的队列中的合适位置 对于基本有序的数列排序,性能比较好 2、希尔排序(插入排序的改良版) 在插入排序之前,先按照一定的步长,把数列用插入排序排好,再逐渐减少步长,直到步长为1。 比插入排序多的步骤主要是为了,先初步排一下序,方便最后的插入排序。 对于基本有序的数列排序,性能比较好 3、冒泡排序 重复地走访过要排序的数列,一次比较两个元素,如果它们的顺序错误就把它们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。这个算.

qq_41716261的博客 1122

【同花顺公式编辑教程】第4章 功能函数

本章节主要给出大部分能够运行且常用的同花顺指标编辑器提供的函数。其中,计算类函数不作演示,绘图类函数提供示例及示例运行结果。

LiaoYi2016218的博客 2万+

Unity半透明物体景深失效?教你用双材质球方案完美解决(附完整Shader代码)

本文深入剖析了Unity中半透明物体导致景深效果失效的根本原因,即半透明物体默认不写入摄像机深度图。针对此问题,文章详细介绍了稳定高效的“双材质球”解决方案,通过为物体附加一个仅写入深度信息的不可见材质,完美修复景深效果,并提供了完整的Shader代码与实现脚本。

weixin_29010003的博客 381

几种基本排序方法的比较

本文章部分图片和定义参考网络上他人博客,如有侵权立即删除。 几种排序算法以及性能比较 稳定性:指排序时相同大小元素的相对位置是否发生变化,不发生变化则说明该排序稳定。 一、直接插入排序(内部排序、O(n^2)、稳定):小规模数据或者数据基本有序时高效   插入排序详细介绍:https://blog.youkuaiyun.com/sindyra/article/details/103597338 ...

sindyra的博客 2374

从d、q轴电流到电机性能:FOC控制中角度偏移的实战影响与调试策略

本文深入探讨了永磁同步电机FOC控制中d、q轴电流与角度偏移对电机性能的影响及调试策略。通过分析角度偏移导致的效率下降、电流异常等问题,提供了实用的四步调试法和参数优化技巧,帮助工程师有效提升电机控制精度和效率。

weixin_29264201的博客 294

【数据结构】各种排序算法

排序算法稳定性 如果在元素序列中有两个元素R[i]和R[j],它们的排序码K[i] == k[j],且 在排序之前,元素R[i]在R[j]的前面。如果在排序之后,元素R[i]仍在R[j] 之前,则称这个排序算法是稳定的,否则称这个排序算法是不稳定的。 内部排序:数据元素全部放在内存中的排序。   外部排序:数据元素太多不能同时放在内存中,根据排序过程的要求不能 在内外存之间移动数据的排序 ...

lw__sunshine的博客 447

先进封装Interposer仿真步骤及说明

摘要: Interposer仿真是2.5D/3DIC封装设计的关键环节,涵盖信号完整性(SI)、电源完整性(PI)、热及结构应力分析。流程分为五个阶段:1)前处理,定义层叠结构与材料属性;2)参数提取,通过3D电磁建模获取TSV、传输线等寄生参数;3)仿真设置,选择求解器并设定频率范围;4)结果分析,评估信号损耗、阻抗及电源网络性能;5)后处理,进行多物理场协同仿真并生成模型。核心挑战在于多尺度与多物理场耦合,需优先确保高速信号与电源网络的仿真精度。常用工具包括Ansys HFSS、Cadence Sigr

DSY_0324的博客 1343

Python自动化:3分钟搞定微信收藏链接批量导出到TXT(附完整代码)

本文介绍如何使用Python自动化工具在3分钟内将微信收藏链接批量导出到TXT文件。通过模拟人类操作和OCR技术,脚本高效处理大量链接,显著提升工作效率,并附有完整代码和实战避坑指南。

weixin_29062671的博客 628

算法-排序与双指针

具体实现时,需要先确定待排序数组中最大元素的值max,然后创建一个长度为max+1的计数数组count,遍历待排序数组,统计每个元素出现的次数,最后根据计数数组将元素放入相应的位置。具体实现时,需要先确定桶的数量和每个桶的范围,然后遍历待排序数组,将每个元素放入相应的桶中,最后对每个桶内部使用其他排序算法进行排序,最后将所有桶中的元素按照顺序依次放入待排序数组中。归并排序是一种基于分治思想的排序算法,其基本思想是将数组分成两个子数组,递归地对子数组进行排序,然后将两个有序的子数组合并成一个有序的数组。

weixin_51225684的博客 1280

Kettle 连接 Oracle 数据库全流程指南

例如:C:\Oracle\product\19.0.0\dbhome_1\jdbc\lib\ojdbc8.jar 2. 替换 Kettle 驱动文件 将驱动文件复制到 Kettle 的 目录: 删除旧版本驱动:如 ojdbc14.jar 只能保留一个oracle驱动 重启 Kettle 以加载新驱动 二、配置数据库连接 1. 启动 Kettle 并新建转换 运行 (Windows)或 (Linux)。 新建转换(Transformation),添加 “表输入” 步骤,双击进入配置。 2.

qq_44724453的博客 3480

排序算法大集合

排序算法大集合 1.快速排序 //快速排序 void Quick_Sort(int* arr, int begain, int end) { int i = begain; int j = end; if (i < j) { int temp = arr[i]; while (i < j) { while (i<j&&arr[j]>te...

a_hang_szz的博客 167

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

c的从大到小的排序算法

c的从大到小的排序算法 #include <stdio.h>#define SIZE 10int main(){int arr[SIZE]={100,200,400,21,-1,20,40,78,66,11};int len=sizeof(arr)/si...

191

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

大O表示法、常见排序算法(附有常见的排序算法代码)

大O表示法、常见排序算法(附有常见的排序算法代码)

jcandzero的博客 690

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

大O记法与排序算法

我们在描述算法的时间复杂度时都会用到大O记法,那么什么是大O记法呢?百度百科(大O符号)给出了比较准确的定义:它是用来描述一个函数的无穷大渐近。举个例子,解决一个规模为 n 的问题所花费的时间(或者所需步骤的数目)可以被求得:T(n) = 4n^2 - 2n + 2,那么当 n 趋近于无穷大的情况下,n方项起主导作用,所以它的时间复杂度可以被记为:O(n^2)。 更加详细的介绍可见一下博客: 大O...

让兔子飞得更高 659

详细介绍7大排序算法

1.直接选择排序思考非常好理解,但是效率不是很好。实际中很少使用2.时间复杂度:O(N^2)3.空间复杂度:O(1)4.稳定性:不稳定2.2.3 堆排序堆排序(Heapsort)是指利用堆积树(堆)这种数据结构所设计的一种排序算法,它是选择排序的一种。它是通过堆来进行选择数据。

weixin_71964451的博客 1641

8大排序算法详解

8大排序算法详解

WQP_Ya_Ping的博客 485

【leetcode】手撕排序算法,力扣912题的7大排序算法代码归总(纯代码)

本期主要讲解了关于排序算法的7种解题方式,涉及冒泡,选择,插入,希尔,堆排,分治,并归排序~~~

GGBond778的博客 2521

c 语言从大到小排序算法,10 大经典排序算法(动图演示+ C 语言代码)

原标题:10 大经典排序算法(动图演示+ C 语言代码)来源:C语言与CPP编程以前也零零碎碎发过一些排序算法,但排版都不太好,又重新整理一次,排序算法是数据结构的重要部分,系统地学习很有必要。时间、空间复杂度比较排序算法平均时间复杂度最差时间复杂度空间复杂度数据对象稳定性冒泡排序O(n2)O(n2)O(1)稳定选择排序O(n2)O(n2)O(1)数组不稳定、链表稳定插入排序O(n2)O(n2)O...

weixin_32139147的博客 3303

【一起学习排序算法】 算法特性及大O记法

作者:莫林 来源:掘金 原文链接: https://juejin.im/post/5bf2e626f265da616f6f92f8 排序算法 排序算法(Sorting algorithms)是什么? Wikipedia 说: In computer science, a sorting algorithm is an algorithm that puts elements of a list in a certain order. 也就是说,排序算法,就是某种算法,将列表中的元素按照某

qq_40229790的博客 285

java sortable_Java实现的5大排序算法

Java实现的5大排序算法排序算法很多地方都会用到,近期又重新看了一遍算法,并自己简单地实现了一遍,特此记录下来,为以后复习留点材料。废话不多说,下面逐一看看经典的排序算法:1、Java排序算法之选择排序选择排序的基本思想是遍历数组的过程中,以 i 代表当前需要排序的序号,则需要在剩余的[i…n-1]中找出其中的最小值,然后将找到的最小值与i指向的值进行交换。因为每一趟确定元素的过程中都会有一个选...

weixin_32021519的博客 365

Java 8大排序算法之选择排序

       选择排序(Selection sort)是一种简单直观的排序算法。它的工作原理是:第一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,然后再从剩余的未排序元素中寻找到最小(大)元素,然后放到已排序的序列的末尾。以此类推,直到全部待排序的数据元素的个数为零。选择排序是不稳定的排序方法。 说白...

weixin_44148815的博客 308

各种排序算法大汇总

比较排序是比较常见的排序算法,它分为以下几个类:交换排序:冒泡排序(BubbleSort)和快速排序(QuickSort)。插入排序:直接插入排序和希尔排序(ShellSort)。选择排序:选择排序(SelectSort)和堆排序(HeapSort)。(一)交换排序:void BubbleSort(int* arry, int size) { for (int i = 0; i < size -

如风 657
上一篇: 计算机网络+计算机组成原理+操作系统高频笔试面试题
下一篇: [Leetcode] 125. Valid Palindrome
Peggy_Chang
博客等级 码龄11年 21粉丝 44原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值