时间复杂度为O(nlogn)的两种排序算法

news/2025/2/11 8:11:44/

1.归并排序

归并排序的核心思想:如果要排序一个数组,我们先把数组从中间分成前后两部分,然后对前后两部分分别排序,再将排好序的两部分合并在一起,这样整个数组就都有序了。
归并排序使用的就是分治思想。分治,顾名思义,就是分而治之,将一个大问题分解成小的子问题来解决。小的子问题解决了,大的问题也就解决了。

在这里插入图片描述

public class MergeSort {public static void main(String[] args) {int[] arr = new int[] {7,4,2,8,9,5};mergeSort(arr,0,arr.length-1);System.out.println(Arrays.toString(arr));}/*** 归并排序* 原地排序:否 * 稳定排序:是* 空间复杂度:O(n)* 时间复杂度:最好O(nlogn)——最坏O(nlogn)——平均O(nlogn)* @param arr 要排序数组* @param start 数组起始位* @param last 数组结束位* @return*/public static int[] mergeSort(int[] arr,int start,int last) {//也可以是(start+last)/2,这样写是为了防止数组长度很大造成两个相加大于int范围,导致溢出int mid = (last-start)/2+start;if(start<last) {mergeSort(arr,start,mid);//左数组排序mergeSort(arr,mid+1,last);//右数组排序merge(arr,start,mid,last);//合并两数组}return arr;}//合并数组public static int[] merge(int arr[],int start,int mid,int last) {int i=start;//左边数组下标int j=mid+1;//右边数组下标int[] tempArr = new int[last-start+1];//定义临时数组int k=0;while(i<=mid && j<=last) {if(arr[i]<arr[j]) {tempArr[k++] = arr[i++];}else {tempArr[k++] = arr[j++];}}while(i<=mid) {//将左边剩余元素移入到临时数组中tempArr[k++]=arr[i++];}while(j<=last) {//将右边剩余元素移入到临时数组中tempArr[k++]=arr[j++];}//把临时数组中的数据合并到新数组中for(int z=0;z<tempArr.length;z++) {arr[start+z] = tempArr[z];}return arr;}
}

2.快速排序

假设被排序的无序区间为[A[i],…,A[j]]

一、基准元素选取:选择其中的一个记录的关键字 v 作为基准元素(控制关键字);
二、划分:通过基准元素 v 把无序区间 A[I]…A[j] 划分为左右两部分,使得左边的各记录的关键字都小于 v;右边的各记录的关键字都大于等于 v;(如何划分?)
三、递归求解:重复上面的一、二步骤,分别对左边和右边两部分递归进行快速排序。
四、组合:左、右两部分均有序,那么整个序列都有序。上面的第 三、四步不用多说,主要是第一步怎么选取关键字,从而实现第二步的划分?

划分的过程涉及到三个关键字:“基准元素”、“左游标”、“右游标”

基准元素:它是将数组划分为两个子数组的过程中,用于界定大小的值,以它为判断标准,将小于它的数组元素“划分”到一个“小数值的数组”中,而将大于它的数组元素“划分”到一个“大数值的数组”中,这样,我们就将数组分割为两个子数组,而其中一个子数组的元素恒小于另一个子数组里的元素。

左游标:它一开始指向待分割数组最左侧的数组元素,在排序的过程中,它将向右移动。找大于基准值的数。

右游标:它一开始指向待分割数组最右侧的数组元素,在排序的过程中,它将向左移动。找小于基准值的数。

**注意:**上面描述的基准元素/右游标/左游标都是针对单趟排序过程的, 也就是说,在整体排序过程的多趟排序中,各趟排序取得的基准元素/右游标/左游标一般都是不同的。对于基准元素的选取,原则上是任意的。但是一般我们选取数组中第一个元素为基准元素(假设数组是随机分布的)

在这里插入图片描述

/*** 快速排序* 原地排序:是* 稳定排序:否* 空间复杂度:O(1)* 时间复杂度:最好O(nlogn)——最坏O(n^2)——平均O(nlogn)*/
public class QuickSort {public static void main(String[] args) {int[] arr = new int[] {6,1,2,7,9,3,4,5,10,8};reQuickSort(arr,0,arr.length-1);System.out.println(Arrays.toString(arr));}public static void swap(int[] arr,int i,int j) {int temp = arr[i];arr[i] = arr[j];arr[j] = temp;}public static void reQuickSort(int[] arr,int left,int right) {if(right<=left) {return;//终止递归}else {int partition = partitionIt(arr,left,right);reQuickSort(arr,left,partition-1);//基准元素左边元素进行排序reQuickSort(arr,partition+1,right);//基准元素右边元素进行排序}}public static int partitionIt(int[] arr,int left,int right) {//为什么 j加一个1,而i没有加1,是因为下面的循环判断是从‐‐j和++i开始的.//而基准元素选的array[left],即第一个元素,所以左游标从第二个元素开始比较int i=left;int j=right+1;int pivot = arr[left];// pivot 为选取的基准元素(头元素)while(true) {while(j>left&&arr[--j]>pivot) {}while(i<right&&arr[++i]<pivot) {}if(i>=j) {break;//左右游标相遇时候停止, 所以跳出外部while循环}else {swap(arr,i,j);//左右游标未相遇时停止, 交换各自所指元素,循环继续}}swap(arr,left,j);//基准元素和游标相遇时所指元素交换,为最后一次交换return j;//一趟排序完成, 返回基准元素位置(注意这里基准元素已经交换位置了)}
}

http://www.ppmy.cn/news/997632.html

相关文章

JavaScript 高阶函数

高阶函数是指能够接收一个或多个函数作为参数&#xff0c;或者返回一个函数作为结果的函数。在JavaScript中&#xff0c;函数可以被视为一种特殊的对象&#xff0c;因此可以作为参数传递给其他函数&#xff0c;也可以从函数中返回。 这种函数作为参数或返回值的特性&#xff0…

数据结构 | Radix Tree 树

什么是基数树&#xff1f; 基数树是一种多叉搜索树&#xff0c;数据位于叶子节点上&#xff0c;每一个节点有固定的2^n个子节点&#xff08;n为划分的基大小&#xff0c;当n为1时&#xff0c;为二叉树&#xff09;。 什么为划分的基&#xff1f; 以一个64位的长整型为例&#x…

JSON语法

目录 一、JSON 语法规则 二、JSON 的两种结构&#xff1a; 三、JSON 名称/值对 JSON 值 JSON 数字 JSON 对象 JSON 数组 JSON 布尔值 JSON null 四、JSON 使用 JavaScript 语法 JSON 语法是 JavaScript 语法的子集。 一、JSON 语法规则 JSON 语法是 JavaScript 对象…

7.24-7.30 周报

本周已完成&#xff1a; 1 矩阵分解&#xff08;原理及代码&#xff09; 2 学习深度学习知识 2.1 反向传播内容&#xff08;BP神经网络&#xff09; 2.2 用PyTorch实现线性回归 下周计划&#xff1a; 1 BP神经网络java代码&#xff08;Day 71-76&#xff09; 2 继续学习深…

我的4周年创作纪念日

机缘 今天是2023年8月1日&#xff0c;工作四年了&#xff0c;记录博客也四年了。 2019年&#xff0c;我硕士毕业入职到了这家公司&#xff0c;当时培训的资料有一句话说&#xff1a;网络通信100Mbps是串口通信的是串口通信的10倍&#xff0c;我当时就好奇是怎么算出来的&…

性能调试【学习笔记】

什么是调优&#xff1f; 每执行一个Java命令&#xff0c;就分配一个JVM&#xff0c;调优时不要混淆。 根据需求进行JVM规划和预调优优化运行JVM的运行环境&#xff08;慢、卡顿&#xff09;解决JVM运行过程中出现的各种问题&#xff08;内存泄露、内存溢出OOM&#xff09; 生…

[QT编程系列-36]:数据存储 - 配置数据的存储方式种类:QSettings 、QSQLite 、QJSON

目录 1. QT配置数据的管理和存储方式 1.1 概述 1.2 如何通知配置数据的变化 2. QSettings详解 1. QT配置数据的管理和存储方式 1.1 概述 在Qt中&#xff0c;你可以使用多种方式来保存和管理配置数据。 配置数据的用途&#xff1a; &#xff08;1&#xff09;应用程序重…

Java面向对象之四种访问权限修饰符

四种访问权限修饰符 Java提供的四种权限修饰符public、protected、(缺省)、private置于类的成员定义前&#xff0c;用来限定对象对该类成员的访问权限。Java提供的四种权限修饰符可以用来修饰类及类的内部结构&#xff1a;属性、方法、构造器、内部类。对于类的权限修饰符只可…