排序算法大汇总 Java实现
一、插入类算法
排序算法的稳定性:两个大小相等的元素排序前后的相对位置不变。{31,32,2} 排序后{2,31,32},则称排序算法稳定
通用类:
public class Common {
public static int[] a = {48,62,35,77,55,14,35,98};
public static void swap(int[] a, int i, int j) {
int temp = a[i];
a[i] = a[j];
a[j] = temp;
}
public static void print(int[] a) {
for(int num : a) {
System.out.print(num + " ");
}
System.out.println();
}
}
1、插入排序
算法思想:将第i个元素插入到前i-1个已排好序的序列中。即要从i=2开始插入元素,默认第一个元素在已排好序的子集之中。
public static void insertSort(int[] a) {
for(int i = 1; i < a.length; i++) {
for(int j = i - 1; j>=0 ; j--) {
if(a[j+1]<a[j]) Common.swap(a, j+1, j);
else break;
}
}
}
对插入排序就是这么简单,想这么简单的代码面试时是不可能考的,主要理解算法的思想,例如考一个对链表进行插入排序。
时间复杂度:最好的情况待排序序列已经有序O(n),最差的情况O(n2)。
空间复杂度:O(1)
稳定性:稳定
2、希尔排序
算法思想:希尔排序是对插入排序的改进,插入排序在待排序序列基本有序的情况下效率最高,希尔排序会进行组内插入排序,使得待排序数组基本有序,在进行插入排序。先以间隔为d元素划分一组,将集合划分成d组子集,例如{1,2,3,4,5,6},d=2,则第一组{1,3,5},第二组{2,4,6};即下标i+k*d的都是一组。d的值一般取d = n/3 + 1,每次排序d缩小为原来的1/3。
public static void shellSort(int[] a) {
int d = a.length/3 + 1;
while(d >= 1) {
for(int i = d; i < a.length; i++) {
for(int j = i - d; j >=0 ; j = j-d) {
if(a[j+d]<a[j]) Common.swap(a, j+d, j);
else break;
}
}
d = d/3;
}
}
时间复杂度:O(n1.5)
空间复杂度:O(1)
稳定性:不稳定
二、交换类排序
1、冒泡排序
算法思想:每一轮和相邻元素比较,以第一个元素为开始,当前元素大于后一个元素则交换位置,当前元素小于后面元素则不动,这样没一轮都可以上浮一个最大的元素,最多进行n-1轮。
public static void bubbleSort(int[] a) {
boolean flag = true;
for(int i = 1; i <= a.length-1&&flag; i++) {
flag = false;
for(int j = 0; j < a.length - i; j++) {
if(a[j]>a[j+1]) {
Common.swap(a, j, j+1);
flag = true;
}
}
}
}
时间复杂度:最好的情况下,待排序列有序O(n);最坏的情况下,倒序O(n2)
空间复杂度:O(1)
稳定性:稳定
2、快速排序
这个有点重要哦,Java类库里对基本类型的排序基本上都是使用快速排序,对象类型的元素都使用归并排序。
算法思想:基于分治法的思想
首先,进行一趟快排,选择第一个元素作为枢轴元素x,目的将小于x的移到x的左边,大于等于x的移到x的右边。
①low从左向右扫描,直到a[low] >= x,交换a[low]与a[high]
②high从右向左扫描,直到a[high] > x,交换a[low]与a[high]
③将x与a[high]交换
记住low永远指向大于等于x的元素,high永远指向小于x的元素
然后使用分治法,对x左边和右边元素分别进行快排。
public static void sort(int[] a, int low, int high) {
if(low>=high) return;
int l = low+1;
int h = high;
while(l<=h) {
if(a[l]>=a[low]) Common.swap(a, l, h--);
else l++;
}
Common.swap(a, low, h);
sort(a, low, h-1);
sort(a, h+1, high);
}
时间复杂度:一般情况O(nlogn),最坏的情况待排序列有序O(n2)
空间复杂度:使用了递归栈O(logn)
稳定性:不稳定
3、三向切分排序
这是快速排序的演变版本,多了一个指针维护与枢轴相等的元素
public static void sort1(int[] a, int low, int high) {
if(low>=high) return;
int l = low;
int i = low+1;
int h = high;
while(i<=h) {
if(a[i]>a[low]) Common.swap(a, i, h--);
else if(a[i]<a[low]) Common.swap(a, i++, l++);
else i++;
}
sort1(a,low,l-1);
sort1(a,h+1,high);
}
时间复杂度:O(nlogn)
空间复杂度:O(logn)
稳定性:不稳定
4、利用一趟快排寻找第K大或第K小元素
private static int partition(int[] a, int low, int high) {
int l = low+1;
int h = high;
while(l<=h) {
if(a[l]>=a[low]) Common.swap(a, l, h--);
else l++;
}
Common.swap(a, low, h);
return h;
}
public static int select(int[] a, int k) {
int l = 0;
int h = a.length-1;
while(l<h) {
int min = partition(a,l,h);
if(min >= k-1) h = min;
else l = min+1;
}
return a[h];
}
时间复杂度:O(n)排序算法中能够在线性时间复杂度内解决问题的只有切分快速选择和桶排序了。
空间复杂度:O(1)
三、归并排序
这个也重要哦,因为有点难所以就很重要,面试的时候总不是拿几个大家都会的简单题考吧,考的一定是难题。
算法思想:基于分治法的算法思想
合并两个排好序的子集,然后递归调用,看程序啪
public static void sort(int[] a, int low, int high) {
if(low>=high) return;
int mid = (low + high) >>> 1;
int l1 = low;
int l2 = mid + 1;
int i = low;
sort(a,low,mid);
sort(a,mid+1,high);
int[] temp = Arrays.copyOf(a, a.length);
while(l1<=mid&&l2<=high) {
if(temp[l1]<=temp[l2]) a[i++] = temp[l1++];
else a[i++] = temp[l2++];
}
while(l1<=mid) {
a[i++] = temp[l1++];
}
while(l2<=high) {
a[i++] = temp[l2++];
}
}
时间复杂度:O(nlogn)
空间复杂度:O(n)
稳定性:稳定
四、堆排序
堆排序真的是很少用,排序重点应该在排序上面,而堆排序重点在建堆上。
堆排序最主要的操作是重建堆
//重建堆
private static void sift(int[] a, int start, int end) {
int i = start;//始终指向当前根
int j = 2*i;//指向当前根的左孩子
int x = a[start];
while(j<=end) {
//有右孩子,且右孩子值大,搜索右子树
if(j+1<=end&&a[j+1]>a[j]) j++;
if(x>=a[j]) break;
else {
Common.swap(a, i, j);
i = j;
j = 2*i;
}
}
}
创建堆自下而上,从第一个非叶子节点开始创建堆
//创建堆
public static void create(int[] a) {
int i = (a.length-1)/2;
for(; i >= 1; i--) {
sift(a,i,a.length-1);
}
}
堆排序
public static void sort(int[] a) {
create(a);
for(int i = a.length-1; i > 1; i--) {
Common.swap(a, 1, i);
sift(a,1,i-1);
}
}
时间复杂度:O(nlogn)
空间复杂度:O(1)
考察形式:215. 数组中的第K个最大元素
public int findKthLargest(int[] nums, int k) {
PriorityQueue<Integer> pq = new PriorityQueue<>();
for(int num : nums) {
pq.add(num);
if(pq.size() > k) pq.poll();
}
return pq.peek();
}
使用优先级队列PriorityQueue创建一个小顶堆,确保队列中只有K各元素,每次poll都是去掉小的元素,剩下k就是k个最大的元素,队头就是我们要找的答案。
当然我们也可以使用切分选择算法,但是都没有Java类库中自带的排序算法高效。
五、选择排序
算法思想:从剩下的元素集合A中选取一个最小的和A中的第一个元素交换,直至有序
public static void sort(int[] a) {
for(int i = 0; i < a.length; i++) {
int k = i;
for(int j = i; j < a.length; j++) {
if(a[j]<a[k]) k = j;
}
if(k!=i) Common.swap(a, i, k);
}
}
时间复杂度:O(n2)
空间复杂度:O(1)
稳定性:不稳定
六、桶排序
算法思想:用空间换时间,使用了哈希表。
看个题就明白了
public List<Integer> topKFrequent(int[] nums, int k) {
HashMap<Integer,Integer> hash = new HashMap<>();
LinkedList<Integer> ans = new LinkedList<>();
for(int num : nums) {
int v = hash.containsKey(num) == true ? hash.get(num) + 1 : 1;
hash.put(num,v);
}
LinkedList<Integer>[] buckets = new LinkedList[nums.length+1];
for(Map.Entry e : hash.entrySet()) {
int f = (Integer)e.getValue();
if(buckets[f] == null) buckets[f] = new LinkedList<Integer>();
buckets[f].add((Integer)e.getKey());
}
for(int i = nums.length; i >= 1 ; i--) {
if(buckets[i]==null) continue;
while(k > 0 && buckets[i].size() > 0) {
ans.add(buckets[i].poll());
k--;
}
}
return ans;
}
使用hash表统计频率,以频率为数组下标放入桶中,这样就利用数组按照频率自然的由低到高排序
时间复杂度:只有O(n)哦,要是排序题中出现线性时间复杂度,就妥妥的桶排序。
空间复杂度:O(n)
七、总结
| 类别 | 算法 | 稳定性 | 时间复杂度 | 空间复杂度 | 说明 |
|---|---|---|---|---|---|
| 插入类 | 插入排序 | √ | O(n)~O(n2) | O(1) | |
| 希尔排序 | × | O(n1.5) | O(1) | 对直接插入排序的改进 | |
| 交换类 | 冒泡排序 | √ | O(n)~O(n2) | O(1) | |
| 快速排序 | × | O(nlogn)~O(n2) | O(logn) | 对冒泡的改进 | |
| 三向快排 | × | O(nlogn) | O(logn) | 适用于有重复元素的 | |
| 选择类 | 选择排序 | × | O(n2) | O(1) | |
| 堆排序 | × | O(nlogn) | O(1) | 对选择排序的改进 | |
| 其他类 | 归并排序 | √ | O(nlogn) | O(n) | |
| 桶排序 | × | O(n) | O(n) | 唯一线性时间 |
1、稳定的算法,只有插入排序、冒泡排序、归并排序
2、时间复杂度稳定在O(nlog)常用的就是快排和归并
3、桶排序,唯一的线性时间
排序算法大汇总 Java实现的更多相关文章
- 排序算法总结(基于Java实现)
前言 下面会讲到一些简单的排序算法(均基于java实现),并给出实现和效率分析. 使用的基类如下: 注意:抽象函数应为public的,我就不改代码了 public abstract class Sor ...
- 常见排序算法题(java版)
常见排序算法题(java版) //插入排序: package org.rut.util.algorithm.support; import org.rut.util.algorithm.Sor ...
- 八大排序算法总结与java实现(转)
八大排序算法总结与Java实现 原文链接: 八大排序算法总结与java实现 - iTimeTraveler 概述 直接插入排序 希尔排序 简单选择排序 堆排序 冒泡排序 快速排序 归并排序 基数排序 ...
- 第二章:排序算法 及其他 Java代码实现
目录 第二章:排序算法 及其他 Java代码实现 插入排序 归并排序 选择排序算法 冒泡排序 查找算法 习题 2.3.7 第二章:排序算法 及其他 Java代码实现 --算法导论(Introducti ...
- 动画展现十大经典排序算法(附Java代码)
0.算法概述 0.1 算法分类 十种常见排序算法可以分为两大类: 比较类排序:通过比较来决定元素间的相对次序,由于其时间复杂度不能突破O(nlogn),因此也称为非线性时间比较类排序. 非比较类排序: ...
- 排序算法总结及Java实现
1. 整体介绍 分类 排序大的分类可以分为两种,内排序和外排序.在排序过程中,全部记录存放在内存,则称为内排序,如果排序过程中需要使用外存,则称为外排序.主要需要理解的都是内排序算法: 内排序可以分为 ...
- 常见排序算法总结(java版)
一.冒泡排序 1.原理:相邻元素两两比较,大的往后放.第一次完毕,最大值在最大索引处. 即使用相邻的两个元素一次比价,依次将最大的数放到最后. 2.代码: public static void bub ...
- 排序算法之冒泡排序Java实现
排序算法之冒泡排序 舞蹈演示排序: 冒泡排序: http://t.cn/hrf58M 希尔排序:http://t.cn/hrosvb 选择排序:http://t.cn/hros6e 插入排序:ht ...
- 排序算法代码实现-Java
前言 为了准备面试,从2月开始将排序算法认认真真得刷了一遍,通过看书看视频,实践打代码,还有一部分的leetcode题,自己感觉也有点进步,将笔记记录总结发出来. 冒泡排序 该排序就是一种像泡泡浮到水 ...
随机推荐
- 2019 南昌ICPC网络赛H The Nth Item
The Nth Iteam 题意:F(0)=1,F(1)=1,F(n)=3*F(n-1)+2*F(n-2) (n>=2) ,F(n) mod 998244353.给出Q跟N1,Ni=Ni-1^( ...
- 从斐波那契数列看java方法的调用过程
先看斐波那契数列的定义: 斐波那契数列(Fibonacci sequence),又称黄金分割数列.因数学家列昂纳多·斐波那契(Leonardoda Fibonacci)以兔子繁殖为例子而引入,故又称为 ...
- 第72节:Java中的数组
https://www.jianshu.com/p/9ad176caa5bc
- Jmeter(十四)取样器之JDBC Request
在接口测试中,需要与数据库进行交互,这时候需要用到JDBC Request取样器. JDBC Request可以向数据库发送一个请求(sql语句),一般它需要配合JDBC Connection Con ...
- 如何优雅地防止MLE(for linux)
赛前最后一天模拟赛又有小伙伴MLE了--这里就讲一下如何较为精确地获取程序运行时间和空间. 资源统计当然是操作系统统计的最精确.所以可以这样写(noilinux实测通过,windows下应该不行): ...
- 修改tomcat控制台的标题
Tomcat的bin目录下,创建一个名为setenv.bat的文件. setenv.bat 编辑内容 : set TITLE = 想要命名的标题名称 保存修改.重新启动. 第二种. 修改tomca ...
- 关于使用express作为spa应用服务的问题
前端工程师应该知道,spa是基于前端路由的单页面应用,如果服务端不做相应的配置,会经常出现404的问题. 一般的做法是默认返回应用的首页. express // 安装相关依赖 npm install ...
- 解决虚拟机上的tomcat无法被主机访问的问题
在wmware中安装linux后安装好数据库,JDK及tomcat后启动服务,虚拟机中可以访问,但是主机却无法访问,但是同时主机和虚拟机之间可以ping的通. 网上查阅资料后 第一种解决方法是 ...
- QT .pro文件中的变量说明
https://blog.csdn.net/tanou3212/article/details/79942840 TEMPLATE:定义了工程的编译模式 赋值方式为:TEMPLATE=app (1 ...
- 华为鸿蒙OS能取代安卓吗?
先回答问题,不能,起码几年之内不存在这种可能.8月9日华为的开发者大会上,余承东说:鸿蒙是一款基于微内核的全场景分布式OS.鸿蒙OS的设计初衷是为满足全场景智慧体验的高标准的连接要求,为此华为提出了4 ...