Java 复习笔记 - 常见算法:排序算法

文章目录

  • 概述
  • 一,冒泡排序
    • (一)排序概述
    • (二)排序原理
    • (三)示例
  • 二,选择排序
    • (一)排序概述
    • (二)排序原理
    • (三)示例
  • 三,插入排序
    • (一)排序概述
    • (二)排序原理
    • (三)示例
  • 四,快速排序
    • (一)排序概述
    • (二)排序原理
    • (三)示例


概述

排序算法是一种计算机算法,用于将一组数据按照特定顺序进行排列。这种顺序可以是一个或多个关键字,以便更容易查找和比较。排序算法的分类主要包括内部排序和外部排序。

内部排序是指将需要处理的所有数据都加载到内部存储器中进行排序,而外部排序则是数据量过大,无法全部加载到内存中,需要借助外部存储进行排序。

常见的排序算法包括冒泡排序、快速排序、插入排序、选择排序、归并排序和堆排序等。这些算法可以按照特定的规则和算法思想将数据按照一定的顺序排列,以提高数据处理的效率和准确性。

对于Java中的排序算法,常用的有冒泡排序、选择排序、插入排序和快速排序等。冒泡排序是一种简单的排序算法,它通过重复地走访过要排序的数列,一次比较两个元素,如果顺序错误就把它们交换过来,直到所有元素均已排序完成。选择排序则是一种简单直观的排序算法,它的工作原理是在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。插入排序的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。快速排序则是通过一个基准元素将待排序列分为两部分,其中一部分的所有数据都比另一部分的所有数据要小,然后再按照此方法对这两部分数据分别进行快速排序,整个过程可以递归进行,以此达到整个数据变成有序序列。

这些算法可以通过不同的方式进行优化和改进,以提高其效率和性能。此外,在实际应用中,需要根据具体的数据特征和需求选择合适的排序算法。

一,冒泡排序

(一)排序概述

冒泡排序(Bubble Sort)是一种简单的排序算法,它通过重复地走访过要排序的元素列,一次比较两个相邻的元素,如果顺序错误就把它们交换过来,直到没有相邻元素需要交换,也就是说该元素列已经排序完成。这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到数列的顶端,如同碳酸饮料中二氧化碳的气泡最终会上浮到顶端一样。

冒泡排序的应用场景包括对基本数据结构的排序,例如数组和列表,以及在数据挖掘和信息检索等领域中的排序。它的主要特点是比较简单易懂,但是效率较低,尤其是对于大规模数据的排序。因此,在实际应用中,冒泡排序通常不是首选的排序算法。

(二)排序原理

冒泡排序的原理是通过重复地走访要排序的元素列,依次比较相邻的两个元素,如果它们的顺序错误,就交换它们的位置。这样,每一对相邻元素都会做同样的工作,从开始的第一对到结尾的最后一对,最后的元素应该会是最大的数。然后,对剩下的元素重复以上步骤,直到没有任何一个数字需要比较位置,排序结束。

具体来说,冒泡排序从数组的起始位置开始,比较相邻的两个元素,如果第一个比第二个大,就交换它们的位置。然后对每一对相邻元素做同样的工作,从开始的第一对到结尾的最后一对。这样,最后一个元素应该是最大的数。然后,对剩下的元素重复以上步骤,直到没有任何一个数字需要比较位置,排序结束。

冒泡排序的时间复杂度为O(n²),空间复杂度为O(1)。如果数组的初始状态是正序的,一趟扫描即可完成排序,所以冒泡排序最好的时间复杂度为O(n)。然而,冒泡排序的最坏时间复杂度为O(n²),总的平均时间复杂度也为O(n²)。由于冒泡排序是原址排序,所以空间复杂度为O(1)。

(三)示例

以下是一个简单的冒泡排序算法的Java实现:

