![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/d3e491e19c6488dd536ec99d345cfd9b.png)
1、冒泡排序
冒泡排序原理:相邻元素两两比较,大的往后放,第一次完毕,最大值出现在了最大索引处
冒泡排序图解:
代码演示:
package 八大排序;
import java.util.Arrays;
public class 冒泡排序 {
public static void main(String[] args) {
//冒泡排序的原理:相邻元素两两比较,大的往后放,第一次完毕,最大值出现在了最大索引处
int[] arr={4,21,5,86,74,12};
//外层循环次数是数组长度减一,从索引0开始
for (int i = 0; i < arr.length-1; i++) {
//里层循环次数是数组长度减第几轮循环
for (int j = 0; j < arr.length-1-i; j++) {
if(arr[j]>arr[j+1]){
int t=arr[j];
arr[j]=arr[j+1];
arr[j+1]=t;
}
}
}
System.out.println(Arrays.toString(arr));
}
}
2、选择排序
选择排序原理:从0索引开始,依次和后面元素比较,小的往前放,第一次完毕,最小值出现在了最小索引处
选择排序图解:
代码实现:
package 八大排序;
import java.util.Arrays;
public class 选择排序 {
public static void main(String[] args) {
//选择排序原理:从0索引开始,依次和后面元素比较,小的往前放,第一次完毕,最小值出现在了最小索引处
int[] arr={4,21,5,86,74,12};
//外层循环次数是数组长度减一,从索引0开始
for (int i = 0; i < arr.length-1; i++) {
//里层循环次数是数组长度减第几轮循环
for (int j = i+1; j < arr.length; j++) {
if(arr[i]>arr[j]){
int t=arr[i];
arr[i]=arr[j];
arr[j]=t;
}
}
}
System.out.println(Arrays.toString(arr));
}
}
3、直接插入排序
直接插入排序原理:从1索引处开始,将后面的元素插入到之前的有序列表中,使之仍保持有序
直接插入排序图解:
代码演示:
package 八大排序;
import java.util.Arrays;
public class 直接插入排序 {
public static void main(String[] args) {
//直接插入排序的原理:从1索引处开始,将后面的元素插入到之前的有序列表中,使之仍保持有序
int[] arr={4,21,5,86,74,12};
//外层循环次数是数组长度减一,从索引1开始
for (int i = 1; i < arr.length; i++) {
//里层循环进行比较插入
while (arr[i]<arr[i-1]){
int t=arr[i];
arr[i]=arr[i-1];
arr[i-1]=t;
//让i自减,可以使它继续和前面的元素进行比较,加上判断条件,是为了防止索引越界
if(i>1){
i--;
}
}
}
System.out.println(Arrays.toString(arr));
}
}
4、希尔排序
希尔排序原理:他是对插入排序的一个优化,核心的思想就是合理的选取增量,经过一轮排序后,就会让序列大致有序,然后再不断地缩小增量,进行插入排序,直到增量为 1,那整个排序结束
希尔排序图解:
代码演示:
package 八大排序;
import java.util.Arrays;
public class 希尔排序 {
public static void main(String[] args) {
//希尔排序原理:他是对插入排序的一个优化,核心的思想就是合理的选取增量,经过一轮排序后,就会让序列大致有序
//然后再不断地缩小增量,进行插入排序,直到增量为 1,那整个排序结束
int[] arr={4,21,5,86,74,12,57,42};
//增量的大小最好定义为数组长度的一半,然后不断减半,直至为1
for(int h=arr.length/2;h>0;h/=2){
//里层循环次数=数组长度 - 增量大小
for (int i=h;i<arr.length;i++){
//里层循环次数=j/h,保证和间隔h的数比较后,再和间隔h的数进行比较,已达到有序的目的,例如:此时h=2,j=4,索引4的数和索引2的数比较后,继续和索引0的数进行比较,已达到有序的目的
for(int j=i;j>h-1;j-=h){
if(arr[j]<arr[j-h]){
int t=arr[j];
arr[j]=arr[j-h];
arr[j-h]=t;
}
}
}
}
System.out.println(Arrays.toString(arr));
}
}
5、快速排序
快速排序原理:分治法:比大小,再分区
实现步骤:
1.从数组中取出一个数,作为基准数
2.分区:将比这个数大的数放在它的右边,比它小的数放在它的左边(挖坑填数的思想)
挖坑填数思想:
(1):用基准数挖出形成第一个坑
(2):由后向前找比它小的数,找到后挖出此数填到前一个坑中
(3):由前向后找比它大或等于它的数,找到后挖出此数填到前一个坑中
3.再对左右区间重复第二步,直到各区间只有一个数(用递归方法实现)
快速排序图解:
代码演示:
package 八大排序;
import java.util.Arrays;
public class 快速排序 {
public static void main(String[] args) {
int[] arr = {4,21,5,86,74,12,57,42};
quickSort(arr, 0, arr.length - 1);
System.out.println(Arrays.toString(arr));
}
public static void quickSort(int[] arr, int start, int end) {
if (start < end) {
//获取分区索引
int index = getIndex(arr, start, end);
//对左右两个分区 再进行同样的步骤 ,即是递归调用
quickSort(arr, start, index - 1);//左半部分
quickSort(arr, index + 1, end);//右半部分
}
}
private static int getIndex(int[] arr, int start, int end) {
int i = start;
int j = end;
//定义基准数
int x = arr[i];
//循环
while (i < j) {
//从右往左比较,找出比基准数小的数
while (i < j && arr[j] >= x) {
j--;
}
//从右往左找到比基准数小的数了后,填坑
if (i < j) {
// 找比基准数小的数,填到基准数的坑位上
arr[i] = arr[j];
//让 i++,准备从左找比基准数大的数
i++;
}
//从左往右找,找比基准数大的数
while (i < j && arr[i] < x) {
i++;
}
// 找比基准数大的数,找到后填到上一个坑
if (i < j){
arr[j] = arr[i];
//让 j--,准备下一次循环
j--;
}
}
//当上面的循环结束后把基准数填到最后一个坑位,也就以基准数为界,分成了左右两部分
arr[i] = x; //把基准数填进去
return i; //返回基准数所在位置的索引
}
}
//基准数的左边没有数,不用进行再分区,基准数的右边进行再分区,
6、归并排序
归并排序原理:假设初始序列有N个记录,则可以看成是N个有序的子序列(拆分思想,递归实现),每个子序列的长度是1,然后两两归并,得到N/2个长度为2或1的有序子序列,再两两归并…如此重复,直到一个长度为N的有序子序列为止
归并排序图解:
代码演示:
package 八大排序;
import java.util.Arrays;
public class 归并排序 {
public static void main(String[] args) {
int[] arr = {4,21,5,86,74,12,57,42};
chaiFen(arr,0,arr.length-1);
System.out.println(Arrays.toString(arr));
}
private static void chaiFen(int[] arr, int start, int end) {
if(start<end){
int center=(start+end)/2;
chaiFen(arr,start,center);
chaiFen(arr,center+1,end);
heBing(arr,start,center,end);
}
}
private static void heBing(int[] arr, int start, int center, int end) {
//定义一个临时数组
int[] arr2 = new int[end - start + 1];
//定义左边数组的起始索引
int i=start;
//定义右边数组的起始索引
int j=center+1;
//定义临时数组的起始索引
int index=0;
//比较左右两个数组的元素大小,往临时数组里加
while (i<=center&&j<=end){
//左小右大,临时数组加左边的数,同时左边数组索引自增一下,让左边下一个数继续和右边的数进行比较
if(arr[i]<=arr[j]){
arr2[index]=arr[i];
i++;
}else { //反之,左大右小,临时数组加右边的数,同时右边索引自增一下,让右边下一个数继续和左边的数进行比较
arr2[index]=arr[j];
j++;
}
//让临时数组的索引也进行自增,保证临时数组每个索引都有值
index++;
}
//处理左边剩余元素
while (i<=center){
arr2[index]=arr[i];
i++;
index++;
}
//处理右边剩余元素
while (j<=end){
arr2[index]=arr[j];
j++;
index++;
}
//将临时数组的元素装到原数组中
for (int i1 = 0; i1 < arr2.length; i1++) {
arr[i1+start]=arr2[i1];
}
}
}
7、基数排序
基数排序原理:基数排序属于分配式排序,又称桶子法,通过分配再收集的方法进行排序,属于稳定式排序。
基数排序图解:
代码演示:
package 八大排序;
import java.util.Arrays;
public class 基数排序 {
public static void main(String[] args) {
//基数排序:通过分配再收集的方法进行排序
int[] arr = {4,21,5,86,74,12,57,42};
//用来装数的桶
int[][] arr2 = new int[10][arr.length];
//定义统计数组
int[] arr3 = new int[10];
int max=0;
for (int i : arr) {
max=max>i?max:i;
}
//求出最大数是几位数,并将最大数传给排序方法
int len = String.valueOf(max).length();
//参一:原始数组 参二:用来装数的桶(二维数组) 参三:统计数组 参四:原始数组中最大的数的位数
sort(arr, arr2, arr3, len);
System.out.println(Arrays.toString(arr));
}
private static void sort(int[] arr, int[][] arr2, int[] arr3, int len) {
//最大数是几位数,外层装桶几次
for (int i = 0,n=1; i < len; i++,n*=10) {
for (int j = 0; j < arr.length; j++) {
int ys=arr[j]/n%10;
//给对应的桶中装数
arr2[ys][arr3[ys]++]=arr[j];
}
//将桶中的数拿出来
int index=0;
for (int h = 0; h < arr3.length; h++) {
//统计数组的元素不为零,再将桶中的数拿出来
if(arr3[h]!=0){
//统计数组中元素的大小是多少,则遍历几次,将对应桶中的元素全部拿出来
for (int k = 0; k < arr3[h]; k++) {
arr[index]=arr2[h][k];
index++;
}
//将统计数组清零,准备下一次装桶
arr3[h]=0;
}
}
}
}
}
8、堆排序
堆排序原理:堆排序是指利用堆这种数据结构所设计的一种排序算法。堆积是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。
堆排序图解:
代码演示:
package 八大排序;
import java.util.Arrays;
public class 堆排序 {
public static void main(String[] args) {
//堆排序原理:堆排序是指利用堆这种数据结构所设计的一种排序算法。堆积是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。
//大顶堆:arr[i]>=arr[i*2+1]&&arr[i]>=arr[i*2+2]
//小顶堆:arr[i]<=arr[i*2+1]&&arr[i]<=arr[i*2+2]
int[] arr = {4,21,5,86,74,12,57,42};
//求出最大的非叶子节点的索引
int startIndex=(arr.length-1)/2;
//循环开始调,最大的非叶子节点多大,则循环几次,从最大的非叶子节点开始调
for (int i = startIndex; i >=0; i--) {
toMaxheap(arr,arr.length,i);
}
//以上的运行结果已经达到大顶堆的效果,此时只需将根节点的元素与最后一个叶子节点的元素互换就行,并递归将剩余元素继续转化成大顶堆
for (int i = arr.length-1; i > 0; i--) {
int t=arr[i];
arr[i]=arr[0];
arr[0]=t;
//将剩余元素继续转化为大顶堆结构
toMaxheap(arr,i,0);
}
System.out.println(Arrays.toString(arr));
}
/**
*
* @param arr //要进行排序的数组
* @param size //要排序的范围
* @param startIndex //起始的索引位置
*/
private static void toMaxheap(int[] arr, int size, int startIndex) {
//求出左右节点的索引
int leftNodeIndex=startIndex*2+1;
int rightNodeIndex=startIndex*2+2;
//假设刚开始最大数的索引就是起始索引
int maxIndex=startIndex;
//求出最大节点所对应的索引
if(leftNodeIndex<size&&arr[leftNodeIndex]>arr[maxIndex]){
maxIndex=leftNodeIndex;
}
if(rightNodeIndex<size&&arr[rightNodeIndex]>arr[maxIndex]){
maxIndex=rightNodeIndex;
}
//调换位置,将最大节点放在大顶堆的根节点处
if(maxIndex!=startIndex){
int t=arr[startIndex];
arr[startIndex]=arr[maxIndex];
arr[maxIndex]=t;
//互换完之后可能会影响最大节点以下的大顶堆结构,所以这里需要递归调用方法,保证每个子树都是大顶堆结构
toMaxheap(arr,size,maxIndex);
}
}
}