常见排序汇总--你都了解吗?

常见的排序算法汇总(详解篇) 所谓排序,就是使一串记录,按照其中的某个或某些关键字的大小,递增或递减的排列起来的操作。稳定性 :假定在待排序的记录序列中,存在多个具有相同的关键字的记录,若经过排序,这些记录的相对次序保持不变,即在原序列中, r[i]=r[j] ,且 r[i] 在 r[j] 之前,而在排序后的序列中, r[i] 仍在 r[j] 之前,则称这种排序算法是稳定的;否则称为不稳定的。数据元素全部放在内存中的排序。数据元素太多不能同时放在内存中,根据排序过程的要求不能在内外存之间移动数据的排序。 阅读详情

目录

1,排序的比较方法

2,堆排序

3,冒泡排序

4,直接插入排序

5,希尔排序

6,直接选择排序

7,快速排序

8,归并排序

一,排序的比较

我们一般比较排序只要通过判断排序是否是稳定的,然后就是比较时间复杂度和空间复杂度,并且在下面的排序当中也会设计到,具体稳定性:也就是如下图,我们原本红色的5在后面,不过通过排序之后,可能会有以下两种情况,位置不改变也就是稳定的,空间复杂度我们探究的是最坏情况

二,堆排序

核心:堆排序为的是原地进行排序,而不是重现创建空间来排序,这和我下面提到的从小到大排的时候就要建立大根堆,而相反的从大到小排序就要建立小根堆说法一致

堆排序就是利用优先级队列的思想来排序,当我们想要从小到大排的时候就要建立大根堆,而相反的从大到小排序就要建立小根堆,我们就拿从小到大排来举例,我们先要创建一个大根堆,堆顶元素就是所有里面最大的,然后将最后一个元素和堆顶元素进行交换,然后usedsize--,然后调整除刚换下来的数据以外的数据,然后找到次大的,然后调整剩下的n-2个,直到调整完

稳定性:不稳定,因为当我们堆顶元素和最后元素进行交换后,原来本来存在的顺序会进行一个一百八十度翻转

时间复杂度:O(nlogn),通俗理解:一共 n 个元素,每个元素最多下沉 (log n) 层,总代价 (nlog n)。

空间复杂度:O(1),没有创建新的空间

 public void creatheap(){
        //先找到最后一颗子树的根节点的下标
        for (int parent = (usedsize-1-1)/2; parent >=0; parent--) {
            shelldown(parent, usedsize);
        }
    }
    //向下调整
    private void shelldown(int parent,int usedsize){
        //1,先取得左孩子节点的下标
        int child=parent*2+1;
        //调整到child小于usedsize的时候
        while (child<usedsize){
            //先取得左右孩子中最大的,并且得保证有右孩子的情况下,没有就直接不用变
            if (child+1<usedsize && elem[child]<elem[child+1]){
                child++;
            }
            //现在child里面存储的就是左右孩子里的最大值的下标,然后进行交换
            if (elem[child]>elem[parent]){
                swap(elem,parent,child);
                //只能保证调整了的是正确的,但是还得向下调整保证换完的也是大根堆
                parent=child;
                child=parent*2+1;
            } else {
                break;
            }
        }
    }
//从小到大排
    public void heapsort(){
        int end=usedsize-1;
        while (end>0){
            swap(elem,0,end);
            shelldown(0,end);
            end--;
        }
    }

三,冒泡排序

很常见的一种排序方法,让大的依次放到最后面,跟冒泡一样

public void BubbleSort(int[]array){
        for (int i = 0; i < array.length-1; i++) {
            for (int j = 0; j < array.length - 1 - i; j++) {
                if (array[j]>array[j+1]){
                    int tmp=array[j];
                    array[j]=array[j+1];
                    array[j+1]=tmp;
                }
            }
        }
    }

稳定性:稳定,因为内层循环是严格的判断array[j]>array[j+1]