public class BubbleSort {void bubbleSort(int arr[]) {int n = arr.length;for (int i = 0; i < n-1; i++) {for (int j = 0; j < n-i-1; j++) {if (arr[j] > arr[j+1]) {// swap arr[j+1] and arr[j]int temp = arr[j];arr[j] = arr[j+1];arr[j+1] = temp;}}}}/* 打印数组 */void printArray(int arr[]) {int n = arr.length;for (int i=0; i<n; ++i) {System.out.print(arr[i] + " ");}System.out.println();}// 测试public static void main(String args[]) {BubbleSort ob = new BubbleSort();int arr[] = {64, 34, 25, 12, 22, 11, 90};ob.bubbleSort(arr);System.out.println("Sorted array");ob.printArray(arr);}
}

这个Java程序首先定义了一个名为bubbleSort的方法来执行冒泡排序。然后,定义了一个名为printArray的方法来打印数组。在main方法中,创建了一个BubbleSort对象,定义了一个待排序的数组,然后调用bubbleSort方法对数组进行排序,最后调用printArray方法打印排序后的数组。

二,选择排序

(一)排序概述

选择排序是一种简单直观的排序算法,它的工作原理是每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,直到全部待排序的数据元素排完。选择排序的特点是简单直观、易于实现,不占用额外的内存空间,原地排序。

选择排序与冒泡排序非常相似,都是一层层筑顶的过程,不同点在于冒泡排序会频繁地互换位置,而选择排序只是记录最大元素的位置,并与顶互换,只需交换一次,所以选择排序与冒泡排序相比时间消耗会更少,更有效率,尽管它们最坏的时间复杂度都是O(n^2)。

选择排序的应用场景包括对小规模的数据集进行排序,因为其性能相对较好。然而,对于大规模的数据集,由于其效率较低,通常不会使用选择排序。此外,选择排序不是稳定的排序算法,即在一趟选择中,如果一个元素比当前元素小,而该小的元素又出现在一个和当前元素相等的元素后面,那么交换后稳定性就被破坏了。

(二)排序原理

选择排序的排序原理是每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,然后再从剩余的未排序元素中寻找到最小(大)元素,然后放到已排序的序列的末尾。以此类推,直到全部待排序的数据元素的个数为零。选择排序是通过不断选择剩余元素中的最小(大)元素并将其放在正确的位置上,从而达到排序的目的。它是不稳定的排序方法,即可能改变等值元素的相对位置。

(三)示例

以下是一个简单的选择排序算法的Java实现:

public class SelectionSort {void selectionSort(int arr[]) {int n = arr.length;for (int i = 0; i < n-1; i++) {// 找到最小元素的索引int min_idx = i;for (int j = i+1; j < n; j++) {if (arr[j] < arr[min_idx]) {min_idx = j;}}// 交换找到的最小元素和第一个元素int temp = arr[min_idx];arr[min_idx] = arr[i];arr[i] = temp;}}/* 打印数组 */void printArray(int arr[]) {int n = arr.length;for (int i=0; i<n; ++i) {System.out.print(arr[i] + " ");}System.out.println();}// 测试方法public static void main(String args[]) {SelectionSort ob = new SelectionSort();int arr[] = {64, 25, 12, 22, 11};ob.selectionSort(arr);System.out.println("Sorted array");ob.printArray(arr);}
}

在这个示例中,selectionSort方法通过循环遍历数组,每次循环找出当前未排序部分的最小值,并将其与未排序部分的第一个元素交换。这个过程一直持续到整个数组都被排序。然后,printArray方法用于打印排序后的数组。最后,main方法用于测试这个排序算法。

三,插入排序

(一)排序概述

插入排序是一种简单直观且稳定的排序算法,一般也被称为直接插入排序。它是对于少量元素的排序有效的算法。

插入排序的基本思想是将一个记录插入到已经排好序的有序表中,从而得到一个新的、记录数增加1的有序表。在实现过程中,使用双层循环,外层循环对除了第一个元素之外的所有元素,内层循环对当前元素前面有序表进行待插入位置查找,并进行移动。

插入排序在应用方面,适用于已经有部分数据已经排好,并且排好的部分越大越好。这种情况下,插入排序能充分利用已经排好序的数据,避免从头开始排序。然而,如果输入规模过大(例如超过1000个元素),插入排序的效率会降低。

插入排序的平均时间复杂度是O(n^2),空间复杂度为常数阶O(1)。具体时间复杂度和数组的有序性也有关联:当待排序数组是有序时,是最优的情况,只需当前数跟前一个数比较即可,此时一共需要比较N-1次,时间复杂度为O(N);而最坏的情况是待排序数组是逆序的,此时需要比较次数最多,最坏的情况是O(n^2)

(二)排序原理

插入排序的原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。在实现上,通常采用in-place排序(即只需用到O(1)的额外空间的排序),因而在从后向前扫描过程中,需要反复把已排序元素逐步向后挪位,为最新元素提供插入空间。一般来说,插入排序都采用in-place在数组上实现。对于未排序的元素,在已排序的元素序列中从后向前扫描,如果该元素大于新元素,将该元素移到下一位置;重复步骤3,直到找到已排序的元素小于或者等于新元素的位置;将新元素插入到该位置后;重复步骤2~5,以此类推。

(三)示例

以下是一个简单的Java实现插入排序的例子:

public class InsertionSort {/* 插入排序函数 */public void sort(int arr[]) {int n = arr.length;for (int i = 1; i < n; ++i) {int key = arr[i];  // 当前需要插入的元素int j = i - 1;  // 与已排序的元素进行比较的元素索引/* 将大于key的元素移动到它们的下一个位置 */while (j >= 0 && arr[j] > key) {arr[j + 1] = arr[j];  // 将元素向后移动一位j = j - 1;  // 继续与前面的元素进行比较}arr[j + 1] = key;  // 找到key的正确位置并插入}}/* 打印数组的函数 */public static void printArray(int arr[]) {int n = arr.length;for (int i = 0; i < n; ++i)System.out.print(arr[i] + " ");System.out.println();}// 主函数,用于测试排序算法public static void main(String args[]) {int arr[] = {12, 11, 13, 5, 6};  // 待排序的数组InsertionSort ob = new InsertionSort();  // 创建InsertionSort对象ob.sort(arr);  // 对数组进行排序printArray(arr);  // 打印排序后的数组}
}

在这个例子中,sort函数是插入排序的主要部分。这个函数会循环遍历数组中的每个元素。对于每个遍历到的元素,它都会将元素与前面已经排序好的部分进行比较,并找到合适的位置插入。主要的操作是将当前元素与其前面的元素进行比较,并将大于当前元素的元素向后移动一位,以便为当前元素腾出空间。这个过程会一直持续到数组的所有元素都被遍历并插入到正确的位置。

四,快速排序

(一)排序概述

快速排序是一种非常高效的排序算法,其实现基于“分而治之”的思想,通过一趟扫描将待排序序列分成两部分,一部分小于基准值,一部分大于等于基准值,然后再递归地对这两部分进行快速排序,直到整个序列有序。

快速排序的最好情况下的时间复杂度为O(N LogN),此时每次分割操作都能将序列大致平分,递归调用层数为LogN,每层需要的比较次数为N。然而,在最坏情况下,快速排序的时间复杂度为O(n^2),此时待排序序列已经有序或基本有序,每次分割操作只能切割出一个子序列,递归调用的层数为n,每层需要的比较次数为n。但是,通过随机选择基准值或使用三数取中法等优化方法,可以减少最坏情况发生的可能性,从而提高了快速排序的平均性能。

在实际应用中,快速排序被广泛使用,尤其是对于大量数据的情况,其通常比其他排序算法更快、更有效。同时,快速排序还具有较低的空间复杂度,只需用到常量级的额外空间,因此对于内存受限的应用场景来说,是一个很好的选择。但是,需要注意的是,快速排序在某些特殊情况下可能会出现性能下降的情况,例如待排序序列已经有序或基本有序时,因此在具体应用中需要根据数据的特点进行选择和优化。

(二)排序原理

快速排序的排序原理基于“分而治之”的思想,将大问题分解为小问题,将复杂的问题分解为简单的问题进行处理。在快速排序中,我们选择一个基准元素将待排序序列分成两部分,一部分比基准元素小,一部分大于等于基准元素。然后对这两部分分别进行快速排序,直到整个序列有序。

具体来说,快速排序的实现步骤如下:

