数据结构七:七大排序

news2024/11/28 14:31:30

目录

1:排序的概率

2.插入排序

2.1:直接插入排序-----稳定

2.1.1:基本思想

2.2:希尔排序

2.2.1:概念:

3.选择排序

3.1:选择排序

3.1.1:概念

3.2:堆排序

4.交换排序

4.1:概念

4.2:冒泡排序

4.3:快速排序

4.3.1:hoare版(左右指针)

4.3.2:挖坑法

4.3.3:前后指针

4.4:快排的优化

4.4.1:三数取中--取中间数值做基准

4.5:快排的非递归

5.归并排序

5.1:海量数据的排序问题


前言:前一篇我们讲了堆和优先级队列。接下来我们将进行的是七大排序,但我不会讲这七大排序都着重的说,会将一些排序大致带过,如冒泡排序,堆排序。

1:排序的概率

排序:所谓排序,就是使一串记录,按照其中的莫个或莫些关键字的大小,递增或递减的排列起来。

稳定性:在原序列中,r[i]=r[j],且r[i]在r[j]的前面,而在排序后的序列中r[i]仍在r[j]的前面,这样称为稳定性。

内部排序:数据元素放在内存中的排序。

外部排序:数据元素不能同时放在内存中,根据排序过程的要求不能在内外之间移动数据的排序。


2.插入排序

2.1:直接插入排序-----稳定

2.1.1:基本思想

将带排序的记录按其关键码的大小逐个插到一个已经排好序的有序序列中,直到所有的记录插入完为止。感觉像不像打牌的时候,自己弄自己手中的牌

 /**
     * 直接插入排序
     * 时间复杂度O(N^2)
     * 空间复杂度0(1)
     * 稳定
     * @param arr
     */
    public void insertSort(int [] arr){
        for (int i = 0; i <arr.length ; i++) {
          int tmp=arr[i];//记录关键码
            int j=i-1;
            for (; j >=0 ; j--) {//插入到0到i-1中
               if(arr[j]>tmp){//tmp小于arr[j]
                   arr[j+1]=arr[j];//将arr[j]向后移一个
                }else{
                   break;
               }
            }
            arr[j+1]=tmp;
        }
    }

 注意:

一个本身就稳定的排序可以实现为不稳定的排序。


2.2:希尔排序

2.2.1:概念:

先选定一个整数(gap),把待排序的文件中所有记录分成一个gap个组,所有距离相同的分在同一组,并对每一组内的记录进行排序(插入排序)。然后,重复上述分组和排序的工作。

这个gap有多种取法,我一般是按照shell提出的gap=[n/2](n:是待排元素的个数)。

 /**
     * 希尔排序
     * 时间复杂度O(2^1.3)
     * 不稳定
     * @param arr
     */
    public  static void shell(int [] arr){
        int gap= arr.length;
        while(gap>1){
            gap=gap/2;
            for (int i = gap; i <arr.length ; i++) {
                int tmp=arr[i];
                int j=i-gap;
                for (; j >=0 ; j=j-gap) {
                    if (arr[j] > tmp) {
                        arr[j + gap] = arr[j];
                    }else{
                        break;
                    }
                }
                arr[j + gap] = tmp;
            }
        }
    }

3.选择排序

3.1:选择排序

3.1.1:概念

每一次从待排序的数据元素中选出最小或(最大)的一个元素,存放到序列的起始位置,直到全部待排序的数据元素排完

  /**
     * 选择排序
     * 时间复杂度O(N^2)
     *空间复杂度o(1)
     * 不稳定
     * @param arr
     */
    public static  void select(int [] arr){
        //选出最大值和最小值
        int left=0;
        int right=arr.length-1;
        while(left<right) {
            int min=left;
            int max=left;
            for (int i = left+1; i <=right; i++) {
                if (arr[i] < arr[min]) {
                    min =i;
                }
                if (arr[i] >arr[max]) {
                    max = i;
                }
            }
            //最小值和left交换。
            swap(arr,min,left);
            //最大值和right交换
            if(left==max){//这里是害怕max就是left
                max=min;
            }
            swap(arr,max,right);
            left++;
            right--;
        }
    }
    protected static void swap(int [] arr,int i,int j){
        int tmp=arr[i];
        arr[i]=arr[j];
        arr[j]=tmp;
    }
}

