JAVA-数据结构-排序

news2024/10/12 21:47:02

1.直接插入排序

1.原理:和玩扑克牌一样,从左边第二个牌开始,选中这个,和前面的所有牌比较,插在合适的位置

public static void insertsort(int[] arr){//直接插入排序
        for (int i = 1; i < arr.length; i++) {//此循环用来从1开始确定牌的位置
            int j = i-1;//得到j前面一个元素
            int tmp = arr[i];//将i处元素取出来,用来作比较
            for (; j >=0 ; j--) {//此循环用来和i前面的比较,将i放在正确的位置
                if(arr[j] > tmp){
                    arr[j+1] = arr[j];//若i前面的比i大则将前面的值赋值给后面
                }else{
//                    arr[j+1] = tmp;
                    break;//比前面都要大,没有比较的必要
                }
            }
            arr[j+1] = tmp;//j走完上面循环为-1,上面走完一次循环j=0时为空,
        }
    }

直接插入排序特点

1. 元素集合越接近有序,直接插入排序算法的时间效率越高
2. 时间复杂度:O(N^2)
3. 空间复杂度:O(1),它是一种稳定的排序算法
4. 稳定性:稳定

2.希尔排序

希尔排序是直接插入排序的Promax版本,将直接插入排序分为n份,比较完n份,排序即成功

思想:先选定一个整数,把待排序文件中所有记录分成多个组,
所有距离为的记录分在同一组内,并对每一组内的记录进行排序。然后,取,重复上述分组和排序的工作。当到达
=1时,所有记录在统一组内排好序。

public static void shellSort(int[] array){//希尔排序是直接插入排序的优化
        int gap = array.length;
        while(gap > 0){//将每组距离最终干为1,即可成功
            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--) {
                if(array[j] > tmp){
                    array[j+gap] = array[j];
                }else{
                    array[j+gap] = tmp;
                    break;
                }
            }
            array[j+gap] = tmp;
        }
    }

3.选择排序

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

 public static void selsctSort1(int[] array){//选择排序基础版
        for (int i = 0; i < array.length; i++) {
            int minIndex = i;//每循环一次确定一个从左往右的最小值
            int j = i+1;
            for (; j <array.length; j++) {
                if(array[minIndex] > array[j]){
                    minIndex = j;//将minTndex和j的下标先进行交换,找到最小的和其交换
                }//从一次次循环中得出在[i,length)的最小值
            }
            swap(array,minIndex,i);
        }
    }

    public static void selsctSort(int[] array){//选择排序promax版
         int left = 0;
         int right = array.length-1;
         while (left < right){
             int minIndex = left;
             int maxIndex = left;//统一从没排序的起点开始
             for (int i = left+1; i < array.length; i++) {
                 if(array[maxIndex] < array[i]){
                     maxIndex = i;
                 }
                 if(array[minIndex] > array[i]){
                     minIndex = i;
                 }
             }
             swap(array,left,minIndex);
             swap(array,right,maxIndex);
             left++;
             right--;
         }
    }

    public static void swap(int[]array ,int minIndex,int j){
        int tmp = array[j];
        array[j] = array[minIndex];
        array[minIndex] = tmp;
    }
}

总结:
1. 直接选择排序思考非常好理解,但是效率不是很好。实际中很少使用
2. 时间复杂度:O(N^2)
3. 空间复杂度:O(1)
4. 稳定性:不稳定

4. 堆排序

 降序建大堆,升序建小堆

详情思路请看之前写的堆部分

https://mp.csdn.net/mp_blog/creation/editor/139502440

 /**
     * 堆排序
     * 时间复杂度:O(n*logN)
     * 空间复杂度:O(1)
     * 稳定性:不稳定
     * @param array
     */
    public static void heapSort(int[] array) {
        createHeap(array);
        int end = array.length-1;
        while (end > 0) {
            swap(array,0,end);
            siftDown(array,0,end);
            end--;
        }
    }

    private static void createHeap(int[] array) {
        for (int parent = (array.length-1-1)/2; parent >= 0; parent--) {
            siftDown(array,parent,array.length);
        }

    }

    /**
     *
     * @param array
     * @param parent 每棵子树调整的根节点
     * @param length 每棵子树调整的结束节点
     */
    private static void siftDown(int[] array, int parent, int length) {
        int child = 2 * parent + 1;
        while (child < length) {
            if(child + 1 < length && array[child] < array[child+1]) {
                child++;
            }
            if(array[child] > array[parent]) {
                swap(array, parent, child);
                parent = child;
                child = 2*parent+1;
            }else {
                break;
            }
        }
    }

