排序算法超详细代码和知识点整理(java版)

排序

1、冒泡排序

​ 两层循环,相邻两个进行比较,大的推到后面去,一共比较“数组长度”轮,每一轮都是从第一个元素开始比较,每一轮比较都会将一个元素固定到数组最后的一个位置。【其实就是不停的把元素往后堆,数组剩余长度越来越少,直到堆到最后一个,数组都堆好排好序了】

if (arr == null || arr.length < 2) 
    return;
for (int e = arr.length - 1; e > 0; e--) {
    for (int i = 0; i < e; i++) {
        if (arr[i] > arr[i + 1]) {
            swap(arr, i, i + 1); } } }

2、选择排序

​ 也是比较**“数组长度-1”轮,但是每一轮中是将一个最值元素放在开头**,然后从这个更新过元素的位置往后继续开始此轮的选择最值过程【其实就是不停的从选择最小元素,然后往前堆,和冒泡正好相反,然后前面剩余空间越来越少,直到前面都堆好了排好序了

if (arr == null || arr.length < 2) 
    return;
for(int i=0; i<arr.length - 1; i++){
    int minIndex = i;
    for(int j=i+1; j<arr.length; j++){
        minIndex = arr[j] < arr[minIndex] ? j : minIndex;
    } 
    swap(arr,i,minIndex);
}

3、插入排序

​ 重点看当前索引指向的元素大小,去对比比当前索引小,也就是前面排好序的那一部分元素。找到合适的位置,然后插进去。这对比的次数明显变少,只用和【索引-1】前面的数进行比较。

if (arr == null || arr.length < 2) 
    return;
for(int i = 1; i<arr.length; i++)
    for(int j = i-1; arr[j+1]<arr[j] && j >= 0; j--)
        swap(arr,j,j+1);

4、快速排序

​ 本质是找个基准值,一般可以选取这段数组中的最后一个元素。然后将小于这个基准值的放在其左侧,大于的放在其右侧.

​ 在遍历数组时,一般采用三指针法来实现。具体来说,我们使用一个左指针指向数组的左边界,用一个右指针指向数组的右边界。另外一个指针指向元素,用来遍历。

  • 如果当前查找的索引值对应数据 arr [i] 小于基准值,那么这个值和左边界【左指针】的下一个进行交换,同时左指针右移;

  • 如果大于基准值,就将其和右边界的前一个元素交换,同时左边界指针不动。索引 i 也不动,但是右指针左移

  • 如果等于基准值,索引 i ++

在这里插入图片描述

public static void quickSort(int[] arr){
    if(arr == null || arr.length < 2)
        return;
    quickSort(arr,0,arr.length-1);
}

public static void quickSort(int[] arr, int l, int r){
    if(l < r){
        int[] p = partition(arr,l,r);  //作用就是将最后一个元素当作基准值,然后将大于基准值得放右边,小于的放左边
        					//同时,返回一个基准信息,p[0]就是基准值中最左的一个【考虑到可能标志值会重复】,p[1]是最右侧
        quickSort(arr, l, p[0] - 1);
        quickSort(arr, p[1] + 1, r);
    }
}

public static void partiton(int[] arr, int l, int r){ //l是左边界,
	int pivot = arr[r];
    int left = l -1;
    int right = r;
    while(l < right){            //arr[l],就用来记录逐步遍历数组中的元素
        if(arr[l] < pivot)
            swap(arr, ++left, l++); // 将小于等于pivot的元素交换到左边界的右侧
        else if(arr[l] > pivot){
            swap(arr, --right, l); // 将大小于等于pivot的元素交换到右边界的左侧
        }
        else
            l++;
    }
    swap(arr, more, r); //最后将基准值转移到右指针位置
	return new int[] { less + 1, more };
}

5、归并排序

​ 将数组按照中间的位置,划分成左右两部分,然后对这两部分进行扫描归并。准备两个指针,分别指向左部分的开头,以及有部分的开头。然后比较大小,按照比较结果,将结果放进一个临时开辟的数组中,最后将这个临时数组的元素再塞回去。

public static void mergeSort(int[] arr){
	if(arr == null || arr.length < 2)
        return;
    mergeSort(arr,0,arr.length-1);
}

