十大排序算法(Java实现)
一、冒泡排序(Bubble Sort)
基础版
/**
* 遍历数组,依次比较相邻的元素并交换,每次都将最大元素(根据正序还是逆序决定)放到数组末尾
* @param arr 待排序数组
* @return
*/
public static int[] bubbleSort(int[] arr) {
int temp;
for (int i = 0; i < arr.length - 1; i++) {
for (int j = 0; j < arr.length - i - 1; j++) {
if (arr[j] > arr[j + 1]) {
temp = arr[j + 1];
arr[j + 1] = arr[j];
arr[j] = temp;
}
}
}
return arr;
}
优化一
//冒泡排序:优化一
public static int[] bubbleSort1(int[] arr) {
int temp;
//记录数组是否有序
boolean isSorted;
for (int i = 0; i < arr.length - 1; i++) {
isSorted = true;
for (int j = 0; j < arr.length - i - 1; j++) {
if (arr[j] > arr[j + 1]) {
temp = arr[j + 1];
arr[j + 1] = arr[j];
arr[j] = temp;
//记录本轮排序是否交换了元素,如果交换则置为false
isSorted = false;
}
}
//没有交换证明已经是有序的了,直接终止循环
if (isSorted) {
break;
}
}
return arr;
}
优化二
//冒泡排序:优化二
public static int[] bubbleSort2(int[] arr) {
int temp;
boolean isSorted;
//第一次循环边界
int sortBorder = arr.length - 1;
//记录每轮排序最后一次进行交换的位置
int lastSwapIndex = 0;
for (int i = 0; i < arr.length - 1; i++) {
isSorted = true;
for (int j = 0; j < sortBorder; j++) {
if (arr[j] > arr[j + 1]) {
temp = arr[j + 1];
arr[j + 1] = arr[j];
arr[j] = temp;
isSorted = false;
lastSwapIndex = j;
}
}
sortBorder = lastSwapIndex;
if (isSorted) {
break;
}
}
return arr;
}
二、选择排序(Selection Sort)
/**
* 遍历数组,每次遍历都找到最小的元素,记录其下标,内层循环结束后再根据下标将其与数组头部元素交换
* 与冒泡排序不同的是,冒泡排序每次循环可能交换多次,而选择排序最多交换一次
* @param arr 待排序数组
* @return
*/
public static int[] selectionSort(int[] arr) {
int temp, minIndex;
for (int i = 0; i < arr.length - 1; i++) {
minIndex = i;
for (int j = i + 1; j < arr.length; j++) {
if (arr[j] < arr[minIndex]) {
minIndex = j;
}
}
temp = arr[minIndex];
arr[minIndex] = arr[i];
arr[i] = temp;
}
return arr;
}
三、插入排序(Insertion Sort)
/**
* 用一个临时变量存储待插入的值,从后往前找,如果找到比这个值大的元素,则将其前面的元素依次后移,
* 结束后再将带插入的值放到该插入的位置,减去了许多不必要的交换操作
* @param arr
* @return
*/
public static int[] insertionSort(int[] arr) {
for (int i = 1; i < arr.length; i++) {
int insertValue = arr[i];//待插入元素
int preIndex = i - 1;
while (preIndex >= 0 && insertValue < arr[preIndex]) {
arr[preIndex + 1] = arr[preIndex];
preIndex--;
}
arr[preIndex + 1] = insertValue;
}
return arr;
}
四、希尔排序(Shell Sort)
/**
* 希尔排序
* 插入排序的升级版,设定步长为数组长度的一半,每次都除以二,直到步长为1
* @param arr
* @return
*/
public static int[] shellSort(int[] arr) {
int len = arr.length;
for (int k = len / 2; k > 0; k /= 2) {
for (int i = k; i < len; i++) {
int temp = arr[i];
int j = i - k;
while (j >= 0 && temp < arr[j]) {
arr[j + k] = arr[j];
j -= k;
}
arr[j + k] = temp;
}
}
return arr;
}
五、归并排序(Merge Sort)
//归并排序
public static int[] mergeSort(int[] arr) {
return mergeSort(arr, 0, arr.length - 1, new int[arr.length]);
}
/**
* 归并排序通过递归将数组分解为只有两个元素,按照它们的大小放入到一个临时数组中,直到全部合并
*
* @param arr 待排序数组
* @param left 左索引
* @param right 右索引
* @param temp 临时数组,存储每次合并后的元素
* @return
*/
public static int[] mergeSort(int[] arr, int left, int right, int[] temp) {
if (left < right) {
int mid = (left + right) >> 1;
//向左分解
mergeSort(arr, left, mid, temp);
//向右分解
mergeSort(arr, mid + 1, right, temp);
//合并
merge(arr, left, mid, right, temp);
}
return arr;
}
//合并
public static int[] merge(int[] arr, int left, int mid, int right, int[] temp) {
int i = left, j = mid + 1, k = 0;
//按大小放入临时数组中
while (i <= mid && j <= right) {
if (arr[i] < arr[j]) {
temp[k] = arr[i];
k++;
i++;
} else {
temp[k] = arr[j];
k++;
j++;
}
}
//将剩余元素放到temp剩余位置
while (i <= mid) {
temp[k] = arr[i];
k++;
i++;
}
while (j <= right) {
temp[k] = arr[j];
k++;
j++;
}
//将排好序的temp数组元素赋值给原数组
k = 0;
int l = left;
while (l <= right) {
arr[l] = temp[k];
k++;
l++;
}
return arr;
}
六、快速排序(Quick Sort)
//快速排序
public static int[] quickSort(int[] arr) {
return quickSort(arr, 0, arr.length - 1);
}
public static int[] quickSort(int[] arr, int startIndex, int endIndex) {
if (startIndex < endIndex) {
//获取基准对应的下标
int pivotIndex = partition1(arr, startIndex, endIndex);
quickSort(arr, startIndex, pivotIndex - 1);
quickSort(arr, pivotIndex + 1, endIndex);
}
return arr;
}
/**
* 方式一:双边循环交换
* 先从右边找到比基准元素小的值,再从左边找到比基准元素大的值,然后交换两者
* 直到左右指针相遇,再交换基准和相遇位置的值
*
* @param arr 待排序数组
* @param startIndex 起始索引
* @param endIndex 结束索引
* @return 返回基准索引
*/
public static int partition1(int[] arr, int startIndex, int endIndex) {
//取第一个元素作为基准,也可以取一个随机元素与第一个元素交换
int pivot = arr[startIndex];
int left = startIndex, right = endIndex;
int temp;
while (left != right) {
while (left < right && arr[right] > pivot) {
right--;
}
while (left < right && arr[left] <= pivot) {
left++;
}
//交换左右元素
if (left < right) {
temp = arr[right];
arr[right] = arr[left];
arr[left] = temp;
}
}
//交换重合位置元素和基准
arr[startIndex] = arr[left];
arr[left] = pivot;
return left;
}
//方式二:单边循环
public static int partition2(int[] arr, int startIndex, int endIndex) {
int pivot = arr[startIndex];
//定义一个mark,数组向右寻找比pivot小的元素,找到后mark+1,然后互相交换
int mark = startIndex;
for (int i = startIndex + 1; i <= endIndex; i++) {
if (arr[i] < pivot) {
mark++;
int temp = arr[i];
arr[i] = arr[mark];
arr[mark] = temp;
}
}
//交换mark位置的值和pivot
arr[startIndex] = arr[mark];
arr[mark] = pivot;
return mark;
}
七、堆排序(Heap Sort)
public static int[] heapSort(int[] arr) {
//以最后一个非叶子结点构建大顶堆
for (int i = arr.length / 2 - 1; i >= 0; i--) {
adjustHeap(arr, i, arr.length);
}
//此时顶部元素是最大的,交换顶部元素和末端元素
for (int i = arr.length - 1; i > 0; i--) {
swap(arr, 0, i);
//末端元素已经是最大的了,无需考虑排序
adjustHeap(arr, 0, i);
}
return arr;
}
/**
* 形成大顶堆
*
* @param arr 数组元素
* @param i 当前结点位置
* @param len 结点个数
*/
public static void adjustHeap(int[] arr, int i, int len) {
//保存当前结点
int temp = arr[i];
//遍历当前结点的左子结点
for (int k = 2 * i + 1; k < len; k = 2 * k + 1) {
//如果右结点存在 且 右结点比左结点大,指向右结点
if (k + 1 < len && arr[k] < arr[k + 1]) {
k++;
}
//判断当前结点和左(右)结点哪个大
if (temp < arr[k]) {
//交换
swap(arr, k, i);
//交换后,下次遍历以该子结点作为根节点的子树就会受到影响,因此需要重新指定下次的根节点
i = k;
} else {
//不用交换,直接终止循环
break;
}
}
}
public static void swap(int[] arr, int i, int j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
八、计数排序(Counting Sort)
/**
* 计数排序:
* 将待排序数组的值(或者差值)作为新数组的下标,新数组的值是排序元素在此位置的个数
* 使用max-min+1作为数组长度可以减少空间浪费
*
* @param arr
* @return
*/
public static int[] countingSort(int[] arr){
int max = arr[0];
int min = arr[0];
for (int i = 1; i < arr.length; i++) {
if(max < arr[i]){
max = arr[i];
}
if(min > arr[i]){
min = arr[i];
}
}
int[] count = new int[max - min + 1];
//将待排序数组放到count中
for (int value : arr) {
count[value - min]++;
}
//将count放到arr中
int k = 0;
for (int i = 0; i < count.length; i++) {
while(count[i] > 0){
arr[k++] = i;
count[i]--;
}
}
return arr;
}
优化
//计数排序优化,变为稳定排序
public static int[] countingSort1(int[] arr){
int max = arr[0];
int min = arr[0];
for (int i = 1; i < arr.length; i++) {
if(max < arr[i]){
max = arr[i];
}
if(min > arr[i]){
min = arr[i];
}
}
int[] count = new int[max - min + 1];
//将待排序数组放到count中
for (int value : arr) {
count[value - min]++;
}
//当前的元素等于前面的元素加上当前
for (int i = 1; i < count.length; i++) {
count[i] += count[i-1];
}
//倒序遍历count
int[] storedArr = new int[arr.length];
for (int i = arr.length - 1; i >= 0; i--) {
storedArr[count[arr[i] - min]-1] = arr[i];
count[arr[i] - min]--;
}
return storedArr;
}
九、桶排序(Bucket Sort)
public class BucketSort {
/**
* 桶排序:
* 将数据分为n个区间,区间的跨度为 (max - min) / (n - 1)
*
* @param arr
* @return
*/
public static int[] bucketSort(int[] arr){
int max = arr[0];
int min = arr[0];
for (int i = 1; i < arr.length; i++) {
if (max < arr[i]) {
max = arr[i];
}
if (min > arr[i]) {
min = arr[i];
}
}
int bucketNum = arr.length;//桶个数
int d = max - min;//差值
ArrayList<LinkedList<Integer>> bucketList = new ArrayList<>(bucketNum);//模拟5个桶
//初始化桶
for (int i = 0; i < bucketNum; i++) {
bucketList.add(new LinkedList<>());
}
//将待排序元素放到桶中
for (int i = 0; i < arr.length; i++) {
int num = (arr[i] - min) * d / (bucketNum - 1);//应该存入的桶号
bucketList.get(num).add(arr[i]);
}
//对每个桶的数据进行排序
for (int i = 0; i < bucketNum; i++) {
//JDK 底层采用了归并排序(1.7之前)或归并的优化版本
Collections.sort(bucketList.get(i));
}
//将桶的数据取出
int k = 0;
for (LinkedList<Integer> nums : bucketList) {
for (Integer num : nums) {
arr[k++] = num;
}
}
return arr;
}
}
十、基数排序(Radix Sort)
public class RadixSort {
/**
* 基数排序:
* 根据每个数的个位、十位、百位...的值(0~9)放入桶中(规则和计数排序相同),因此需要10个桶
*
* @param arr
* @return
*/
public static int[] radixSort(int[] arr){
//创建并初始化10个桶
ArrayList<LinkedList<Integer>> bucketList = new ArrayList<>(10);
for (int i = 0; i < 10; i++) {
bucketList.add(new LinkedList<>());
}
//找出数据中最大值
int max = arr[0];
for (int i = 1; i < arr.length; i++) {
if (max < arr[i]) {
max = arr[i];
}
}
//获取最大值的位数
int maxRadix = (max + "").length();
//从个位开始
for (int i = 0; i < maxRadix; i++) {
//将待排序元素放入桶中
for (int j = 0; j < arr.length; j++) {
//获取数字对应位上的值
int radix = arr[j] / (int) Math.pow(10, i) % 10;
//放入对应的桶中
bucketList.get(radix).add(arr[j]);
}
//将桶中元素放回原数组
int k = 0;
for (int j = 0; j < 10; j++) {
for (Integer number : bucketList.get(j)) {
arr[k++] = number;
}
bucketList.get(j).clear();
}
}
return arr;
}
}
最后:测试
public static void main(String[] args) {
int[] arr = {3, 1, 9, 10, 4, 0, 6, 5, 2, 12, 8, 7, 11};
//[0, 3, 4, 5, 6, 7, 8, 10, 16, 22, 29, 33, 38]
System.out.println("冒泡排序:"+ Arrays.toString(bubbleSort(arr)));
System.out.println("冒泡排序-优化1:"+ Arrays.toString(bubbleSort1(arr)));
System.out.println("冒泡排序-优化2:"+ Arrays.toString(bubbleSort2(arr)));
System.out.println("选择排序:"+ Arrays.toString(selectionSort(arr)));
System.out.println("插入排序:"+ Arrays.toString(insertionSort(arr)));
System.out.println("希尔排序:"+ Arrays.toString(shellSort(arr)));
System.out.println("归并排序:"+ Arrays.toString(mergeSort(arr)));
System.out.println("快速排序:"+ Arrays.toString(quickSort(arr)));
System.out.println("堆排序:"+ Arrays.toString(heapSort(arr)));
System.out.println("计数排序:"+ Arrays.toString(countingSort(arr)));
System.out.println("计数排序-优化1:"+ Arrays.toString(countingSort1(arr)));
System.out.println("桶排序:"+ Arrays.toString(bucketSort(arr)));
System.out.println("基数排序:"+ Arrays.toString(radixSort(arr)));
}
十大排序算法(Java实现)的更多相关文章
- 十大排序算法总结(Python3实现)
十大排序算法总结(Python3实现) 本文链接:https://blog.csdn.net/aiya_aiya_/article/details/79846380 目录 一.概述 二.算法简介及代码 ...
- Algorithm --> 十大排序算法
十大排序算法 主要排序法有: 一.冒泡( Bubble)排序—— 相邻交换 二.选择排序 ——每次最小/ 大排在相应的位置 三.插入排序 ——将下一个插入已排好的序列中 四.壳( Shell) ...
- [ 转载 ] js十大排序算法:冒泡排序
js十大排序算法:冒泡排序 http://www.cnblogs.com/beli/p/6297741.html
- 十大排序算法JavaScript实现总结
花费了几周的时间断断续续的练习和模仿与使用JavaScript代码实现了十大排序算法. 里面有每种算法的动图和静态图片演示,看到图片可以自己先按照图片的思路实现一下. github中正文链接,点击查看 ...
- 一篇夯实一个知识点系列--python实现十大排序算法
写在前面 排序是查找是算法中最重要的两个概念,我们大多数情况下都在进行查找和排序.科学家们穷尽努力,想使得排序和查找能够更加快速.本篇文章用Python实现十大排序算法. 干货儿 排序算法从不同维度可 ...
- 使用 js 实现十大排序算法: 快速排序
使用 js 实现十大排序算法: 快速排序 QuickSort 快速排序 /** * * @author xgqfrms * @license MIT * @copyright xgqfrms * @c ...
- 使用 js 实现十大排序算法: 桶排序
使用 js 实现十大排序算法: 桶排序 桶排序 refs xgqfrms 2012-2020 www.cnblogs.com 发布文章使用:只允许注册用户才可以访问!
- 使用 js 实现十大排序算法: 计数排序
使用 js 实现十大排序算法: 计数排序 计数排序 refs xgqfrms 2012-2020 www.cnblogs.com 发布文章使用:只允许注册用户才可以访问!
- 使用 js 实现十大排序算法: 基数排序
使用 js 实现十大排序算法: 基数排序 基数排序 refs xgqfrms 2012-2020 www.cnblogs.com 发布文章使用:只允许注册用户才可以访问!
- 使用 js 实现十大排序算法: 冒泡排序
使用 js 实现十大排序算法: 冒泡排序 冒泡排序 refs xgqfrms 2012-2020 www.cnblogs.com 发布文章使用:只允许注册用户才可以访问!
随机推荐
- H3C 802.1X典型配置举例
- 基于Springboot+Junit+Mockito做单元测试
前言 前面的两篇文章讨论过< 为什么要写单元测试,何时写,写多细 >和<单元测试规范>,这篇文章介绍如何使用Springboot+Junit+Mockito做单元测试,案例选取 ...
- ASP.NET MVC 实现页落网资源分享网站+充值管理+后台管理(1)之数据库设计
本文主要讲解本项目网站所应用到的知识点,及数据库的相关设计: 一.知识点 (1)本项目主要采取ASP.NET MVC的编程模式,相信你已经了解到了MVC的具体含义是什么,这里不再赘述,有不了解的朋友, ...
- Linux 内核完成 urb: 完成回调处理者
如果对 usb_submit_urb 的调用成功, 传递对 urb 的控制给 USB 核心, 这个函数返回 0; 否则, 一个负错误值被返回. 如果函数成功, urb 的完成处理者(如同被完成函数指针 ...
- 【37.74%】【codeforces 725D】Contest Balloons
time limit per test3 seconds memory limit per test256 megabytes inputstandard input outputstandard o ...
- ansible核心模块playbook介绍
ansible的playbook采用yaml语法,它简单地实现了json格式的事件描述.yaml之于json就像markdown之于html一样,极度简化了json的书写.在学习ansible pla ...
- TCP&IP基础概念复习
第一章概述 NII(National Information Infrastructure):国家信息基础设施 GII(Global Information Infrastructure):全球信息基 ...
- 【一起学源码-微服务】Nexflix Eureka 源码八:EurekaClient注册表抓取 精妙设计分析!
前言 前情回顾 上一讲 我们通过单元测试 来梳理了EurekaClient是如何注册到server端,以及server端接收到请求是如何处理的,这里最重要的关注点是注册表的一个数据结构:Concurr ...
- HashMap、Hashtable、LinkedHashMap、TreeMap、ConcurrentHashMap的区别
Map是Java最常用的集合类之一.它有很多实现类,我总结了几种常用的Map实现类,如下图所示.本篇文章重点总结几个Map实现类的特点和区别: 特点总结: 实现类 HashMap LinkedHash ...
- The fourth day of Crawler learning
爬取58同城 from bs4 import BeautifulSoupimport requestsurl = "https://qd.58.com/diannao/35200617992 ...