3.2:堆排序

这里,我上一篇已经讲了,上一篇的建堆就是堆排序。

注意:

排升序要排大堆

排降序要排小堆

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

空间复杂度:O(1)

不稳定


4.交换排序

4.1:概念

键值较大的记录向序列的尾巴移动,键值较小的记录向序列的前部移动

4.2:冒泡排序

    /**
     * 冒泡排序
     * 时间复杂度O(N^2)
     * 空间复杂度O(1)
     * 稳定
     * @param arr
     */
    public  static  void bubble(int [] arr){
        for (int i = 0; i < arr.length ; i++) {
            for (int j = 0; j < arr.length-1-i ; j++) {
                if(arr[j]>arr[j+1]){
                    swap(arr,j,j+1);
                }
            }
        }
    }

4.3:快速排序

任取待排序元素序列中的莫元素作为基准值,按照该排序列将排序集合分割成两子序列,左子序列中所有元素均小于基准值,右子序列中所有元素均大于基准值,然后左右子序列重复该过程,直到所有元素都排列在相应位置上为止

4.3.1:hoare版(左右指针

 /**
     * 快速排序
     * 左右指针找基准
     * 时间复杂度O(N*logN)
     * 空间复杂度O(logN)
     * 不稳定
     * @param arr
     */
    public static void quick(int [] arr){
        quickChild(arr,0,arr.length-1);
    }
    protected static void quickChild(int [] arrt ,int star,int end){
       if(star>=end){
           return;
       }
        int pivot=partition(arrt,star,end);
       quickChild(arrt,0,pivot-1);//这是基准前部分
       quickChild(arrt,pivot+1,end);//基准后部分
    }
    //找基准
    protected static int partition(int [] arr,int start ,int end){
        int pivot=start;
        int left=start;
        int right=end;
        while(left<right){
            if(arr[right]>arr[pivot]){
                right--;
            }
            if(arr[left]<arr[pivot]){
                left++;
            }
            //这时候right找到比基准小的数
            //left找到比基准大的数。两者进行交换
            swap(arr,left,right);
        }//left和right相遇
        //left和para交换
        swap(arr,left,pivot);
        //返回基准值
        return  pivot;
    }

4.3.2:挖坑法

 protected static  int partition2(int [] arr,int start,int end){
        int left=start;
        int tmp=arr[left];
        int right=end;
        while(left<right){
            while(left<right&&arr[right]>=tmp){
                right--;
            }//这时候 right比基准小
            arr[left]=arr[right];
            while(left<right&&arr[left]<=tmp){
                left++;
            }//这是left比基准大
            arr[right]=arr[left];
        }//left和right相遇
        arr[left]=tmp;
        return  left;//返回基准
    }

4.3.3:前后指针

  //前后指针
    protected static int  partition(int [] arr,int start,int end){
        int pivot=end;
        int prev=start-1;
        int cur=start;
        for (; cur <end ; cur++) {
            if(arr[cur]<=arr[pivot]){
                prev++;
                swap(arr,cur,prev);
            }//这时候cur走到了
        }
        swap(arr,prev+1,pivot);
        return (prev+1);
    }

4.4:快排的优化

4.4.1:三数取中--取中间数值做基准

 protected static void quickChild(int [] arrt ,int star,int end){
       if(star>=end){
           return;
       }
       //小区间的是,待排序的数组是几乎接近有序的。
        //这时候我们可以在小区间直接用插入排序
        if(end-star>=2){
            insertSort(arrt,star,end);
        }
       //三数取中
        int index=findMidValOfIndex(arrt,star,end);
        swap(arrt,star,index);
        int pivot=partition(arrt,star,end);
       quickChild(arrt,0,pivot-1);//这是基准前部分
       quickChild(arrt,pivot+1,end);//基准后部分
    }
    //三数取中
    private  static  int findMidValOfIndex(int [] arr,int start,int end){
        int mid=(end+start)/2;
        //大体分两种情况
        if(arr[start]>arr[end]){
            if(arr[mid]>arr[start]){
                return  start;
            }else if(arr[end]>arr[mid]){
                return  end;
            }else{
                return  mid;
            }
        }else{
            if(arr[mid]>arr[start]){
                return  mid;
            }else if(arr[mid]>arr[end]){
                return  end;
            }else{
                return  start;
            }
        }
    }

4.5:快排的非递归

 //快排的非递归
    public static  void noquick(int [] arr){
    Stack<Integer>s1=new Stack<>();
    int start=0;
    int end=arr.length-1;
    int index=partition2(arr,start,end);
    //判断左边的数字个数是否大于1;
        if(index-start>1){
            s1.push(start);//左边的头
            s1.push(index-1);//左边的尾
        }
        //判断右边的字数个数是否大于1
        if(end-index>1){
            s1.push(index+1);
            s1.push(end);
        }
        while(!s1.empty()){
            end=s1.pop();//栈是先进后出
            start=s1.pop();
            index=partition2(arr,start,end);
            //判断左边的数字个数是否大于1;
            if(index-start>1){
                s1.push(start);//左边的头
                s1.push(index-1);//左边的尾
            }
            //判断右边的字数个数是否大于1
            if(end-index>1){
                s1.push(index+1);
                s1.push(end);
            }
        }
    }

5.归并排序

  /**
     * 归并排序
     * 时间复杂度:O(N*logN)
     * 空间复杂度:O(N)
     * wend
     * @param arr
     */
    public static  void merge(int [] arr){
        mergeChild(arr,0,arr.length-1);
    }
    public  static  void mergeChild(int [] arr,int start,int end){
        if(start==end){
            return;
        }//拆分数组
        int mid=(start+end)/2;
        mergeChild(arr,start, mid);
        mergeChild(arr,mid+1,end);
        //合并数组
        merge1(arr,start,mid,end);
    }

    protected static void merge1(int[] arr, int start, int mid, int end) {
        int s1 = start;
        int a1 = mid;
        int s2 = mid + 1;
        int a2 = end;
        int[] tmp = new int[end - start + 1];
        int count = 0;
        while (s1 <= a1 && s2 <= a2) {
            if (arr[s1] <= arr[s2]) {
                tmp[count++] = arr[s1++];
            } else {
                tmp[count++] = arr[s2++];
            }
        }
        while (s1 <= a1) {
            tmp[count++] = arr[s1++];
        }
        while (s2 <= a2) {
            tmp[count++] = arr[s2++];
        }//将数值拷贝到arr数组里面
        for (int i = 0; i < count; i++) {
            arr[i + start] = tmp[i];
        }
    }

}

