java数据结构之排序

news2024/9/24 23:26:13

前言:

排序在我们日常生活中随处可见,这里将介绍java数据结构里面常见的几种排序。

ps:

swap函数的实现:

public void swap(int[] arr, int i, int j) {
    int tmp = arr[i];
    arr[i] = arr[j];
    arr[j] = tmp;
}

1.直接插入排序

(1)分析:

(2)代码实现:

时间复杂度:最好情况:O(N)              最坏情况:O(N^{2})

空间复杂度:O(1)

稳定性:稳定

public void insertSort(int[] arr) {
    for(int i = 1; i < arr.length; i++) {
        int j = i - 1;
        int tmp = arr[i];
        while (j >= 0) {
            if(arr[j] > tmp) {
                swap(arr,j,j+1);
            }else {
                break;
            }
            j--;
        }
    }
}

2.希尔排序

希尔排序的初衷就是想要将数组的元素变得逐渐有序,在最后一次排序时能够加快速度。希尔排序内部也是采用直接插入排序。

(1)分析:

(2)代码实现:

时间复杂度:O(N^{_{1.3}})~O(N^{1.5}) ( 经研究表明 ) 

空间复杂度:O(1)

稳定性:不稳定

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

3.选择排序

(1)分析:

(2)代码实现:

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

空间复杂度:O(1)

稳定性:不稳定

public void selectSort(int[] arr) {
    for (int i = 0; i < arr.length; i++) {
        int minIndex = i;
        for (int j = i + 1; j < arr.length; j++) {
            if(arr[j] < arr[minIndex]) {
                minIndex = j;
            }
        }
        swap(arr,i,minIndex);
    }
}

(3)优化:

public void selectSortFastly(int[] arr) {
    int right = arr.length - 1;
    int left = 0;
    int minIndex = 0;
    int maxIndex = 0;
    while(left < right) {
        minIndex = left;
        maxIndex = left;
        for (int i = left + 1; i <= right; i++) {
            if(arr[i] < arr[minIndex]) {
                minIndex = i;
            }
            if(arr[i] > arr[maxIndex]) {
                maxIndex = i;
            }
        }
        //有一种情况需要注意,就是最大值就是第一个元素,
        //eg:91,2,5,3,6,4,7,9,按照下面方法会出错,在第一次交换中把最大值交换走了
        //swap(arr,left,minIndex);
        //swap(arr,right,maxIndex);
        swap(arr,right,maxIndex);
        swap(arr,left,minIndex);
        left++;
        right--;
    }
}

 4.堆排序

(1)分析:

(2)代码实现:

时间复杂度:O(N\log_{2}N)

空间复杂度:O(1)

稳定性:不稳定 

private void softDown(int[] arr,int parent,int size) {
    int child = parent * 2 + 1;
    while(child < size) {
        if(child + 1 < size && arr[child] < arr[child + 1]) {
            child++;
        }
        swap(arr,child,parent);
        parent = child;
        child = parent * 2 + 1;
    }
}
//创建大根堆
private void createMaxHeap(int[] arr) {
    for(int parent = (arr.length - 1 - 1) / 2; parent >= 0; parent--) {
        softDown(arr,parent,arr.length);
    }
}

public void heapSort(int[] arr) {
    createMaxHeap(arr);
    int size = arr.length;
    while(size > 0) {
        swap(arr,0,size - 1);
        softDown(arr,0,size - 1);
        size--;
    }
}

5.冒泡排序

(1)分析:

(2)代码实现:

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

空间复杂度:O(1)

稳定性:稳定

public void bubbleSort(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);
            }
        }
    }
}

(3)优化:

给定一个标志位,如果进行一次排序过后没有进行过交换就说明整个数组已经有序,直接跳出循环。

public void bubbleSort(int[] arr) {
        for (int i = 0; i < arr.length; i++) {
            boolean flag = false;
            for (int j = 0; j < arr.length - 1 - i; j++) {
                //从小到大排
                if(arr[j] > arr[j + 1]) {
                    swap(arr,j,j+1);
                    flag = true;
                }
            }
            if(!flag) {
                //代表此时已经有序
                break;
            }
        }
    }

6.快速排序

(1)分析:


 (2)代码实现:(递归实现)

时间复杂度:O(N\log_{2}N)  但是需要注意的是当一个数组是逆序的时候,此时来进行快排,会让时间复杂度达到O(N^{2})(单只树)

空间复杂度:O(\log_{2}N)

稳定性:不稳定

