一、冒泡排序(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实现)的更多相关文章

  1. 十大排序算法总结(Python3实现)

    十大排序算法总结(Python3实现) 本文链接:https://blog.csdn.net/aiya_aiya_/article/details/79846380 目录 一.概述 二.算法简介及代码 ...

  2. Algorithm --> 十大排序算法

    十大排序算法 主要排序法有:  一.冒泡( Bubble)排序—— 相邻交换  二.选择排序 ——每次最小/ 大排在相应的位置  三.插入排序 ——将下一个插入已排好的序列中  四.壳( Shell) ...

  3. [ 转载 ] js十大排序算法:冒泡排序

    js十大排序算法:冒泡排序  http://www.cnblogs.com/beli/p/6297741.html

  4. 十大排序算法JavaScript实现总结

    花费了几周的时间断断续续的练习和模仿与使用JavaScript代码实现了十大排序算法. 里面有每种算法的动图和静态图片演示,看到图片可以自己先按照图片的思路实现一下. github中正文链接,点击查看 ...

  5. 一篇夯实一个知识点系列--python实现十大排序算法

    写在前面 排序是查找是算法中最重要的两个概念,我们大多数情况下都在进行查找和排序.科学家们穷尽努力,想使得排序和查找能够更加快速.本篇文章用Python实现十大排序算法. 干货儿 排序算法从不同维度可 ...

  6. 使用 js 实现十大排序算法: 快速排序

    使用 js 实现十大排序算法: 快速排序 QuickSort 快速排序 /** * * @author xgqfrms * @license MIT * @copyright xgqfrms * @c ...

  7. 使用 js 实现十大排序算法: 桶排序

    使用 js 实现十大排序算法: 桶排序 桶排序 refs xgqfrms 2012-2020 www.cnblogs.com 发布文章使用:只允许注册用户才可以访问!

  8. 使用 js 实现十大排序算法: 计数排序

    使用 js 实现十大排序算法: 计数排序 计数排序 refs xgqfrms 2012-2020 www.cnblogs.com 发布文章使用:只允许注册用户才可以访问!

  9. 使用 js 实现十大排序算法: 基数排序

    使用 js 实现十大排序算法: 基数排序 基数排序 refs xgqfrms 2012-2020 www.cnblogs.com 发布文章使用:只允许注册用户才可以访问!

  10. 使用 js 实现十大排序算法: 冒泡排序

    使用 js 实现十大排序算法: 冒泡排序 冒泡排序 refs xgqfrms 2012-2020 www.cnblogs.com 发布文章使用:只允许注册用户才可以访问!

随机推荐

  1. POJ2763 Housewife Wind 树链剖分 边权

    POJ2763 Housewife Wind 树链剖分 边权 传送门:http://poj.org/problem?id=2763 题意: n个点的,n-1条边,有边权 修改单边边权 询问 输出 当前 ...

  2. 用sublime 3搭建php 运行环境

    1.首先把php加入到环境变量中 2.第二步是打开sblime tools->build system->build new system 然后在打开的文件写上 { "cmd&q ...

  3. python scrapy爬取前程无忧招聘信息

    使用scrapy框架之前,使用以下命令下载库: pip install scrapy -i https://pypi.tuna.tsinghua.edu.cn/simple 1.创建项目文件夹 scr ...

  4. Django的安装命令

    国内的一些pipy镜像源: 1.清华源: https://pypi.tuna.tsinghua.edu.cn/simple 2.豆瓣源: https://pypi.douban.com/simple ...

  5. 三句话说清楚ssh端口转发

    看了下自己以前的笔记发现也没有完全搞清楚, 网上好多文章都是抄来抄去,远程端口转发全都是拿127.0.0.1举例 总结了下,三句话就可以讲清楚了   1 ssh本地端口转发是 把ssh服务器可以访问到 ...

  6. FactoryMethodPattern(工厂方法模式)-----Java/.Net

    也就是工厂方法(FactoryMethod)模式允许将产品类的实例化推迟到具体的创建者子类,由创建者子类决定实例化哪一个产品类.我们同样以汽车的生产作为讲解该模式的例子,因为汽车生产从宏观上来说也是特 ...

  7. 「分块系列」「洛谷P4168 [Violet]」蒲公英 解题报告

    蒲公英 Description 我们把所有的蒲公英看成一个长度为\(n\)的序列(\(a_1,a_2,...a_n\)),其中\(a_i\)为一个正整数,表示第i棵蒲公英的种类的编号. 每次询问一个区 ...

  8. 「洛谷P1198」 [JSOI2008]最大数 解题报告

    P1198 [JSOI2008]最大数 题目描述 现在请求你维护一个数列,要求提供以下两种操作: 1. 查询操作. 语法:Q L 功能:查询当前数列中末尾L个数中的最大的数,并输出这个数的值. 限制: ...

  9. React Native 性能优化指南【全网最全,值得收藏】

    2020 年谈 React Native,在日新月异的前端圈,可能算比较另类了.文章动笔之前我也犹豫过,但是想到写技术文章又不是赶时髦,啥新潮写啥,所以还是动笔写了这篇 React Native 性能 ...

  10. linux各目录及重要目录的详细介绍

    1 目录说明 根目录 (/) /bin bin是Binary的缩写, 这个目录存放着最经常使用的命令,比如ls,cat,mkdir等 /dev dev是Device(设备)的缩写, 该目录下存放的是L ...