5.1:海量数据的排序问题

前提:内存只有1G,需要排序的数据右10G

因为内存中无法把所有的数据全部放下,所以需要外部排序,而归并排序是最常用的外部排序。

1.先把文件切成成10份,每份1G.

2.分别对每份排序,因为内存可以放的下,

3.进行2路归并,同时对200份有序的文件进行归并,最终有序

总结:

以上就是我总结的排序的知识点,如果有错误,请各位铁铁留言指教。

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

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

相关文章

微信小程序自动化测试之路

1. 前言 在每次发布新版本之前、都需要回归核心功能、已确保上线后小程序也能按照预期运行. 目前这部分回归工作是由测试同事手工去验证测试用例、按照每周一版本的迭代节奏、回归就花了测试挺多时间的. 最近前端工作比较轻松、故在思考能否把这部分重复的工作交给程序自动来进…

【EhCache: 一款Java的进程内缓存框架】EhCache 是什么、代码实战 Demo

文章目录1 EhCache 是什么2 代码实战 DemoTestEH.javaehcache.xml1 EhCache 是什么 Ehcache 是一种开源的、基于标准的缓存&#xff0c;可提高性能、卸载数据库并简化可扩展性。它是最广泛使用的基于 Java 的缓存&#xff0c;因为它健壮、经过验证、功能齐全&#xff0c;并且与…