//挖坑法
private int partition(int[] arr,int left, int right) {
    int tmp = arr[left];
    while(left < right) {
        while(left < right && arr[right] >= tmp) {
            right--;
        }
        arr[left] = arr[right];
        while(left < right && arr[left] <= tmp) {
            left++;
        }
        arr[right] = arr[left];
    }
    arr[left] = tmp;
    return left;
}
private void quick(int[] arr,int left, int right) {
    if(left >= right) {
        return;
    }
    int midIndex = partition(arr,left,right);
    quick(arr,left,midIndex - 1);
    quick(arr,midIndex + 1,right);

}
public void quickSort(int[] arr) {
    quick(arr,0,arr.length - 1);
}

(3)优化:

我们可以使用三数取中法(在第一次partition后minIndex左右两端的元素个数是差不多相同的),和当在递归中数组的长度小于某个范围时直接用插入排序来两种方法来优化快排。

//挖坑法
private int partition(int[] arr,int left, int right) {
    int tmp = arr[left];
    while(left < right) {
        while(left < right && arr[right] >= tmp) {
            right--;
        }
        arr[left] = arr[right];
        while(left < right && arr[left] <= tmp) {
            left++;
        }
        arr[right] = arr[left];
    }
    arr[left] = tmp;
    return left;
}
private void quick(int[] arr,int left, int right) {
    if(left >= right) {
        return;
    }
    //优化2:
    if(right - left + 1 < 10) {
        //直接用插入排序
        insertSort(arr,left,right);
    }
    //优化1:三数取中法
    int mid = findMid(arr,left,right);
    swap(arr,mid,left);
    int midIndex = partition(arr,left,right);
    quick(arr,left,midIndex - 1);
    quick(arr,midIndex + 1,right);

}
//直接插入排序
private void insertSort(int[] arr, int left, int right) {
    for(int i = left + 1; i <= right; i++) {
        int j = i - 1;
        int tmp = arr[i];
        while(j >= 0) {
            if(arr[j] > tmp) {
                swap(arr,j+1,j);
            }else {
                break;
            }
            j--;
        }

    }
}
//三数取中法
private int findMid(int[] arr, int left,int right) {
    int midIndex = (right - left)/2;
    if(arr[left] > arr[right]) {
        if(arr[midIndex] < arr[right]) {
            return right;
        }else if(arr[midIndex] > arr[left]) {
            return left;
        }else {
            return midIndex;
        }
    }else {
        if(arr[midIndex] < arr[left]) {
            return left;
        }else if(arr[midIndex] > arr[right]) {
            return right;
        }else {
            return midIndex;
        }
    }
}
public void quickSort(int[] arr) {
    quick(arr,0,arr.length - 1);
}

(4)非递归实现:

在这里我们会用到栈,来实现:

代码实现:

public void quickSortNor(int[] arr) {
    Stack<Integer> stack = new Stack<>();
    int left = 0;
    int right = arr.length-1;
    int midIndex = partition(arr,left,right);
    stack.push(midIndex+1);
    stack.push(right);
    stack.push(left);
    stack.push(midIndex-1);
    while(!stack.empty()) {
        right = stack.pop();
        left = stack.pop();
        if(left >= right) {
            continue;
        }
        midIndex = partition(arr,left,right);
        stack.push(midIndex+1);
        stack.push(right);
        stack.push(left);
        stack.push(midIndex-1);
    }
}

7.归并排序

(1)分析:

(2)代码实现:(递归实现)

时间复杂度:O(N\log_{2}N) 

空间复杂度:O(N)   

稳定性:稳定 

public void mergeSort(int[] arr) {
    mergesort(arr,0, arr.length-1);
}
private void mergesort(int[] arr, int left, int right) {
    if(left >= right) {
        return;
    }
    int mid = (left + right - 1) / 2;
    mergesort(arr,left,mid);
    mergesort(arr,mid+1,right);

    //合并
    merge(arr,left,mid,right);
}
private void merge(int[] arr, int left, int mid, int right) {
    int s1 = left;
    int e1 = mid;
    int s2 = mid + 1;
    int e2 = right;
    int size = right - left + 1;
    int[] ret = new int[size];
    int k = 0;
    while(s1 <= e1 && s2 <= e2) {
        if(arr[s1] < arr[s2]) {
            ret[k++] = arr[s1++];
        }else {
            ret[k++] = arr[s2++];
        }
    }
    while(s1 <= e1) {
        ret[k++] = arr[s1++];
    }
    while(s2 <= e2) {
        ret[k++] = arr[s2++];
    }
    //注意:如果在进行4个元素进行合并的时候,前四个元素合并完成,
    //但是如果i不加left,就会覆盖刚才放的元素。
    for(int i = 0; i < ret.length; i++) {
        arr[i+left] = ret[i];
    }
}

