排序算法汇总

一、二分查找

public static int binarySearch(int[] nums,int target){int l = 0, r = nums.length-1;while(l <= r){int mid = l + (r-l)/2;if(nums[mid] == target){return mid;}else if(nums[mid] < target){r = mid - 1;}else{l = mid + 1;}}return -1;}

对于防止溢出的 mid = l + (r - l ) /2;操作,也可以使用 mid = (l + r)>>>2; 但这里无符号右移等价除法仅适用于操作数是正数的情况。

对于二分查找的填空类笔试题,遵循:

- 奇数二分取中间

- 偶数二分取中间靠左

的原则。

二、排序

(一)冒泡排序

每次判断比较相邻两个位置的数字,直到末尾,在末尾确定一个数组中最大/最小的元素,这是一轮冒泡。

每一轮冒泡都确定好一个元素的位置,所以一共要进行nums.length - 1轮

 public static void bubble(int[] nums){for(int j = 0 ; j < nums.length ;j++){for(int i = 0 ; i < nums.length - 1 ; i++){if(nums[i] > nums[i+1]){swap(nums,i,i+1);}}}}public static void swap(int[] nums, int i , int j){int tmp = nums[i];nums[i] = nums[j];nums[j] = tmp;}

优化:

(1)每一轮冒泡不必都是nums.length - 1 次,每进行一轮,都可以少比较一次,因为结尾多确定了一位元素。

要减去的次数恰好是外层循环进行的次数,因此 i < nums.length - 1 - j 即可

 public static void bubble(int[] nums){for(int j = 0 ; j < nums.length ;j++){for(int i = 0 ; i < nums.length - 1 - j ; i++){if(nums[i] > nums[i+1]){swap(nums,i,i+1);}}}}public static void swap(int[] nums, int i , int j){int tmp = nums[i];nums[i] = nums[j];nums[j] = tmp;}

(2)当数组有序时,没有必要再进行冒泡了。

即当一次冒泡没有交换之后,就结束冒泡。

在每一轮冒泡前,增添一个标志位为false,swap时置为true,如果没有交换过,那么直接break.

public static void bubble(int[] nums){for(int j = 0 ; j < nums.length - 1;j++){boolean swapped = false;for(int i = 0 ; i < nums.length - 1 - j; i++){if(nums[i] > nums[i+1]){swap(nums,i,i+1);swapped = true;}}if(!swapped){break;}}}public static void swap(int[] nums, int i , int j){int tmp = nums[i];nums[i] = nums[j];nums[j] = tmp;}

(3)每一轮冒泡要比较的次数仍然可以改进,实际上,只需要记录下上一轮冒泡最后交换元素的下标是多少,在这之后没有发生过交换,说明这之后的元素是有序的,这个下标即为本轮冒泡要比较的次数。

这种优化方法融合了(1)和(2),并考虑了更多

最终实现:

public static void bubble2(int[] nums){int n  = nums.length - 1;for(;;){int last = 0;for(int i = 0 ; i < n ; i++){if(nums[i] > nums[i+1]){swap(nums,i,i+1);last = i;}}n = last;if(n == 0){break;}}}public static void swap(int[] nums, int i , int j){int tmp = nums[i];nums[i] = nums[j];nums[j] = tmp;}

关于上面这个实现如何理解:

(1)last就是记录的上一次交换的位置,这也是下一次冒泡要比较的次数

(2)last是最外层for循环内的局部变量,每次进来都是0,为了利用到last,添加的n,记录上一次的last;同时,last为0时(由n判断)也可以及时break,起到优化(2)的效果

(3)优化完以后,会发现最外层冒泡几轮已经完全由last(n)、i控制,最外层for循环的j不再需要,因此最外层的循环条件可以删除。

冒泡排序文字描述:

1.依次比较数组中相邻两个元素的大小,若a[i]>a[i+1],则交换两个元素,两两比较完一次称为一轮冒泡,一轮冒泡的结果是让最大的元素排到了最后