python 基于PHP+MySQL的装修网站的设计与实现

至今为止,越来越多企业公司都已经实现了线上推广,提高了企业的运营工作效率,为装修公司设计一款强大的智能装修网,集企业信息展示和信息管理于一体,结合企业与外部的在线交流功能,主要用于大力宣传企业服务、企业产品等信息,让更多的人了解,提高企业的知名度 1&#xff1a;系统…

Spring Data Neo4j(1.对象映射)

文章目录一、Spring Data Neo4j二、注释NodeIdVersion(乐观锁)PropertyRelationship一、Spring Data Neo4j Spring Data Neo4j或简称SDN是下一代Spring Data模块&#xff0c;由Neo4j&#xff0c;Inc.创建和维护。与VMware的Spring Data Team密切合作。 它支持所有官方支持的Ne…

<Linux> shell运行原理及Linux权限的理解

文章目录一、shell 命令及其运行原理shell外壳shell运行原理二、Linux 权限的概念1.用户分类2.切换用户3.用户提权三、Linux 权限管理1.文件访问者的分类&#xff08;人&#xff09;2.文件类型和访问权限&#xff08;事物属性&#xff09;四、文件权限值的表示方法1.字符表示法…

Pycharm 配置远程SSH服务器环境(切换不同虚拟环境)

1.首先在Xshell上通过conda创建新的虚拟环境 2.此时在 /home/y210101004/.conda/envs下多了刚刚创建的环境的文件夹 3.路径说明&#xff01; &#xff08;注意&#xff01;&#xff09;该环境的编译器python3.6就在.../jiayan_test/bin里面 &#xff08;注意&#xff01;&…

04.函数

一、 函数 在计算机科学中&#xff0c;子程序&#xff08;英语&#xff1a;Subroutine, procedure, function, routine, method, subprogram, callable unit&#xff09;&#xff0c;是一个大型程序中的某部分代码&#xff0c; 由一个或多个语句块组 成。它负责完成某项特定任务…

ctfshow学习记录-misc入门(图片篇-颜色通道50-59)

目录misc50misc51misc52misc53misc54misc55misc56misc57misc58misc59misc51-52的wp和脚本参考的是csdn博主&#xff1a;z.volcano 九某人的碎碎念&#xff1a;这篇一更&#xff0c;说明近期是真的没有时间写wp了。虽说好多都是之前做过的题&#xff0c;但是wp整理起来还是比较耗…

OpenCV-Python 颜色识别(红色)并拟合矫正目标区域

OpenCV版本&#xff1a;4.6.0.66 算法实现思路&#xff1a; 颜色识别(红色)形态学去噪轮廓检测多边形拟合透视矫正代码实现&#xff1a; import cv2 import numpy as np# 可视化 def img_show(name, img):cv2.namedWindow(name, 0)cv2.resizeWindow(name, 1000, 500)cv2.imsh…

Java内存模型与volatile

Java内存模型 Java内存模型Java Memory Model&#xff0c;简称JMM&#xff0c;本身是一种抽象的概念并不真实存在它仅仅描述的是一组约定或规范&#xff0c;通过这组规范定义了程序中(尤其是多线程)各个变量的读写访问方式并决定一个线程对共享变量的写入何时以及如何变成对另…

白鹭群优化算法(ESOA)附matlab代码