(3)非递归实现:

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

8.计数排序(不需要比较的排序)

计数排序适用排序一定范围内的数据。

(1)分析:

(2)代码实现:

public void countSort(int[] arr) {
    int max = arr[0];
    int min = arr[0];
    for(int i = 0; i < arr.length; i++) {
        if(arr[i] < min) {
            min = arr[i];
        }
        if(arr[i] > max) {
            max = arr[i];
        }
    }
    int size = max - min + 1;
    int[] count = new int[size];
    for(int j = 0; j < arr.length; j++) {
        count[arr[j] - min]++;
    }
    int k = 0;
    for(int i = 0; i < size; i++) {
        while(count[i] != 0) {
            arr[k++] = i + min;
            count[i]--;
        }
    }
}

 

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

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

相关文章

如何使用内网穿透为本地部署的开源虚拟机平台Proxmox VE配置公网地址

文章目录 前言1. 局域网访问PVE2. 安装Cpolar 工具3. 创建PVE公网地址4. 远程访问PVE5. 设置固定域名6. 固定地址访问 前言 本文主要介绍如何在Windows环境安装内网穿透工具&#xff0c;实现公网环境远程访问本地局域网中的Proxmox VE平台WEB 管理界面。 Proxmox VE是一个完全…

什么是互联网?

什么是互联网&#xff1f;互联网是由什么组成的&#xff1f;我们身处一个怎样的网络环境&#xff1f;相信很多人其实都无法回答。互联网起始于1969年&#xff0c;至今已经发展为一个极其庞大的全球网络&#xff0c;没有人能够详细描述其全貌。 我觉得这是一个特别奇怪的现象&a…

Nestjs使用Redis的最佳实践

前几天在项目中有用到Redis JWT实现服务端对token的主动删除(退出登录功能)。故此介绍下如何在Nestjs中使用Redis&#xff0c;并做下总结。 知识准备 了解Redis - 网上很多简介。了解Nestjs如何使用jwt生成token - 可移步看下我之前的文章 效果展示 一、mac安装与使用 示…

生成式AI的双重路径:Chat与Agent的融合与竞争

文章目录 每日一句正能量前言整体介绍对话系统&#xff08;Chat&#xff09;自主代理&#xff08;Agent&#xff09;结论 技术对比技术差异优势与劣势技术挑战结论 未来展望发展趋势Chat与Agent的前景社会和经济影响结论 后记 每日一句正能量 在避风的港湾里&#xff0c;找不到…

若依ruoyi+AI项目二次开发

//------------------------- //定义口味名称和口味列表静态数据 const dishFlavorListSelectref([ {name:"辣度",value:["不辣","微辣","中辣","重辣"]}, {name:"忌口",value:["不要葱","不要…

ADG901解析

目录 一、特性二、增强产品特性三、应用四、一般描述五、极低功耗六、引脚描述七、尺寸参数八、电路连接一、特性 宽带开关:-3 dB 在 4.5 GHz吸收型开关高关断隔离度:在 1 GHz 时为 38 dB低插入损耗:在 1 GHz 时为 0.8 dB单一 1.65 V 至 2.75 V 电源CMOS/LVTTL 控制逻辑小巧…

AI无处不在,英特尔举办第十七届网络与边缘计算行业大会,推动边缘AI深度融合

AI正在成为全行业的技术热潮。CSDN 看到&#xff0c;AI正在引发计算、开发、交互三大范式的全面升级&#xff0c;技术开发或将迎来一次全新的科技变革周期。国际权威的分析机构数据也一致显示了AI的快速增长之势。据IDC数据&#xff0c;中国生成式AI的复合年增长率达到86.2%&am…

企业利用AI智能名片S2B2C商城小程序参与社区团购的风险与机遇分析

摘要 在新零售浪潮的推动下&#xff0c;社区团购以其独特的商业模式迅速崛起&#xff0c;成为连接消费者与供应商的重要桥梁。企业纷纷探索如何有效利用这一新兴渠道&#xff0c;以扩大市场份额、提升品牌影响力。AI智能名片S2B2C商城小程序的引入&#xff0c;为企业参与社区团…

Spring源码学习笔记之@Async源码

文章目录 一、简介二、异步任务Async的使用方法2.1、第一步、配置类上加EnableAsync注解2.2、第二步、自定义线程池2.2.1、方法一、不配置自定义线程池使用默认线程池2.2.2、方法二、使用AsyncConfigurer指定线程池2.2.3、方法三、使用自定义的线程池Excutor2.2.4、方法四、使用…