2.重复以上步骤,直到整个数组有序。

3.优化方式:每一轮冒泡时,最后一次交换的索引可以作为下一轮冒泡的比较次数,如果这个值为0,表示整个数组有序,直接退出外层循环即可。

(二)选择排序

选择排序每一轮从未排序部分选择一个最小的,放在已排序部分的最后,进行nums.length - 1轮后使数组有序。

最外层的遍历轮数 也即本轮从未排序部分找出最小的元素要交换到的索引位置。

public static void selection(int[] nums){for(int i = 0; i < nums.length - 1 ; i++){int s = i;for(int j = i + 1 ; j < nums.length ; j++){if(nums[j] < nums[s]){s = j;}}if(s != i){swap(nums,s,i);}}}public static void swap(int[] nums, int i , int j){int tmp = nums[i];nums[i] = nums[j];nums[j] = tmp;}

选择排序描述:

1.将数组分为两个子集,排序的和未排序的,每一轮从未排序的子集中选出最小的元素,放到排序子集的后面。

2.重复以上步骤,直到整个数组有序。

优化方式:

为了减少交换次数,每一轮先找到最小的索引,最后进行交换,这样可以让每一轮只进行一次交换。

与冒泡排序比较:

(1)二者的平均时间复杂度都是O(n^2)

(2)选择排序一般快于冒泡,因其交换次数少

(3)当集合有序度高时,冒泡优于选择

(4)冒泡排序是稳定算法,选择排序是不稳定算法

(三)插入排序

插入排序也将集合视为有序部分和无序部分,但插入排序是顺序扩大有序部分的。

与冒泡一样,对于有序数组排序的时间复杂度是O(n)