时间复杂度:O(N^2),外层执行n-1轮,内层最坏依次执行n-1,n-2......总比较次数:((n-1)+(n-2)+...+1 = n(n-1)/2,也就是n^2

空间复杂度:O(1),原地排序

四,直接插入排序

跟打牌把牌插入一样,定义了i,j下标,并且开始j=i-1,并且假设一个零时变量tmp,并且把array[i]的值放入tmp里面,并且和array[j]的值进行比较,然后j--进行回调,直接插入排序的特点:有序度越高,插入排序需要的元素移动次数越少,运行速度越快;完全有序时达到线性最优效率。

  //直接插入排序
    public void InsertSort(int[] array){
        for (int i = 1; i < array.length; i++) {
            int tmp=array[i];
            int j = i-1;
            for (; j >=0; j--) {
                if (array[j]>tmp){
                    array[j+1]=array[j];
                }else {
                    break;
                }
            }
            array[j+1]=tmp;
        }
    }

稳定性:稳定,比较逻辑:if(tmp < array[j]) 才移动元素

时间复杂度:O(N^2),内层循环每次都要把前面所有元素往后移

空间复杂度:O(1),原地排序

五,希尔排序

将数据分成很多组来进行排序,如第一次分成五组,每组数据进行排序,接下来再分成两组,组内排序,最后是整组数据一起排序,当然分的组的个数各有说法,可以分成6组可以分成3组,都是可以的,所以我以gap=array.lenth/2来进行分组数,当然组的数据也不能挨着来分,是跳着来分的,目的是为了让大的数据尽可能的往后移

public static void ShellSort(int[]array){
        int gap=array.length;
        while (gap>1){
            gap=gap/2;
            shell(array, gap);
        }
    }
    public static void shell(int[]array,int gap){
        for (int i = gap; i < array.length; i++) {
            int tmp=array[i];
            int j = i-gap;
            for (; j >=0; j-=gap) {
                if (array[j]>tmp){
                    array[j+gap]=array[j];
                }else {
                    break;
                }
            }
            array[j+gap]=tmp;
        }
    }

稳定性:不稳定

时间复杂度:O(N^1.3)-O(N^1.5)

空间复杂度:O(1),原地排序

六,直接选择排序

定义i,j下标和minIndex记录小值的下标,j一直往后走,找到比当前minIndex记录的值还小的值,如果有则minIndex换成j,然后进行交换

public static void SelectSort(int[]array){
        for (int i = 0; i < array.length; i++) {
            int minIndex=i;
            for (int j = i+1; j < array.length; j++) {
                if (array[j]<array[minIndex]){
                    minIndex=j;
                }
            }
            //开始交换
            swap(array,i,minIndex);
        }
    }
    private static void swap(int[]array,int i,int minIndex){
        int tmp=array[i];
        array[i]=array[minIndex];
        array[minIndex]=tmp;
    }

稳定性:不稳定

时间复杂度:O(N^2)

空间复杂度:O(1),原地排序

七,快速排序

1,Hoare法

public static void QuickSort(int[]array){
        quick(array,0,array.length-1);
    }

    private static void quick(int[] array, int start, int end) {
        if (start>=end){
            return;
        }
        //找到中值的下标
        int par=pattion(array,start,end);
        //左边排序
        quick(array,start,par-1);
        //右边排序
        quick(array,par+1,end);
    }

    private static int pattion(int[] array, int low, int high) {
        //array[low]这个值是一个基准值,通过low以及high以及最后的一个交换,使基准值的左边比他小,右边比他大,让他是一个中值,并且返回中值的下标
        int pivot=array[low];
        int i=low;
        while (low<high){
            //high找到比pivot小的值
            //low找到比pivot大的值
            while (array[high]>=pivot && low<high){
                high--;
            }
            while (array[low]<=pivot && low<high){
                low++;
            }
            swap(array,high,low);
        }
        //走完这个循环后low和high走到了一起,让这个值的下标和pivot的下标交换
        swap(array,i,low);
        return low;
    }

稳定性:不稳定

时间复杂度:最小O(N*log2N),最大:O(N^2)

空间复杂度:最小O(log2N),最大:O(N)

2,挖坑法

private static int pattion2(int[] array, int low, int high) {
        int tmp=array[low];
        int i=low;
        while (low<high){
            //high找到比pivot小的值
            //low找到比pivot大的值
            while (array[high]>=tmp && low<high){
                high--;
            }
            array[low]=array[high];
            while (array[low]<=tmp && low<high){
                low++;
            }
            array[high]=array[low];
        }
        array[low]=tmp;
        return low;
    }

3,快排的改善

因为快排的时间复杂度取决于递归的树的高度,因为数量是不变的,所以当我们是完全二叉树的时候,我们树的高度是最小的,为log2N,因此此时的时间复杂度和空间复杂度是最小的,最大的情况就是123,或者321这种有序的数组,因为这样的树就只有左树或者只有右树,导致树的高度最大,为N,所以我们要改善就要尽量使高度减少,用到的方法就是三数取中,找到low下标,high下标和(low+high)/2下标中的最小值,然后将low下标的值和这个值进行交换

 private static int threeMid(int[] array,int low, int high) {
        int mid = (low+high)/2;
        if(array[low] < array[high]) {
            if(array[mid] < array[low]) {
                return low;
            }else if(array[mid] > array[high]) {
                return high;
            }else {
                return mid;
            }
        }else {
            // array[low] > array[high]
            if(array[mid] < array[high]) {
                return high;
            }else if(array[mid] > array[low]) {
                return low;
            }else {
                return mid;
            }
        }
    }

4,快排的非递归实现

public static void QuickSortNor(int array[]){
        int start=0;
        int end=array.length-1;
        int par=pattion2(array,start,end);
        Deque<Integer> stack=new LinkedList<>();
        if (par>start+1){
            stack.push(start);
            stack.push(par-1);
        }
        if (par<end-1){
            stack.push(par+1);
            stack.push(end);
        }
        while (!stack.isEmpty()){
            end=stack.poll();
            start=stack.poll();
            par=pattion2(array,start,end);
            if (par>start+1){
                stack.push(start);
                stack.push(par-1);
            }
            if (par<end-1){
                stack.push(par+1);
                stack.push(end);
            }
        }
    }

5,两个问题解决

第一个问题:等号是否可以去除

第二个问题:是否可以让low先走 先++

问题一:不可以,因为当我们0下标和array.lenth-1下标的数一样,那么就会两个一样的数一直交换陷入死循环

问题二:不可以,因为我们每次par的目标都是让par左边的数都比par小,右边都比par大,如果让low先走,low是为了找到比par大的数字,最后当low和high相遇的前一步,是low先走的,那么low和high会想遇到low的任务,就是比基准大的数,当基准和这个大的数交换就不能实现左边都小了

八,归并排序

1,正常递归

先把数据整齐的拆分为左右两部分,一直到只剩一个元素的时候,开始逐渐的往上开始合并

public static void MergeSort(int[] array){
        mergesort(array,0,array.length-1);
    }

    private static void mergesort(int[] array, int left, int right) {
        if (left>=right){
            return;
        }
        int mid=(left+right)/2;
        //左分
        mergesort(array,left,mid);
        //右分
        mergesort(array,mid+1,right);
        //合并
        marge(array,left,mid,right);
    }

    private static void marge(int[] array, int left, int mid, int right) {
        int[] tmp=new int[right-left+1];
        //用于记录数组的下标
        int k=0;
        int s1=left;
        int e1=mid;
        int s2=mid+1;
        int e2=right;
        //保证两段都有数据
        while (s1<=e1 && s2<=e2){
            if (array[s1]>array[s2]){
                tmp[k++]=array[s2++];
            } else{
                tmp[k++]=array[s1++];
            }
        }
        //这里走完当s1超过了e1或者s2超过了e2,也就是有一段或者两段走完了的,所以可能出现没走完的,就让他直接放在数组里
        while (s1<=e1){
            tmp[k++]=array[s1++];
        }
        while (s2<=e2){
            tmp[k++]=array[s2++];
        }
        //下面得将其拷贝在数组里
        for (int i = 0; i < tmp.length; i++) {
            array[i+left]=tmp[i];
        }
    }

稳定性:稳定

时间复杂度:O(N*log2N)

空间复杂度:O(N)

2,归并排序的非递归

思想:递归是递归左右两边,为了不递归,那我就要找到左右两边最开始的下标,所以我引进了gap这个变量,并且gap每次乘2,然后left和right每次都是分组的第一个和最后一个,mid每次都是还没分组的最后一个,例如6 3,mid就指向6,四个已经分好的时候1 2 3 6 4,mid就指向6

public static void MergeSort2(int[] array) {
        int gap = 1;
        while (gap < array.length) {
            for (int i = 0; i < array.length; i = i + gap * 2) {
                int left = i;
                int mid = left + gap - 1;
                if (mid > array.length-1 ) {
                    mid = array.length - 1;
                }
                int right = mid + gap;
                if (right > array.length-1) {
                    right = array.length - 1;
                }
                marge(array, left, mid, right);
            }
            gap *= 2;
        }
    }

Mysql排序与分类汇总实践 Mysql排序与分类汇总实践 一、目的 1、掌握数据排序的基本方法 2、学会使用SQL命令进行数据分类汇总操作 二、内容 用于企业管理的员工管理数据库,数据库名为YGGL,包含员工信息表Employees、部门信息表Departments、员工薪水情况表Salary ,各表数据如下。 对YGGL数据库完成以下查询。 1、 按部门列出该部门工作的员工人数。 select 部门名称,count(*) 人数 from departments JOIN employees ON (departments.部门 阅读详情

相关推荐

Excel分类汇总的5个隐藏技巧:排序+汇总这样用效率翻倍(附常见错误排查)

本文深入解析Excel分类汇总的5个高效隐藏技巧,重点揭示排序与汇总的组合应用逻辑,并详细指导如何避免二级汇总的常见错误。文章还提供了数据更新后的刷新策略与实用快捷键,帮助财务、销售等人员大幅提升报表处理效率与准确性。

grpc6streamer的博客 929

sql 去重求和_SQL汇总分析

上期我们学习了SQL的基本语句,现在我们再深入了解SQL汇总分析方法。在实际工作中,我们往往需要对数据进行汇总整理分析,在SQL中我们可以运用函数进行汇总分析,常用的函数包括:计数count 求和sum 平均值agv 最大数max 最小数 min具体例子:小小练习:注意:如果需要对函数内对象去重可以直接在前面加上distinct .如果select后面加的是*那就表示是整个表的数据。分组:运用 G...

weixin_39772849的博客 4606

pandas | DataFrame中的排序与汇总方法

本文始发于个人公众号:TechFlow,原创不易,求个关注 今天是pandas数据处理专题的第六篇文章,我们来聊聊DataFrame的排序与汇总运算。 在上一篇文章当中我们主要介绍了DataFrame当中的apply方法,如何在一个DataFrame对每一行或者是每一列进行广播运算,使得我们可以在很短的时间内处理整份数据。今天我们来聊聊如何对一个DataFrame根据我们的需要进行排序以及一些汇总运算的使用方法。 排序 排序是我们一个非常基本的需求,在pandas当中将这个需求进一步细分,细分成了根据

TechFlow的博客 2955

常用排序算法总结

常用排序算法总结 在网上找到了关于常见排序算法总结的比较好的两篇帖子,把链接复制如下: 常用排序算法总结(一):https://www.cnblogs.com/eniac12/p/5329396.html 常用排序算法总结(二):http://www.cnblogs.com/eniac12/p/5332117.html...

Allenlzcoder的博客 473

第4章 数据的排序、筛选和分类汇总

Excel提供了强大的数据处理工具,包括排序、筛选和分类汇总三大功能。排序功能支持单条件与多条件排序,可按数值、文本或自定义逻辑排列数据;筛选功能包含自动筛选和高级筛选,能精确筛选文本、数值和日期数据,并支持删除重复项;分类汇总功能可对单类或多类数据进行统计分析,如求和、计数等,并支持分级查看数据。这些工具协同工作,为用户提供了高效、灵活的数据处理解决方案,能显著提升数据分析效率。

2301_81706452的博客 1206

Function实现ALV Table七:汇总,分类汇总,排序,过滤

v/:* {behavior:url(#default#VML);}o/:* {behavior:url(#default#VML);}w/:* {behavior:url(#default#VML);}.shape {behavior:url(#default#VML);} Normal 0 7.8 磅 0 2

焕然一新 5455

常见查找和排序算法汇总

主要内容: 顺序查找、折半查找-------查找算法 冒泡排序、简单选择排序、直接插入排序、希尔排序、归并排序、快速排序、堆排序------排序算法 一、查找 1、顺序查找 从最后一个记录开始,逐个进行比较,若相等则查找成功,否则查找失败。 //顺序查找 a[1 - len] int Sq_Search(int a[],int key,int len) { int i; //哨兵,使内循环不用判断数组是否越界,提高程序运行效率,减少查找时间 a[0] = key; for(i = len;a[

qq_44829047的博客 3760

PHP数组排序方法汇总

在PHP中,对数组进行排序是一项常见的任务。本文将总结一些常用的PHP数组排序方法,并提供相应的源代码示例。这些是PHP中常用的数组排序方法。根据具体的需求,选择适当的方法可以轻松地对数组进行排序。

VtteAlgorithm的博客 93

常见排序算法汇总

整理一下之前学习的各种排序算法

夜槿笙歌的博客 8920

基于STM32与SimpleFOC实现直流无刷电机开环控制的实战指南

本文提供了一份基于STM32微控制器与SimpleFOC开源库实现直流无刷电机开环控制的详细实战指南。内容涵盖硬件连接、PlatformIO环境搭建、核心代码解析及上电测试,旨在帮助开发者快速验证硬件并理解开环控制的基本原理,为后续实现高性能的闭环FOC控制奠定基础。

xxx12的博客 961

ROS2实战:构建模块化启动文件(launch file)以驱动复杂机器人系统

本文详细介绍了ROS2中构建模块化启动文件(launch file)的最佳实践,帮助开发者高效管理复杂机器人系统的节点启动。通过功能分解、参数化设计和嵌套启动等技术,实现批量管理、依赖控制和配置统一,显著提升系统稳定性和调试效率。文章包含实战代码示例和工程化建议,特别适合自动驾驶、物流机器人等场景应用。

weixin_28744613的博客 216

ALV 排序、汇总

在SAP ABAP ALV中,排序和汇总是两个关键特性,用于组织和分析数据显示。排序排序功能允许用户根据一个或多个列的值对ALV中的数据行进行升序或降序排列。这可以通过在调用显示函数REUSE_ALV_GRID_DISPLAY时传递适当的参数来实现。汇总汇总功能允许在ALV中对指定列的数据进行求和计算,并在报表底部或每组数据末尾显示结果。

Leo520liang的博客 1822

PrimeTime生成.lib竟暗藏PG添加Bug

1. 确认原始库中是否包含PG引脚的定义。2. 查阅PrimeTime的write_lib命令文档,寻找相关选项。3. 在生成库时使用正确的选项,例如-include_pg_pins或类似参数。4. 验证生成的.lib文件是否包含pg_pin部分。

limanjihe的专栏 1921

常见常考查找、搜索、排序算法汇总

堆本质上是一个近似完全二叉树,同时满足堆属性。近似完全二叉树: 树的所有层都被完全填满,除了可能的最后一层,最后一层的节点都尽量靠左排列。这个结构特性使得我们可以用一个数组来高效地表示堆,无需指针。对于数组中索引为 i 的节点:其父节点索引为 (i-1)/2其左子节点索引为 2*i + 1其右子节点索引为 2*i + 2堆属性最大堆 (Max-Heap): 每个节点的值都大于或等于其子节点的值。这意味着堆顶元素(数组第一个元素)是整个堆中的最大值。最小堆 (Min-Heap): 每个节点的值都。

weixin_74402791的博客 1092

GPU资源池化:技术原理与应用场景全解析

GPU资源池化技术已成为AI时代高效利用算力的关键方案。该技术通过硬件虚拟化、容器化编排和智能调度三个核心层面,实现GPU资源的共享与优化,可将平均利用率从不足30%提升至60-80%。主流方案包括NVIDIA全栈解决方案、云原生Kubernetes生态及开源工具,适用于企业AI平台、大模型训练和边缘推理等场景。虽然面临性能隔离、资源碎片等挑战,但随着硬件虚拟化细化和AI驱动调度算法的发展,GPU池化正向着智能化、自动化方向演进,推动实现"算力如水电"的愿景。

技术引领业务创新 1352

Qi标准下的充电协议及其记忆技巧

记忆无线充电协议中的。

m0_73991989的博客 1320

常见排序算法的时间复杂度汇总

排序算法 最佳时间复杂度 平均时间复杂度 最坏时间复杂度

qq_35556064的博客 9037

微信小程序审核避坑指南:巧用 wx.getAccountInfoSync 实现审核与线上环境无感切换

本文详细介绍了如何利用`wx.getAccountInfoSync`API实现微信小程序审核与线上环境的无感切换。通过环境识别技术和动态渲染架构设计,开发者可以优雅解决审核资质门槛问题,同时保持生产环境的完整用户体验。文章包含组件化实现、全局状态管理等实用方案,帮助开发者提升审核通过率。

weixin_30527423的博客 260

mysql 对分类汇总进行排序_如何对excel分类汇总的数据进行排序

展开全部1.首先,62616964757a686964616fe58685e5aeb931333337626166来看看要进行分类汇总的表格数据,如图1所示。2.先对数据以“产品名称”为关键字进行一次排序,如图2所示,为排序后的效果。3.然后在数据区域选中任何一个单元格,单击“数据”---“分级显示”组中的“分类汇总”,如图3所示。4.在弹出的“分类汇总”对话框中,在“分类字段”框中选择进行分类汇...

weixin_42507868的博客 1353

昇腾AI原生创新算子挑战赛(S1赛季)复盘-LessEqual算子

【代码】昇腾AI原生创新算子挑战赛(S1赛季)复盘-LessEqual算子。

william_myq的博客 509

UWB 多传感器通信的纳秒无线位置和时钟同步方法

利用UWB高精度的特点,实现多节点下的无线时钟同步和定位。通过优化硬件架构,减少不确定延迟的影响,系统可以提供纳秒级时钟同步消息

DT程序员的博客 1330

常见七大排序(汇总)

快速排序(快排)(递归&非递归) 、 归并排序(递归&非递归) 、 希尔排序 、 堆排序 、 直接插入排序 、 选择排序 、冒泡排序 汇总

2302_80023639的博客 868

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

常见简单的排序算法汇总

带你了解插入排序,希尔排序,选择排序,堆排序,冒泡排序算法。

m0_56911284的博客 1426

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

精雕软件(JDpaint) 5.5 绿色版

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

各种排序汇总

以下将详细介绍常见排序算法的排序过程,并给出对应的 C++ 代码实现。

doubleintfloat的博客 986

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

MySQL汇总排序查询

计算出来的字段销售总额保留两位小数; 排序时,汇总不参与排序,放在最下面。

诡途的博客 3816
上一篇: Java数据结构7(优先级队列)
下一篇: Java数据结构8(map和set)
评论 3
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值