6.快速排序

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

翻译过来实现过程就是取第一个数,分别在头和尾定义一个指针 ,头指针找比第一个数大的(需求就是把小的放在左边所以需要找大的和右边大的交换),尾指针找比第一个小的,两个都找到后,进行交换,确保左边的都是小于或等于第一个数的,右边都是大于或等于第一个数的,直到两个指针位置相等,然后再交换第一个与它们的位置,通过递归将它们分为一个个更小的然后即可完成

快速排序Hoare法实现过程

问题:为什么先从后面开始

如果先从前面开始则会造成最后汇合点大于key.

递归法

通过left和right的不断变化,直到left与right相遇为止,当不断分为很多的left和right后,

public class Sort {
    public static void swap(int[]array ,int minIndex,int j){
        int tmp = array[j];
        array[j] = array[minIndex];
        array[minIndex] = tmp;
    }
    public static void qsort(int[] array){
        int left = 0,right = array.length-1;
        parttrtions(array,left,right);
    }
    private static void parttrtions(int[]array,int left,int right){
        if(left>=right){
            return;
        }
        int start = parttrtion(array,left,right);
        parttrtions(array,left,start-1);
        parttrtions(array,start+1,right);
    }
    private static int parttrtion(int[] array,int left,int right){//Hoare版
        int privt = array[left];
        int end = right,start = left;
        while(start<end){
            while(start<end&& array[end] >= privt) {//从右往左直到找到比array[start](privt)小的放在
                end--;
            }

            while(start<end&&array[start] <= privt){//跳出小循环说明找到了比privt大的数
                start++;
            }
            swap(array,left,start);
        }
        return start;
    }
    private static int parttrtion1(int[] array,int left,int right){//挖坑法
        int privt = array[left];
        int end = right,start = left;
        while(start<end){
            while(start<end&& array[end] >= privt) {//从右往左直到找到比array[start](privt)小的放在
                end--;
            }
            array[start] = array[end];//将end下标的值来补充start的空缺
            while(start<end&&array[start] <= privt){//跳出小循环说明找到了比privt大的数
                start++;
            }
            array[end] = privt;//将start下标的值来补充end的空缺
        }
        return start;
    }
}

 快排的优化:

1.三数取中法:如果是单一的数则可能造成,单支树的产生,最高造成N(O*2),所以可以提前将中间的值给到start,这样能极大减少计算量

private static int getMiddleNum(int[] array,int left,int right) {
        int mid = (left+right)/2;
        if(array[left] < array[right]) {
            if(array[mid] < array[left]) {
                return left;
            }else if(array[mid] > array[right]) {
                return right;
            }else {
                return mid;
            }
        }else {
            if(array[mid] > array[left]) {
                return left;
            }else if(array[mid] < array[right]) {
                return right;
            }else {
                return mid;
            }
        }
    }

非递归法

 利用栈后进先出不断变化left和right的值

public static void qsort1(int[] array){
        int left = 0,right = array.length-1;
        int par = parttrtion(array,left,right);
        Stack<Integer> stack = new Stack<>();
        if(par>left+1){
            stack.push(left);
            stack.push(par-1);
        }
        if(par < right-1){
            stack.push(par+1);
            stack.push(right);
        }
        while(!stack.empty()){
            right = stack.pop();
            left = stack.pop();
            par = parttrtion(array,left,right);
            if(par>left+1){
                stack.push(left);
                stack.push(par-1);
            }
            if(par < right-1){
                stack.push(par+1);
                stack.push(right);
            }
        }

    }

总结: 

 1. 快速排序整体的综合性能和使用场景都是比较好的,所以才敢叫快速排序
2. 时间复杂度:O(N*logN)

3. 空间复杂度:O(logN)
4. 稳定性:不稳定