public static void insert(int[] nums){//i代表待插入元素的索引for(int i = 1 ; i < nums.length ; i++){//t 代表待插入元素的值int t = nums[i];//j 代表有序区的索引int j = i - 1;while(j >= 0){if(nums[j] > t){nums[j+1] = nums[j];j--;}else{break;}}nums[j+1] = t;}}

插入排序描述:

(1)插入排序将数组分为有序区和无序区,每一轮将无需区的第一个元素插入到有序区中,扩大有序区。与选择排序不同的是,插入排序扩大有序区需要保证顺序(即通过每次都是插入无序区的第一个元素来保证)

(2)重复以上步骤,直到整个数组有序

优化方式:

(1)待插入元素进行比较时,需要比自己小的元素,就代表找到了插入位置,可以跳出循环,不必进行后续的比较了。

(2)插入时可以直接移动元素,而不是交换元素。(交换的话需要中间变量,执行的语句更多,这是与冒泡的swap相比的)

插入排序与选择排序比较:

(1)二者平均时间复杂度都是O(n^2)

(2)大部分情况下,插入都略优于选择

(3)有序集合插入的时间复杂度为O(n)

(4)插入排序属于稳定排序算法,选择排序属于不稳定排序算法。

(四)希尔排序

插入排序存在一个缺点:如果一个较大元素一开始排在前半部分的话,这个较大元素需要移动较多次数才能够移动到数组的后半部分。

希尔排序将间隙相同的元素划为一组。同一组的元素进行插入排序。间隙不断减小,减小到1时完成排序。通过这样的方式在实际上增加了大元素的移动步数,从而解决了大元素每次移动一步,需要很多步才能移动到数组后半部分的问题。

(五)快速排序

1.单边循环快排(lomuto洛穆托分区方案)

(1)选择最右元素为pivot

(2)j指针负责找到比pivot小的元素,i指针指向待交换的元素,一旦j指针找到则与i进行交换

(3)i指针维护小于基准点元素的边界,也是每次交换的目标索引

(4)最后基准点与i交换,i即为分区位置。

public class Sort {public static void main(String[] args) {int[] nums= {3,2,3,1,2,4,5,5,6};quickSort(nums,0,nums.length-1);for (int num : nums) {System.out.println(num);}}public static void quickSort(int[] nums,int l , int h){if(l >= h) return ;int p = partition(nums,l,h);quickSort(nums,l,p-1);quickSort(nums,p+1,h);}//partition负责一次划分//return 基准点元素所在的正确索引public static int partition(int[] nums,int l , int h){int pivot = nums[h];int i = l ;for(int j = l ; j < h; j++){if(nums[j] < pivot){swap(nums,i,j);i++;}}swap(nums,i,h);return i;}public static void swap(int[] nums, int i, int j) {int tmp = nums[i];nums[i] = nums[j];nums[j] = tmp;}}

2.双边循环快排

(1)选择最左元素作为基准点元素

(2)j指针负责从右向左找比基准点小的元素,i指针负责从左向右找比基准点大的元素,一旦找到二者相交,直至i,j相交

(3)最后基准点与i(此时i与j相等)交换,i即为分区位置

在代码里有以下要注意的细节:

a.外层循环条件有i<j,内层也要有i<j.避免单次移动时过界

b.必须先找j,再找i,否则会在最后一次swap时出现问题,会把比pivot大的值交换到前面去

c.寻找i时while循环条件是<=,因为要跳过pivot自身

public static void main(String[] args) {int[] nums= {3,2,3,1,2,4,5,5,6};quickSort(nums,0,nums.length-1);for (int num : nums) {System.out.println(num);}}public static void quickSort(int[] nums,int l , int h){if(l >= h) return ;int p = partition2(nums,l,h);quickSort(nums,l,p-1);quickSort(nums,p+1,h);}public static int partition2(int[] nums,int l , int h){int i = l, j = h;int pivot = nums[i];while(i < j){while(i < j && nums[j] > pivot) j--;while(i < j && nums[i] <= pivot) i++;swap(nums,i,j);}swap(nums,l,j); //此时i和j重合return j;//此时i和j重合}public static void swap(int[] nums, int i, int j) {int tmp = nums[i];nums[i] = nums[j];nums[j] = tmp;}

快速排序的特点:

1.平均时间复杂度O(nlogn),但如果数组元素都是重复元素,快速排序的性能会受影响,最坏时间复杂度O(n^2)

2.数据量较大时,优势非常明显

3.属于不稳定排序

应用:leetcode 215.TopK问题

class Solution {public int findKthLargest(int[] nums, int k) {k = nums.length - k + 1;return quickSort3(nums,0,nums.length-1,k);}public static int quickSort3(int[] nums,int l , int h , int k){if(l >= h) return nums[l];int p = partition2(nums,l,h);//下标为p处,前面有p个元素if(p == k-1) return nums[p];else if(p > k-1) return quickSort3(nums,l,p-1,k);else return quickSort3(nums,p+1,h,k);}public static int partition2(int[] nums,int l , int h){int i = l, j = h;int pivot = nums[i];while(i < j){while(i < j && nums[j] > pivot) j--;while(i < j && nums[i] <= pivot) i++;swap(nums,i,j);}swap(nums,l,j); //此时i和j重合return j;//此时i和j重合}public static void swap(int[] nums,int i , int j){int tmp = nums[i];nums[i] = nums[j];nums[j] = tmp;}
}

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

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

相关文章

类和对象(2)

1.类的默认成员函数 默认成员函数就是⽤⼾没有显式实现&#xff0c;编译器会⾃动⽣成的成员函数称为默认成员函数。⼀个类&#xff0c;我们不写的情况下编译器会默认⽣成以下6个默认成员函数&#xff0c;需要注意的是这6个中最重要的是前4个&#xff0c;最后两个取地址重载不…

AcWing 1303:斐波那契前 n 项和 ← 矩阵快速幂加速递推

【题目来源】https://www.acwing.com/problem/content/1305/http://poj.org/problem?id3070【题目描述】 大家都知道 数列吧&#xff0c;。现在问题很简单&#xff0c;输入 和 &#xff0c;求 的前 项和 。【输入格式】 共一行&#xff0c;包含两个整数 和 。【输出格式】…

ElasticSearch备考 -- Index rollover

一、题目 给索引my-index-000001&#xff0c;创建别名my-index&#xff0c;并设置rollover&#xff0c;满足以下三个条件的 The index was created 7 or more days ago.The index contains 5 or more documents.The index’s largest primary shard is 1GB or larger. 二、思考…

zabbix 6.0 监控clickhouse(单机)

zabbix 6.0 LTS已经包含了clickhouse的监控模板&#xff0c;所以我们可以直接使用自带的模板来监控clickhouse了。 0.前置条件 clickhouse 已经安装&#xff0c;我安装的是24.3.5.47zabbix-agent 已经安装并配置。系统是ubuntu 2204 server 1. 新建监控用户 使用xml的方式为…

Jmeter自动化实战

一、前言 由于系统业务流程很复杂,在不同的阶段需要不同的数据,且数据无法重复使用,每次造新的数据特别繁琐,故想着能不能使用jmeter一键造数据 二、创建录制模板 可参考:jmeter录制接口 首先创建一个录制模板 因为会有各种请求头,cookies,签名,认证信息等原因,导致手动复制…

提升网站速度与性能优化的有效策略与实践

内容概要 在数字化快速发展的今天&#xff0c;网站速度与性能优化显得尤为重要&#xff0c;它直接影响用户的浏览体验。用户在访问网站时&#xff0c;往往希望能够迅速获取信息&#xff0c;若加载时间过长&#xff0c;轻易可能导致他们转向其他更为流畅的网站。因此&#xff0…

OpenCV视觉分析之目标跟踪(6)轻量级目标跟踪器类TrackerNano的使用

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 Nano 跟踪器是一个超轻量级的基于深度神经网络&#xff08;DNN&#xff09;的通用目标跟踪器。 由于特殊的模型结构&#xff0c;Nano 跟踪器速度…

C数组手动输入问题

问题界面 解析 输入数组数据也需要加取地址符吗&#xff1f;数组不就是地址了吗&#xff1f; 理解array[i]和array[i][j]的区别&#xff1a; array[i]是一个指向第i行第一个元素的指针&#xff08;int*类型&#xff0c;指向array[i][0]&#xff09;。 array[i][j]是一个int类…

Hadoop-002-部署并配置HDFS集群

集群规划 Hadoop HDFS的角色包含 NameNode(主节点管理者)、DataNode(从节点工作者)、SeconddaryNameNode(从节点辅助) 节点CPU内存hadoop-11C4Ghadoop-21C2Ghadoop-31C2G 一、下载上传Hadoop包 注意: 登录hadoop-1节点root用户执行 1、官网下载安装包后上传 到hadoop-1服务…

Android 在github网站下载项目:各种很慢怎么办?比如gradle下载慢;访问github慢;依赖下载慢

目录 访问github慢gradle下载慢依赖下载慢 前言 大家好&#xff0c;我是前期后期&#xff0c;在网上冲浪的一名程序员。 为什么要看这篇文章呢&#xff1f;问题是什么&#xff1f; 我们在Github上面看到一些好的项目的时候&#xff0c;想下载下来研究学习一下。但经常遇到各…

信息安全数学基础(35)同态和同构

一、同态 定义&#xff1a; 设(M,)和(S,)是两个群&#xff08;或更一般的代数系统&#xff09;&#xff0c;如果存在一个映射σ:M→S&#xff0c;使得对于M中的任意两个元素a、b&#xff0c;都有σ(ab)σ(a)σ(b)&#xff0c;则称σ为M到S的同态或群映射。 性质&#xff1a; 同…

微信小程序中点击搜素按钮没有反应,可能是样式问题(按钮被其他元素覆盖或遮挡)

文章目录 1. 确认 bindtap 绑定在正确的元素上2. 检查是否有遮挡或重叠元素3. 检查 this 上下文绑定问题4. 清除微信小程序开发者工具的缓存5. 用微信开发者工具查看事件绑定6. 确保 handleSearch 没有拼写错误进一步调试 1、searchResults.wxml2、searchResults.wxss3、search…

实验干货|电流型霍尔传感器采样设计03-信号调理

在前两篇博客中&#xff0c;将霍尔输出的电流信号转换成了有正有负的电压信号&#xff0c;但是DSP需要采集0~3V的电压信号&#xff0c;因此需要对信号缩放并抬升至全部为正的信号。 常见的方法是&#xff0c;通过比例放大(缩小)电路对信号进行放缩&#xff0c;通过加法电路抬升…

SQLI LABS | Less-20 POST-Cookie Injections-Uagent field-error based

关注这个靶场的其它相关笔记&#xff1a;SQLI LABS —— 靶场笔记合集-CSDN博客 0x01&#xff1a;过关流程 输入下面的链接进入靶场&#xff08;如果你的地址和我不一样&#xff0c;按照你本地的环境来&#xff09;&#xff1a; http://localhost/sqli-labs/Less-20/ 可以看到…

爬虫+数据保存2

爬取数据保存到MySQL数据库 这篇文章, 我们来讲解如何将我们爬虫爬取到的数据, 进行保存, 而且是把数据保存到MySQL数据库的方式去保存。 目录 1.使用pymysql连接数据库并执行插入数据sql代码(insert) 2.优化pymysql数据库连接以及插入功能代码 3.爬取双色球网站的数据并保…

echarts 遍历多个图表,并添加resize缩放

数据结构&#xff1a; data() { return { charts: [ { title: Chart 1, xAxisData: [Mon, Tue, Wed, Thu, Fri, Sat, Sun], yAxisData: [120, 200, 150, 80, 70, 110, 130], }, { title: Chart 2, xAxisData: [Jan, Feb, Mar, Apr, May, Jun, Jul], yAxisData: [22…

Linux 中,flock 对文件加锁

在Linux中&#xff0c;flock是一个用于对文件加锁的实用程序&#xff0c;它可以帮助协调多个进程对同一个文件的访问&#xff0c;避免出现数据不一致或冲突等问题。以下是对flock的详细介绍&#xff1a; 基本原理 flock通过在文件上设置锁来控制多个进程对该文件的并发访问。…

(五)Web前端开发进阶2——AJAX

目录 2.Axios库 3.认识URL 4.Axios常用请求方法 5.HTTP协议——请求报文/响应报文 6.前后端分离开发 7.Element组件库 1.Ajax概述 AJAX 是异步的 JavaScript和XML(Asynchronous JavaScript And XML)。简单点说&#xff0c;就是使用XMLHttpRequest 对象与服务器通信。它可…

使用C#学习Office文件的处理(pptx docx xlsx)

Office文件 是指PPT 、word、Excel 这些常用工具生成的文件 &#xff0c;例如 pptx docx xlsx。 这些文件的读取和生成有很多很多库 例如 NOPI 、DevExpress、C1、Aspose、Teleric 等等&#xff0c;各有各的优缺点。俺今天不讲这个&#xff0c;俺只是讲讲如何了解Office文件的…

2020年下半年网络规划设计师上午真题及答案解析

1.在支持多线程的操作系统中&#xff0c;假设进程P创建了线程T1&#xff0c;T2&#xff0c;T3&#xff0c;那么下列说法中正确的是&#xff08; &#xff09;。 A.该进程中已打开的文件是不能被T1&#xff0c;T2和T3共享的 B.该进程中T1的栈指针是不能被T2共享&#xff0c;但…