  1. 选择基准元素:通常选择第一个元素或者最后一个元素作为基准元素。
  2. 划分序列:通过一趟扫描,将待排序序列按照基准元素的大小进行划分,小于基准元素的元素放在基准元素的左边,大于等于基准元素的元素放在基准元素的右边。
  3. 递归排序:对划分后的两部分分别进行快速排序,直到序列中的所有元素均有序为止。

在快速排序的实现过程中,为了提高算法的性能,还需要注意以下几点:

  1. 优化基准元素的选择:选择一个好的基准元素能够避免序列的划分不平衡,从而减少比较次数和移动次数。一种常见的做法是随机选择一个元素作为基准元素。
  2. 利用递归缓存:为了避免递归调用时的重复计算,可以使用递归缓存来存储已经计算过的结果,从而减少重复计算的时间。
  3. 优化比较和交换操作:在比较和交换元素的过程中,可以使用二分查找等技巧来减少比较次数和交换次数,从而提高算法性能。

总的来说,快速排序的原理是将问题分解为更小的子问题,通过递归求解子问题,最终得到整个问题的解。这种分而治之的思路使得快速排序在时间复杂度上达到了O(n log n),是一种非常高效的排序算法。

(三)示例

以下是一个快速排序的Java实现示例:

public class QuickSort {// 快速排序函数public static void quickSort(int[] arr, int left, int right) {if (left < right) {// 将数组划分为两部分int pivotIndex = partition(arr, left, right);// 递归地对左半部分进行排序quickSort(arr, left, pivotIndex - 1);// 递归地对右半部分进行排序quickSort(arr, pivotIndex + 1, right);}}// 划分函数,将数组划分为两部分,小于基准的元素放在左边,大于等于基准的元素放在右边private static int partition(int[] arr, int left, int right) {// 选取最后一个元素作为基准int pivot = arr[right];int i = left - 1;for (int j = left; j < right; j++) {// 如果当前元素小于基准,则将其与i+1位置的元素交换位置if (arr[j] < pivot) {i++;swap(arr, i, j);}}// 将基准元素放到i+1位置上swap(arr, i + 1, right);// 返回基准元素的位置return i + 1;}// 交换数组中两个元素的位置private static void swap(int[] arr, int i, int j) {int temp = arr[i];arr[i] = arr[j];arr[j] = temp;}// 测试函数,用于测试快速排序函数的正确性public static void main(String[] args) {int[] arr = {5, 2, 9, 1, 5, 6};quickSort(arr, 0, arr.length - 1);for (int i : arr) {System.out.print(i + " ");}}
}

在上面的代码中,我们定义了一个quickSort函数,用于实现快速排序算法。在函数中,我们首先选择数组的最后一个元素作为基准,然后使用partition函数将数组划分为两部分,小于基准的元素放在左边,大于等于基准的元素放在右边。接着,我们对左右两部分分别进行递归调用,直到整个数组有序为止。在partition函数中,我们使用swap函数来交换数组中两个元素的位置。最后,我们在main函数中测试了快速排序函数的正确性。

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

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

相关文章

微服务保护-隔离

个人名片&#xff1a; 博主&#xff1a;酒徒ᝰ. 个人简介&#xff1a;沉醉在酒中&#xff0c;借着一股酒劲&#xff0c;去拼搏一个未来。 本篇励志&#xff1a;三人行&#xff0c;必有我师焉。 本项目基于B站黑马程序员Java《SpringCloud微服务技术栈》&#xff0c;SpringCloud…

Linux学习第11天:字符设备驱动开发:一字一符总见情

本文是驱动开发的第一篇笔记。主要内容是字符设备驱动开发最基础的内容&#xff0c;主要包括字符设备的概念、开发步骤以及一个十分重要的概念&#xff1a;设备号。其思维导图能简单的显示本文的基本框架&#xff0c;如下&#xff1a; 一、字符设备 字符设备就是一个一个字节&a…

wifi密码破解

文章目录 前言一、破解原理二、配置环境三、运行测试四、资源自取 前言 本文基于 python 实现了破解 wifi 密码的功能&#xff0c;采用的破解方式是穷举法&#xff0c;效率相对来说很低&#xff0c;对于设置密码简单的路由器来说比较适用。 一、破解原理 程序主要采用 python…

上海交通大学生存手册

强烈建议去看看《上海交通大学生存手册》&#xff0c;内容可能有点长&#xff0c;但讲得很好&#xff0c;说出了大学教育的本质。如果几年前我能看到它&#xff0c;也许我的大学生活可能会不一样。 只是&#xff0c;没有如果。 那么我把这本手册推荐给正在上大学或者是将要上…

[字符串和内存函数]strcpy和strncpy的区别

CPlus中对strcpy的介绍 /* strcpy example */ #include <stdio.h> #include <string.h>int main () {char str1[]"Sample string";char str2[40];char str3[40];strcpy (str2,str1);strcpy (str3,"copy successful");printf ("str1: %s\n…

YOLO目标检测——棉花病虫害数据集+已标注txt格式标签下载分享

实际项目应用&#xff1a;目标检测棉花病虫害数据集的应用场景涵盖了棉花病虫害的识别与监测、研究与防治策略制定、农业智能决策支持以及农业教育和培训等领域。这些应用场景可以帮助农业从业者更好地管理棉花病虫害&#xff0c;提高棉花产量和质量&#xff0c;推动农业的可持…

Nginx和Tomcat负载均衡实现session共享

以前的项目使用Nginx作为反向代理实现了多个Tomcat的负载均衡&#xff0c;为了实现多个Tomcat之间的session共享&#xff0c;使用了开源的Memcached-Session-Manager框架。 此框架的优势&#xff1a; 1、支持Tomcat6和Tomcat7 2、操作粘性或不黏性Session 3、没有单点故障 4、T…

Java 时间范围

前端使用Element-ui 时间范围组件 后端注意在Vo里面时间设置String类型不要设置Date类型 XMl组件字段映射成功性

nbcio-boot移植到若依ruoyi-nbcio平台里一formdesigner部分(四)

到目前为止&#xff0c;虽然基础的formdesigner部分已经完成&#xff0c;但流程用formdesigner提交与审批过程中的显示还有问题。 1、后端部分 其中FormConf修改如下&#xff1a; package com.ruoyi.flowable.core;import lombok.Data;import java.util.List; import java.uti…

Android 修复在 Settings 首页,按键盘方向键逐个单选

Android 修复在 Settings 首页&#xff0c;按键盘方向键逐个单选 问题现象问题分析解决办法 问题现象 在 Settings 主界面&#xff0c;按键盘方向键上下会直接整个选中&#xff0c;无法单条选中变色&#xff0c;而在二级页面中按方向键上下是正常的。 没有遥控器可以通过 adb…

flink的几种常见的执行模式

背景 在运行flink时&#xff0c;我们经常会有几种不同的执行模式&#xff0c;比如在IDE中启动时&#xff0c;通过提交到YARN上&#xff0c;还有通过Kebernates启动时&#xff0c;本文就来记录一下这几种模式 flink的几种执行模式 flink嵌入式模式&#xff1a; 这是一种我们在…

GDAL库学习

GDAL库学习 GDAL是一个操作栅格数据和矢量数据的库&#xff0c;对图像而言&#xff0c;可以进行包括读取、写入、转换、处理各种操作。 文章目录 GDAL库学习RasterIO()函数1. 添加引用2. 读取图像3. 获取图像基本信息4. 保存输出图像5. 释放 RasterIO()函数 RasterIO(GDALRWF…

动态的中秋爱心演示送女友用python生成爱心软件文末附c++语言写法

用python生成爱心软件 用python生成动态爱心软件 目录 用python生成爱心软件 完整代码 代码解释 逐句解释 效果展示&#xff1a; 如何打包 c写法 完整代码 import turtledef draw_heart():love turtle.Turtle()love.getscreen().bgcolor("black")love.…

WebSocket vs SSE: 实时数据推送到前端的选择与实现(详细)

Websocket和Server-Sent Events 对比推送数据给前端及各自的实现 二者对比WebSocket&#xff1a;Server-Sent Events (SSE)&#xff1a;选择 WebSocket 还是 SSE&#xff1a; Websocket 实现使用原生 WebSocket API&#xff1a;使用 Netty 创建 WebSocket&#xff1a;总结和选择…

SVN 和 GIT 命令对比

参考 https://blog.csdn.net/justry_deng/article/details/82259470 # TortoiseSVN打分支、合并分支、切换分支 https://www.huliujia.com/blog/802a64152bbbe877c95c84ef2fdf3857a056b536/ # 版本控制&#xff1a;Git与Svn的命令对应关系 TortoiseSVN打分支、合并分支、切换…

达梦数据库修改最大连接数

达梦数据库修改最大连接数 推荐配置修改最大连接数INI参数管理 推荐配置 达梦数据库的最大连接数推荐配置与服务器内存有关。不应设置得过大&#xff0c;否则容易导致出现OOM。 对应关系大致如下&#xff1a; 服务器内存MAX_SESSIONS范围8G50~10016G100~20032G200~30064G300…

unity 实现双击物体让其隐藏,单击物体让其显示

unity 实现双击物体让其隐藏&#xff0c;单击物体让其显示 private float tapThreshold 0.25f; private float tapTimer 0.0f; private bool tap false; private void Update() { if (Input.GetMouseButtonDown(0)) { if (Time.time < this.tapTimer this.tapThreshold)…

【深度学习-注意力机制attention 在seq2seq中应用】

注意力机制 为什么需要注意力机制attention机制的架构总体设计一、attention本身实现评分函数 attention在网络模型的应用-Bahdanau 注意力加性注意力代码实现 为什么需要注意力机制 这是一个普通的seq2seq结构&#xff0c;用以实现机器对话&#xff0c;Encoder需要把一个输入的…

初识React.js

引言&#xff1a; React是一种流行的JavaScript库&#xff0c;用于构建用户界面。无论您是新手还是有一些前端开发经验&#xff0c;本文将带您了解React框架的学习过程&#xff0c;并通过具体的例子来帮助您更好地理解和应用React。 1. 背景起源&#xff1a; React是由Faceb…

Selenium+python怎么搭建自动化测试框架、执行自动化测试用例、生成自动化测试报告、发送测试报告邮件

本人在网上查找了很多做自动化的教程和实例&#xff0c;偶然的一个机会接触到了selenium&#xff0c;觉得非常好用。后来就在网上查阅各种selenium的教程&#xff0c;但是网上的东西真的是太多了&#xff0c;以至于很多东西参考完后无法系统的学习和应用。 以下整理的只是书中…