7.归并排序

思想:先将数组分成很多小份,然后再进行排序,然后把排序完的数组重新整和,最终得到一个有序数组。

递归法

1.首先将大数组分为小数组,把大问题拆分为小问题,1.找到最底层的两个数组,2.排序

 public void mergeSortTmp(int[]a,int left,int right){//将数组先分开再合并
        if(left>=right){
            return;
        }
        int mid = (left+right)/2;
        mergeSortTmp(a,left,mid);//分成很多份,找到最左边
        mergeSortTmp(a,mid+1,right);//上层递归完成,找到对应要排序的另一个数组
        merge(a,mid,left,right);//两个都找到后,进行排序操作
    }

2.然后利用两个数组组合排序的方法,定义两个指针,取到小的添加到新的数组

private void merge(int[]a,int mid,int left,int right){
        int [] array = new int[right-left+1];
        int set = 0;
        int s1 = left;
        int e1 = mid;
        int s2 = mid+1;
        int e2 = right;
        while(s1<e1&&s2<e2){
            if(a[s1] < a[s2]){
                array[set++] = a[s1++];
            }
            else {
                array[set++] = a[s2++];
            }
        }
        while (s1 <= mid) {
            array[set++] = array[s1++];
        }
        while (s2 <= right) {
            array[set++] = array[s2++];
        }
        for (int i = 0; i < array.length; i++) {
            a[i+left] = array[i];//分组后每一小组的下标并不是零
        }
    }

非递归法

思路:我们这个排序的核心就是1.一步步得到最小数组 2.一步步将两个小数组合并起来直到得到 大数组

所以可以在循环里嵌套循环,外面决定数组长度,里面循环将小数组排序合并,外循环设置每个小数组的相隔距离

 public void mergrSort1(int[] array){
        int left = 0,right = array.length-1;
        int gap = 1;//gap负责将数组分为array.length/2
        while(gap<array.length){
            for (int i = 0; i < array.length; i+=2*gap) {//得到小一号的数组并且进行排序合并,里面for循环是为了得到最多组数组
                left = i;
                int mid = left+gap-1;
                right = mid+gap;
                if(mid >= array.length) mid=array.length-1;
                if(right>=array.length) right = array.length-1;
                merge(array,mid,left,right);
            }
                gap *= 2;//世界线收束,每次小数组排序好后,再将更大数组排序
            }
        }
    }

总结:1. 归并的缺点在于需要O(N)的空间复杂度,归并排序的思考更多的是解决在磁盘中的外排序问题。
2. 时间复杂度:O(N*logN)
3. 空间复杂度:O(N)
4. 稳定性:稳定

8.计数排序

思路:将原数组遍历一遍,得到原数组的最大值和最小值,将最大值和最小值相减,得到它们的取值范围,创建一个新数组,然后将对应的值给到,和其相对相等的下标,(比如数组的值为1给到开辟数组的1下标,)然后遍历新数组,赋值给原数组

/**
     * 计数排序:
     * 时间复杂度:O(范围 + n )
     *       范围越大  越慢
     * 空间复杂度:O(范围)
     * 稳定性:
     * @param array
     */
    public static void countSort(int[] array) {
        //1. 找最大值 和 最小值 来确定 计数数组的大小
        int maxVal = array[0];
        int minVal = array[0];
        for (int i = 1; i < array.length; i++) {
            if(array[i] < minVal) {
                minVal = array[i];
            }
            if(array[i] > maxVal) {
                maxVal = array[i];
            }
        }
        int len = maxVal - minVal + 1;
        int[] count = new int[len];

        //2. 遍历原来的数组array把 每个元素 放到对应的计数数组当中 进行计数
        for (int i = 0; i < array.length; i++) {
            int index = array[i];
            count[index-minVal]++;
        }
        //3.依次 遍历计数数组 O(范围)
        int index = 0;
        for (int i = 0; i < count.length; i++) {
            while (count[i] != 0) {
                array[index] = i+minVal;
                index++;
                count[i]--;
            }
        }
    }

总结 