public static void mergeSort(int[] arr, int l, int r){
	if(l < r){
        int mid = l + ((r-l)>>1;
        mergeSort(arr, l, mid+1);
        mergeSort(arr, mid+1, r);     
        merge(arr,l,mid,r);
    }
}

public static void merge(int[] arr, int l, int mid, int r) {
 	int[] help = new int[r - l + 1];
    int i = 0;
    int p1 = l;
    int p2 = mid + 1;
    while(p1 <= mid && p2 <= r){
        help[i++] = arr[p1] < arr[p2] ? arr[p1++] : arr[p2++];
    }
    while (p1 <= m) {
        help[i++] = arr[p1++];
    }
    while (p2 <= r) {
        help[i++] = arr[p2++];
    }
    for (i = 0; i < help.length; i++) {
        arr[l + i] = help[i];
    }
}

6、堆排序

主要涉及两步骤:

1、构建堆【heapInsert】,2、输出堆顶元素,然后调整堆结构,以便于下一轮继续输出堆顶元素【heapify】

构建堆的过程就是不停的往上,也就是和自己的父节点、祖父节点…一直比较下去,如果想要大根堆,那就是只要大于父节点,那就和父节点交换,我们对数组的每一个元素都去单独构建一边。

调整堆,就是不停的往下。将堆顶元素和数组最后元素交换,由于当前数组经过构建堆过程后,已经是堆结构了。所以我们的堆顶元素肯定就是一个最值,交换过后,再重新调整堆即可。就是找到堆顶的孩子节点中最大的值,进行比较交换,一直比较到树的最后一层

public static void heapSort(int[] arr) {   //这个是主函数,参数中的arr数组中存放的就是待排元素
    if (arr == null || arr.length < 2) {
        return;
    }
    for (int i = 0; i < arr.length; i++) { //这个函数是用于创建大根堆,为了之后输出堆顶元素就是最大值
        heapInsert(arr, i);
    }
    int size = arr.length;    			  
    swap(arr, 0, --size);	//这一步是为了将堆顶元素和最后一个元素互换位置,注意最后要自减 也就是说最后应该数组中元素是从小到大排序的(如果一开始是一个大根堆)
    while (size > 0) {
        heapify(arr, 0, size);
        swap(arr, 0, --size); //同上面道理
    }
}
public static void heapInsert(int[] arr, int index) {   //这个函数比较好理解,就是一个循环,只要在创建堆结构过程中,新加入堆中的子节点比父节点元素大,就交换,最后形成的是大根堆
    while (arr[index] > arr[(index - 1) / 2]) {
        swap(arr, index, (index - 1) /2);
        index = (index - 1)/2 ;           //这一步别忘记了,一直是往下走的,index这个表示父节点位置的标记变量也要向下走
    }
}
public static void heapify(int[] arr, int index, int size) {//这次函数中参数中要借助 堆的大小size(对应上面主函数中的每次输出一次堆顶元素后,大小减1)
    int left = index * 2 + 1;
    while (left < size) {
        int largest = left + 1 < size && arr[left + 1] > arr[left] ? left + 1 : left;
        //上面这一步是为了找到左右子节点,哪个最大,然后记录最大的那个下标
        largest = arr[largest] > arr[index] ? largest : index;
        if (largest == index) {
            break;
        }
        swap(arr, largest, index);
        index = largest;
        left = index * 2 + 1;
    }
}
public static void swap(int[] arr, int i, int j) {       //就是一个交换函数,C++中直接用swap函数即可
    int tmp = arr[i];  arr[i] = arr[j];  arr[j] = tmp; }

7、优先级队列

默认是小根堆

//小根堆。默认
PriorityQueue<Integer> heap = new PriorityQueue<>();
  • 在左神算法讲解时举了一个例子,就是;

    堆排序扩展题目:
    已知一个几乎有序的数组,几乎有序是指,如果把数组排好顺序的话,每个元素移动的距离可以不超过k,并且k相对于数组来说比较小。请选择一个合适的排序算法针对这个数据进行排序。
    

    这时候就需要借助 堆结构 一开始先将前k个数存放入此优先级队列,也就是堆结构,然后将堆顶元素返回,也就是用pop返回

    这k个元素构成一个堆结构,找到这个堆中的小根堆的堆顶元素,就是当前最小的

    因为每个元素移动的距离不超过k,所以可以理解为这前k个数中最小的一个属肯也是整体数据中最小的一个数字,把第k+1个数放进去,再次形成小根堆,那返回的堆顶元素就是第二小的元素

    然后再重新从数组中取下一个元素,添加到堆中,自动就排好序形成相应的大根堆或者是小根堆

  • 下面我用左神算法中的java 代码来展示,其中关键的地方都加了注释了:

public void sortedArrDistanceLessK(int[] arr, int k) {
    PriorityQueue<Integer> heap = new PriorityQueue<>();  //java中的优先级队列的定义方式
    int index = 0;
    for (; index < Math.min(arr.length, k); index++) {
        //万一k超出范围了,就选取数组长度当作边界值,min()的作用就是这个
        heap.add(arr[index]);
    }
    int i = 0;
    for (; index < arr.length; i++, index++) {
        heap.add(arr[index]);  //上面那个for循环实际上没有取到第k个元素,所以先取
        arr[i] = heap.poll();  //然后再弹出堆顶元素
    }
    while (!heap.isEmpty()) {//数组最后一个元素也都加进堆结构后,剩下的就是将堆中的所有元素放依次弹出了
        arr[i++] = heap.poll();
    }
}

8、复杂度

  • 冒泡:时间复杂度o(n^2) 空间复杂度O(1)(原地排序,不需要额外空间)
  • 选择:时间复杂度o(n^2) 空间复杂度O(1)(原地排序,不需要额外空间)
  • 插入:时间复杂度o(n^2) 空间复杂度O(1)(原地排序,不需要额外空间)
  • 快速:时间复杂度o(nlogN) 空间复杂度平均情况下是O(log n),最坏情况下是O(n)。
  • 归并:时间复杂度o(nlogN) 空间复杂度O(n)(需要额外的空间来合并子数组)
  • :时间复杂度o(nlogN) 空间复杂度O(1)(原地排序)

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

LLaMA-Factory参数的解答

打开LLaMA-Factory的web页面会有一堆参数 &#xff0c;但不知道怎么选&#xff0c;选哪个&#xff0c;这个文章详细解读一下&#xff0c;每个参数到底是什么含义这是个人写的参数解读&#xff0c;我并非该领域的人如果那个大佬看到有参数不对请反馈一下&#xff0c;或者有补充的…

我于窗中窥月光,恰如仰头见“链表”(Java篇)

本篇会加入个人的所谓‘鱼式疯言’ ❤️❤️❤️鱼式疯言:❤️❤️❤️此疯言非彼疯言 而是理解过并总结出来通俗易懂的大白话, 小编会尽可能的在每个概念后插入鱼式疯言,帮助大家理解的. &#x1f92d;&#x1f92d;&#x1f92d;可能说的不是那么严谨.但小编初心是能让更多人…

时序预测 | Matlab实现GWO-BP灰狼算法优化BP神经网络时间序列预测

时序预测 | Matlab实现GWO-BP灰狼算法优化BP神经网络时间序列预测 目录 时序预测 | Matlab实现GWO-BP灰狼算法优化BP神经网络时间序列预测预测效果基本介绍程序设计参考资料 预测效果 基本介绍 1.Matlab实现GWO-BP灰狼算法优化BP神经网络时间序列预测&#xff08;完整源码和数据…

算法学习——LeetCode力扣动态规划篇6

算法学习——LeetCode力扣动态规划篇6 121. 买卖股票的最佳时机 121. 买卖股票的最佳时机 - 力扣&#xff08;LeetCode&#xff09; 描述 给定一个数组 prices &#xff0c;它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。 你只能选择 某一天 买入这只股票&…

三元组数据模型:构建知识图谱的基石

目录 前言1. 三元组数据模型概述1.1 定义与结构1.2 特点 2. 三元组在知识图谱中的应用2.1 知识表示2.2 知识推理2.3 数据整合 3 三元组的数据格式3.1 N-Triples &#xff1a;3.2 RDF/XML &#xff1a;3.3 Turtle &#xff08;又称为 Terse RDF Triple Language&#xff09;&…

编程语言|C语言——数组与指针

一、数组 同一类型的变量——元素&#xff08;element&#xff09;集中在一起&#xff0c;在内存上排列成一条直线&#xff0c;这就是数组&#xff08;array&#xff09;。 1.1 一维数组 一维数组的声明 int arr1[10]; int arr2[2 8];#define N 10 int arr3[N];int count 10;…

JavaScript的学习笔记

<script src"index.js" defer></script>&#xff0c;defer的作用是延迟加载index.js文件 定义变量 变量的类型分为两大类&#xff1a;基本类型和复合类型 JavaScript是一种弱类型语言&#xff0c;所以没有强类型语言所具有的int,float,char等等&#x…

无药可医还能怎么办?越没本事的人,越喜欢从别人身上找原因!——早读(逆天打工人爬取热门微信文章解读)

无药可医的病该怎么办呢&#xff1f; 引言Python 代码第一篇 洞见 《骆驼祥子》&#xff1a;越没本事的人&#xff0c;越喜欢从别人身上找原因第二篇 人民日报 来啦 新闻早班车要闻社会政策 结尾 “吾日三省吾身&#xff0c;而后深知自助者天助之。” 在人生的迷宫中 遭遇困境时…

域环境共享文件夹,容量配额管理

首先&#xff0c;我们先创建一个新的磁盘&#xff0c;必须在服务器关机的状态下创建&#xff0c;只有在关机状态下才能创建NVMe类型的磁盘。 打开此电脑&#xff0c;右击创建的磁盘&#xff0c;点击属性。 点击共享&#xff0c;点击高级共享。 将共享此文件夹勾选上&#xff0c…

蓝桥杯 第2945题 课程抢购 C++ Java Python

目录 题目 思路和解题方法 c 代码 Java 版本&#xff08;仅供参考&#xff09; Python 版本&#xff08;仅供参考&#xff09; 代码细节&#xff1a; C 代码细节解释: Python 代码细节解释: lenyan算法笔记 语雀 《lenyan算法笔记》 个人笔记日常更新。含金量不高。/…

ZNC3罗德与施瓦茨ZNC3网络分析仪

181/2461/8938产品概述&#xff1a; 罗德与施瓦茨 ZNC3 网络分析仪的工作频率范围为 9 kHz 至 3 GHz&#xff0c;面向移动无线电和电子产品行业的应用。它具有双向测试装置&#xff0c;用于测量有源和无源 DUT 的所有四个 S 参数。此外&#xff0c;它还提供适合开发和生产中各…

2023年第十四届蓝桥杯大赛软件类省赛C/C++研究生组真题(代码完整题解)

C题-翻转⭐ 标签:贪心 简述:如果 S 中存在子串 101 或者 010,就可以将其分别变为 111 和 000,操作可以无限重复。最少翻转多少次可以把 S 变成和 T 一样。 链接: 翻转 思路:要求步骤最少->S每个位置最多修改一次->从头开始遍历不匹配就翻转->翻转不了就-1 …

esp32中vscode的开发环境

vscode中安装esp32开发环境请参考&#xff1a;CSDN 1、调出esp32的控制面板View ->Command Paletter&#xff0c;或者快捷键&#xff08;ctrshitp&#xff09; 调出esp-idf的样例工程 选择ESP-IDF所在的安装路径 选择一个样例工程&#xff0c;作为工程模板 创建的新工程如…

基于springboot实现课程作业管理系统项目【项目源码+论文说明】

基于springboot实现课程作业管理系统演示 摘要 随着科学技术的飞速发展&#xff0c;社会的方方面面、各行各业都在努力与现代的先进技术接轨&#xff0c;通过科技手段来提高自身的优势&#xff0c;课程作业管理系统当然也不能排除在外。课程作业管理系统是以实际运用为开发背景…

swift中的autoreleasepool(自动释放池)有用么?

想到一个问题 swift中的autoreleasepool(自动释放池)有用么? 我们进行验证一下 首先我们写一个加载图片的方法,保证会真正用到真实的IMP内存func loadBigData(string: String?) {if let path Bundle.main.path(forResource: "big", ofType: "png") {for…

[数据库]windows环境安装mysql数据库服务

mysql介绍 MySQL是一个流行的关系型数据库管理系统&#xff08;RDBMS&#xff09;&#xff0c;它是由瑞典的MySQL AB公司开发&#xff0c;后来被Sun Microsystems收购&#xff0c;再后来Sun被Oracle收购。MySQL以其稳定性、可靠性、高性能和开放源代码的特性而闻名&#xff0c…

完整部署一套k8s-v.1.28.0版本的集群

一、系统情况 虚拟机版本&#xff1a;esxi 6.7 系统版本&#xff1a;centos7.9_2009_x86 配置&#xff1a;4核8G&#xff08;官网最低要求2核2G&#xff09; 192.168.0.137 master节点 192.168.0.139 node2节点 192.168.0.138 node1节点&#xff08;节点扩容练习&#xf…

剑指Offer题目笔记21(计数排序)

面试题74&#xff1a; 问题&#xff1a; ​ 输入一个区间的集合&#xff0c;将重叠的区间合并。 解决方案&#xff1a; ​ 先将所有区间按照起始位置排序&#xff0c;然后比较相邻两个区间的结束位置就能知道它们是否重叠。如果它们重叠就将它们合并&#xff0c;然后判断合并…

C++ namespace 使用梳理

前言 发现 namespace 这个小细节在工作项目中处理的有一点点小混乱&#xff0c;于是稍微梳理了一下关于 C namespace 使用相关的使用内容&#xff0c;为日后项目的重构做准备&#xff0c;虽然是很小的点&#xff0c;但是也是值得注意的&#xff0c;毕竟代码的质量体现在每一个…

Java项目实战笔记--基于SpringBoot3.0开发仿12306高并发售票系统--(二)项目实现-第五篇-核心功能车票预定开发及nacos集成

本文参考自 Springboot3微服务实战12306高性能售票系统 - 慕课网 (imooc.com) 本文是仿12306项目实战第&#xff08;二&#xff09;章——项目实现 的第五篇&#xff0c;本篇讲解该项目的核心功能——余票查询、车票预定功能的基础版开发&#xff0c;以及讲解项目与Nacos的集成…