家长读本编辑部家长读本杂志家长读本杂志社2024年第6期目录

新型教育 如何为孩子上好一堂科学课? (1) 孙瑜 全面实施“关爱微心愿”活动——福建宁德:汇聚星光,点亮学生“微心愿” (4) 黄荣夏 如何将STEM教育融入初中数学教学活动 (6) 罗淑萍 小学语文“读思达”教学法的推进策略 (9) 王湘福《家长读本》投稿&#xff1a;cn…

PE文件(十二)导入表

导入表 导入表的引入 当一个PE文件&#xff08;如.dll/.exe等&#xff09;需要使用别的模块的函数&#xff0c;也叫做依赖某模块&#xff0c;就需要一个清单来记录使用的模块&#xff08;一般为.dll文件&#xff0c;为方便理解&#xff0c;以后我们将模块都认为是.dll文件&am…

重磅发布:OpenAI宣布推出AI驱动的搜索引擎SearchGPT,将与Google和Perplexity展开竞争|TodayAI

OpenAI宣布推出其备受期待的AI驱动搜索引擎SearchGPT。该搜索引擎能够实时访问互联网信息&#xff0c;并将作为原型在有限范围内发布&#xff0c;计划最终将其功能整合到ChatGPT中。 SearchGPT的功能特点 SearchGPT是一个具有实时互联网信息访问能力的AI驱动搜索引擎。它的界面…

GoFly快速开发框架基于Go语言和Vue3开发后台管理附件管理插件包

说明 为了给客户提供更好的交互体验&#xff0c;框架把附件管理独立打包成插件包&#xff0c;这样附件管理接可以做个不通需求的附件管理插件包来满足不同甲方客户需求。 目前附件插件包有2个&#xff1a;一个基础包、一个高级包 附件插件包功能 1.基础包 统一管理业务系统…

Python酷库之旅-第三方库Pandas(046)

目录 一、用法精讲 161、pandas.Series.cumsum方法 161-1、语法 161-2、参数 161-3、功能 161-4、返回值 161-5、说明 161-6、用法 161-6-1、数据准备 161-6-2、代码示例 161-6-3、结果输出 162、pandas.Series.describe方法 162-1、语法 162-2、参数 162-3、功…

深入解析:inode、软硬链接与动静态库的奥秘

目录 一.inode1.inode的介绍2.文件系统与inode3.“目录”再理解 二.软硬链接1.硬链接2.软连接 三.动静态库1.静态库2.动态库3.动态库的加载过程 一.inode 1.inode的介绍 在Linux操作系统中&#xff0c;‘inode(索引节点)是文件系统的核心组件之一&#xff0c;用于管理文件和目…

从零开学C++:模板初阶

引言&#xff1a;在C语言当中&#xff0c;如果我们想要实现一个能计算整数和浮点数的计算器时&#xff0c;我们都需要根据不同的返回类型和参数类型创建许多个形式极其相似的函数&#xff0c;非常的麻烦&#xff0c;而在C中&#xff0c;我们将会引入模版的知识概念&#xff0c;…

模型优化—输入特征归一化处理

一、normalization 归一化&#xff08;规范化&#xff09;是对输入数据进行处理&#xff0c;使其满足某种规范。 前提&#xff1a;线性变换&#xff0c;不会改变原始数据的数值顺序。 假设原值分布在第一象限的某区间&#xff0c;并且x轴间距较广&#xff08;离散&#xff0…

QT动态添加布局以及删除布局

具体代码示例如下 &#xff1a; QHBoxLayout* hLayout new QHBoxLayout;hLayout->addWidget(new QLabel("444"));hLayout->addWidget(new QLineEdit("444"));hLayout->addWidget(new QPushButton("444"));layout->addLayout(hLayou…

Axure Web端元件库:从Quick UI到500+组件的飞跃

在快速变化的数字世界中&#xff0c;产品设计不仅仅是功能的堆砌&#xff0c;更是用户体验的精心雕琢。原型设计作为产品开发过程中的关键环节&#xff0c;其重要性不言而喻。Axure&#xff0c;作为业界领先的原型设计工具&#xff0c;凭借其强大的交互设计和丰富的功能&#x…

Masked Autoencoders for Point CloudSelf-supervised Learning

关于SSL中的MAE方法。 摘要 文章介绍了一种新的技术&#xff0c;叫做MAE&#xff0c;在帮助计算机自己学习理解语言和图片方面做得非常好。受到这个技术的启发&#xff0c;它用在了点云上。点云是一堆代表三维空间中某些点的数据&#xff0c;这种数据有时候会有点难处理&…