1. 计数排序在数据范围集中时,效率很高,但是适用范围及场景有限。
2. 时间复杂度:O(MAX(N,范围))
3. 空间复杂度:O(范围)
4. 稳定性:稳定

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

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

相关文章

SSD融合FERPlus模型实现面部情绪识别

关于深度实战社区 我们是一个深度学习领域的独立工作室。团队成员有&#xff1a;中科大硕士、纽约大学硕士、浙江大学硕士、华东理工博士等&#xff0c;曾在腾讯、百度、德勤等担任算法工程师/产品经理。全网20多万粉丝&#xff0c;拥有2篇国家级人工智能发明专利。 社区特色…

帝国竞争主义算法(ICA)的MATLAB代码复现

目录 1 帝国竞争主义算法优化BP神经网络代码复现 2 帝国竞争主义算法优化支持向量机代码复现 3 帝国竞争主义算法优化长短期记忆神经网络代码复现 1 帝国竞争主义算法优化BP神经网络代码复现 1&#xff09;单输出回归预测&#xff1a;单输出回归预测&#xff1a;帝国主义竞…

API接口并发请求控制实现

文章目录 一、问题概述二、解决思路1. AtomicInteger2. LongAdder3. Semaphore4. 实现区别三、API接口并发控制1. 核心源码2. 源码放送 一、问题概述 某API接口&#xff0c;承载某重要业务&#xff0c;希望控制任意时间点的并发访问数在5以内&#xff0c;该如何实现&#xff1…

数据结构-5.5.二叉树的存储结构

一.二叉树的顺序存储&#xff1a; a.完全二叉树&#xff1a; 1.顺序存储中利用了静态数组&#xff0c;空间大小有限&#xff1a; 2.基本操作&#xff1a; (i是结点编号) 1.上述图片中i所在的层次后面的公式应该把n换成i(图片里写错了)&#xff1b; 2.上述图片判断i是否有左…

ThingsBoard规则链节点:JSON Path节点详解

引言 JSON Path节点简介 用法 含义 应用场景 实际项目运用示例 智能农业监控系统 工业自动化生产线 车联网平台 结论 引言 ThingsBoard是一个功能强大的物联网平台&#xff0c;它提供了设备管理、数据收集与处理以及实时监控等核心功能。其规则引擎允许用户通过创建复…

Java-学生管理系统[初阶]

这次我们来尝试使用Java实现一下"学生管理系统"&#xff0c;顾名思义&#xff0c;就是实现一个能用来管理学生各种数据的系统。在后续学习中我们将对"学生管理系统"进行两种实现&#xff1a; &#x1f4da; 学生管理系统[初阶](不带模拟登录系统) &#…

衡石分析平台系统管理手册-智能运维之系统日志

系统日志​ 点击系统设置->系统日志 在这个页面&#xff0c;从时间&#xff0c;操作者, IP&#xff0c;行为&#xff0c;结果&#xff0c;类别&#xff0c;对象&#xff0c;描述等方面记录了用户行为&#xff0c;系统管理员可以从此页面针对整个系统的用户行为进行审计工作…

【C++】set/map 与 multiset/multimap

✨✨欢迎大家来到Celia的博客✨✨ &#x1f389;&#x1f389;创作不易&#xff0c;请点赞关注&#xff0c;多多支持哦&#x1f389;&#x1f389; 所属专栏&#xff1a;C 个人主页&#xff1a;Celias blog~ 目录 ​编辑 序列式容器和关联式容器 一、set 1.1 set介绍 1.2 …

大健康零售电商的智囊团:知识中台的应用与影响

在数字化浪潮席卷各行各业的今天&#xff0c;大健康零售电商行业也在积极探索转型升级的新路径。知识中台&#xff0c;作为一种集知识管理、数据挖掘与智能化应用于一体的新型技术架构&#xff0c;正逐渐成为推动这一转型的关键力量。本文将深入探讨知识中台在大健康零售电商中…

Light灯光组件+组件的相关操作+游戏资源的加载

Light灯光组件 Type: Directional:平行光&#xff0c;模仿的是太阳光 Spot:聚光灯 Area:区域光 Color&#xff1a; 颜色值 Mode: RealTime:实时 Mix:混合 Baked:烘焙 Intersity: 光照强度 Indirect Multiplier:光照强度乘数 Shadow Type:影子设置&#xff1a;…