✅作者简介&#xff1a;热爱科研的Matlab仿真开发者&#xff0c;修心和技术同步精进&#xff0c;matlab项目合作可私信。 &#x1f34e;个人主页&#xff1a;Matlab科研工作室 &#x1f34a;个人信条&#xff1a;格物致知。 更多Matlab仿真内容点击&#x1f447; 智能优化算法 …

单调区间能写成并吗?【基于间断区间的讨论】

不能。 问题 在做到一道题的时候&#xff0c;发现了两个减区间&#xff0c;于是就用并∪连接到一起了&#xff0c;但是答案是要用和连接。于是想要辨析一下这个并和和的区别。 区别 并&#xff1a;并的意思是将多个区间看成一个并起来的整体&#xff0c;在整个区间上仍然是…

按照 STAR 法则介绍自己做过的项目

大家好啊&#xff0c;我是大田 介绍项目注意两点&#xff1a;1、自己真的做过 2、逻辑表达能力 为什么推荐你用 STAR 法则说呢&#xff1f; STAR 法则是结构化面试中非常重要的理论。 面试官通过这样的描述全面了解你的测试知识、经验、技术能力的掌握程度&#xff0c;通过你发…

本地pycharm连接到远程服务器(超级详细)

本地pycharm连接到远程服务器&#xff08;超级详细&#xff09; 文章之前&#xff0c;你需要做的是 1.服务器需要创建好虚拟环境 2.你的本地安装好pycharm 目的是 同步服务器上的文件 在本地进行debug&#xff0c;并将修改后的文件进行更新 一般是将文件代码上传到服务器上面&…

【微服务】Sentinel 控制台

目录 1. 概述 2. 启动控制台 2.1 获取 Sentinel 控制台 2.2 启动 3. 客户端接入控制台 3.1 引入JAR包 3.2 配置启动参数 3.3 触发客户端初始化 4. 查看机器列表以及健康情况 5. 监控 5.1 "簇点链路"中显示刚刚调用的资源&#xff08;单机实时&#xff09; …

猿创征文|分享一下我的日常开发工具和常用软件

1、Eclipse IDE for Java Developers 这个软件&#xff0c;个人已经用了很多年的免费 Java 开发软件。 1&#xff09;配置JDK 2&#xff09;新建项目 3&#xff09;运行使用 这里注意到有 Run As 和 Debug As ,区别就是后者是调试模式&#xff0c;你可以在代码任意处打断点跟…

element-ui中获取el-divider的组件的ref时为空

element-ui中的el-divider组件是函数式组件,所以当我尝试获取其ref时总是获取不到,因为函数式组件没有this. ![在这里插入图片描述](https://img-blog.csdnimg.cn/496711bf5c2a4dd1bee168e4e2d638d4.png)此时打印this.$refs,控制台输出: 没有h2,翻看el-divider源码发现是函数式…

C++入门学习3-指针与字符数组,函数,指针数组

c入门学习3char型指针的使用p*p*p与p与[整型指针指向整型数组]的区别指针与函数的使用指向函数的指针空指针调用函数从函数中返回指针一维数组和二维数组的类比CHAR型指针数组关于&achar型指针的使用 char型指针可以直接指向一个字符串&#xff0c;如下 char s[]{a,b,c};…

YOLO V7源码解析

1.命令行参数介绍 YOLO v7参数与YOLO v5差不多&#xff0c;我就直接将YOLO v5命令行参数搬过来了&#xff0c;偷个懒 --weights:初始权重--cfg:模型配置文件--data:数据配置文件--hyp:学习率等超参数文件--epochs:迭代次数-imgsz&#xff1a;图像大小--rect&#xff1a;长方…

多目标蜉蝣优化算法(MOMA)附Matlab代码

✅作者简介&#xff1a;热爱科研的Matlab仿真开发者&#xff0c;修心和技术同步精进&#xff0c;matlab项目合作可私信。 &#x1f34e;个人主页&#xff1a;Matlab科研工作室 &#x1f34a;个人信条&#xff1a;格物致知。 更多Matlab仿真内容点击&#x1f447; 智能优化算法 …