CV方法再学习

轻量化模型 Mobile系列(V1~V3) MobileNetV1 MobileNetV1之所以轻量&#xff0c;与深度可分离卷积的关系密不可分 深度可分离卷积 主要是两种卷积变体组合使用&#xff0c;分别为逐通道卷积&#xff08;Depthwise Convolution&#xff09;和逐点卷积&#xff08;Pointwise C…

Nginx UI 一个可以管理Nginx的图形化界面工具

Nginx UI 是一个基于 Web 的图形界面管理工具&#xff0c;支持对 Nginx 的各项配置和状态进行直观的操作和监控。 Nginx UI 的功能非常丰富&#xff1a; 在线查看服务器 CPU、内存、系统负载、磁盘使用率等指标 在线 ChatGPT 助理 一键申请和自动续签 Let’s encrypt 证书 在…

八、Python基础语法(判断语句-下)

一、if elif else 结构 应用场景&#xff1a;多个判断条件下&#xff0c;并且这些判断条件存在一定的关联。 语法&#xff1a; elif也是python中关键字&#xff0c;后面跟一个判断条件&#xff0c;判断条件后面跟冒号 存在冒号&#xff0c;需要换行缩进&#xff0c;处于elif…

金九银十软件测试面试题(800道)

今年你的目标是拿下大厂offer&#xff1f;还是多少万年薪&#xff1f;其实这些都离不开日积月累的过程。 为此我特意整理出一份&#xff08;超详细笔记/面试题&#xff09;它几乎涵盖了所有的测试开发技术栈&#xff0c;非常珍贵&#xff0c;人手一份 肝完进大厂 妥妥的&#…

QD1-P5 HTML 段落标签(p)换行标签(br)

本节视频 www.bilibili.com/video/BV1n64y1U7oj?p5 ‍ 本节学习 HTML 标签&#xff1a; p标签 段落br标签 换行 ‍ 一、p 标签-段落 1.1 使用 p 标签划分段落 <p>段落文本</p>示例 <!DOCTYPE html> <html><head><meta charset"…

算法剖析:滑动窗口

文章目录 前言一、长度最小的子数组二、无重复字符的最长子串三、最大连续1的个数 III四、将 x 减到 0 的最小操作数五、水果成篮六、找到字符串中所有字母异位词七、串联所有单词的子串八、最小覆盖子串总结 前言 滑动窗口可以看作为一种特殊的通向双指针&#xff0c;这两个指…

轻松翻译:顶尖翻译器评测!

在工作生活中如果遇到翻译需求&#xff0c;就少不了一些好用的翻译器&#xff0c;接下来是我们就来为大家推荐几款市面上口碑极佳的翻译软件&#xff01; 福昕在线翻译 直达链接&#xff1a; fanyi.pdf365.cn/ 操作教程&#xff1a;立即获取 福昕在线翻译是一款基于云端技…

关于部分股市买卖的演示和总结

本文是对上一文的补充&#xff1a;一个普通人的投资认知-CSDN博客 一、简介 假设公司A 向某交易所发行100股股票&#xff0c;每股5元&#xff0c;预计将融资500元。 股民a买了10股&#xff0c;付出50元。 股民b买了20股&#xff0c;付出100元。 股民c买了30股&#xff0c;付出…

【3维视觉】超级好用的3D模型交互式可视化工具viser

项目地址 https://github.com/nerfstudio-project/viser 功能 SMPL模型可视化编辑 点云可视化 3DGS实时渲染播放 安装和使用 安装viser git clone https://github.com/nerfstudio-project/viser.git使用 官方说明文档 1. SMPL模型可视化编辑 先下载SMPLX人体模型 下载解…

290. 单词规律【哈希表】

文章目录 290. 单词规律解题思路Go代码 290. 单词规律 290. 单词规律 给定一种规律 pattern 和一个字符串 s &#xff0c;判断 s 是否遵循相同的规律。 这里的 遵循 指完全匹配&#xff0c;例如&#xff0c; pattern 里的每个字母和字符串 s 中的每个非空单词之间存在着双向…