数组排序算法
一、冒泡排序
原理:元素两两比较,交换位置,大元素往后放,经过一轮轮比较,每次都少比一次,每次最大的元素就会出现在最大索引处。
public class SortDemo01 {
public static void main(String[] args) {
int[] arr={10,101,20,9,901};//5个数,需要比较4轮比较
//总共比较多少轮,5个数,需要比较4轮比较
for (int j = 0; j < arr.length - 1; j++) {
//每加一轮少比一次,所以每次要多减1个数j=0,1,2,3
for (int i = 0; i < arr.length -1 -j; i++) {
//两两比较
//如果前面元素比后面的大,交换位置
if (arr[i]>arr[i+1]){
int t=arr[i];
arr[i]=arr[i+1];
arr[i+1]=t;
}
System.out.println(Arrays.toString(arr));//输出数组
}
System.out.println("++++++++++++++++++++++++");
}
//System.out.println(Arrays.toString(arr));//输出数组
}
}
//输出
/*
[10, 101, 20, 9, 901]
[10, 20, 101, 9, 901]
[10, 20, 9, 101, 901]
[10, 20, 9, 101, 901]
++++++++++++++++++++++++
[10, 20, 9, 101, 901]
[10, 9, 20, 101, 901]
[10, 9, 20, 101, 901]
++++++++++++++++++++++++
[9, 10, 20, 101, 901]
[9, 10, 20, 101, 901]
+++++++++++++++++++++++
[9, 10, 20, 101, 901]
++++++++++++++++++++++++
*/
二、选择排序
原理:从0索引处开始,依次和后面的元素进行比较,小的元素前移
public class SortDemo02 {
public static void main(String[] args) {
//选择排序
//从索引为0处的元素依次和后面的元素进行比较,小的元素前移
int[] arr={80,24,69,57,5};//个数为4
//每轮比较索引+1,总共有4轮
for (int index = 0; index < arr.length-1; index++) {
//每轮比较将后一位和前一们进行比较,小的提前
/*
第一轮:比较4次
第二轮:比较3次
第三轮:比较2次
第四轮:比较1次
*/
for (int i = 1+index; i < arr.length; i++) {
if(arr[index]>arr[i]){
int t=arr[index];
arr[index]=arr[i];
arr[i]=t;
}
System.out.println(Arrays.toString(arr));
}
System.out.println("+++++++++++++++++++++++++++++");
}
}
}
//输出
/*
[24, 80, 69, 57, 5]
[24, 80, 69, 57, 5]
[24, 80, 69, 57, 5]
[5, 80, 69, 57, 24]
+++++++++++++++++++++++++++++
[5, 69, 80, 57, 24]
[5, 57, 80, 69, 24]
[5, 24, 80, 69, 57]
+++++++++++++++++++++++++++++
[5, 24, 69, 80, 57]
[5, 24, 57, 80, 69]
+++++++++++++++++++++++++++++
[5, 24, 57, 69, 80]
+++++++++++++++++++++++++++++
*/
三、直接插入排序
原理:从索引1开始,将元素一个个插入到之前的有序表中,使之仍然有序.
从索引用1开始,每个数和前面的数比较,比其小的数就插入其前面,比他大的数不变
import java.util.Arrays;
public class SortDemo04 {
public static void main(String[] args) {
//直接插入排序
int[] arr={46,55,13,42,17,94,5,70};
Sort(arr);
}
private static void Sort(int[] arr) {
for (int i = 1; i < arr.length; i++) {
int j=i;
while(j>0&&arr[j]<arr[j-1]){
int t=arr[j-1];
arr[j-1]=arr[j];
arr[j]=t;
j--;
System.out.println(Arrays.toString(arr));
}
System.out.println("第"+i+"轮排序最终结果"+Arrays.toString(arr));
System.out.println("===============================");
}
}
}
/*
第1轮排序最终结果[46, 55, 13, 42, 17, 94, 5, 70]
===============================
[46, 13, 55, 42, 17, 94, 5, 70]
[13, 46, 55, 42, 17, 94, 5, 70]
第2轮排序最终结果[13, 46, 55, 42, 17, 94, 5, 70]
===============================
[13, 46, 42, 55, 17, 94, 5, 70]
[13, 42, 46, 55, 17, 94, 5, 70]
第3轮排序最终结果[13, 42, 46, 55, 17, 94, 5, 70]
===============================
[13, 42, 46, 17, 55, 94, 5, 70]
[13, 42, 17, 46, 55, 94, 5, 70]
[13, 17, 42, 46, 55, 94, 5, 70]
第4轮排序最终结果[13, 17, 42, 46, 55, 94, 5, 70]
===============================
第5轮排序最终结果[13, 17, 42, 46, 55, 94, 5, 70]
===============================
[13, 17, 42, 46, 55, 5, 94, 70]
[13, 17, 42, 46, 5, 55, 94, 70]
[13, 17, 42, 5, 46, 55, 94, 70]
[13, 17, 5, 42, 46, 55, 94, 70]
[13, 5, 17, 42, 46, 55, 94, 70]
[5, 13, 17, 42, 46, 55, 94, 70]
第6轮排序最终结果[5, 13, 17, 42, 46, 55, 94, 70]
===============================
[5, 13, 17, 42, 46, 55, 70, 94]
第7轮排序最终结果[5, 13, 17, 42, 46, 55, 70, 94]
===============================
*/
四、希尔排序
原理:是对直接插入排序的优化,通过设置增量(步长),对相同步长间隔的元素进行比较,然后不断缩减增量,最终使增量为1,完成排序。
直接插入排序可以看成增量为1的希尔排序。
举例:设增量从4开始缩减
import java.util.Arrays;
public class SortDemo04 {
public static void main(String[] args) {
//希尔排序
int[] arr={46,55,13,42,17,94,5,70};
shellSort(arr);
}
//希尔排序是对直接插入排序的优化,通过设置增量(步长),
//对相同步长间隔的元素进行比较,然后不断缩减增量,最终使增量为1,完成排序。
//直接插入排序可以看成增量为1的希尔排序。
private static void shellSort(int[] arr) {
int h=4;//增量
System.out.println("增量:4");
for (int i = h; i < arr.length; i++) {
int j=i;
while(j>h-1&&arr[j]<arr[j-h]){
int t=arr[j-h];
arr[j-h]=arr[j];
arr[j]=t;
j-=h;
System.out.println(Arrays.toString(arr));
}
System.out.println("第"+(i-h+1)+"轮排序最终结果"+Arrays.toString(arr));
System.out.println("===============================");
}
System.out.println("**");
System.out.println("**");
System.out.println("**");
System.out.println("**");
System.out.println("**");
h=2;//增量
System.out.println("增量:2");
for (int i = h; i < arr.length; i++) {
int j=i;
while(j>h-1&&arr[j]<arr[j-h]){
int t=arr[j-h];
arr[j-h]=arr[j];
arr[j]=t;
j-=h;
System.out.println(Arrays.toString(arr));
}
System.out.println("第"+(i-h+1)+"轮排序最终结果"+Arrays.toString(arr));
System.out.println("===============================");
}
System.out.println("**");
System.out.println("**");
System.out.println("**");
System.out.println("**");
System.out.println("**");
h=1;//增量
System.out.println("增量:1");
for (int i = h; i < arr.length; i++) {
int j=i;
while(j>h-1&&arr[j]<arr[j-h]){
int t=arr[j-h];
arr[j-h]=arr[j];
arr[j]=t;
j-=h;
System.out.println(Arrays.toString(arr));
}
System.out.println("第"+(i-h+1)+"轮排序最终结果"+Arrays.toString(arr));
System.out.println("===============================");
}
}
}
/*
增量:4
[17, 55, 13, 42, 46, 94, 5, 70]
第1轮排序最终结果[17, 55, 13, 42, 46, 94, 5, 70]
===============================
第2轮排序最终结果[17, 55, 13, 42, 46, 94, 5, 70]
===============================
[17, 55, 5, 42, 46, 94, 13, 70]
第3轮排序最终结果[17, 55, 5, 42, 46, 94, 13, 70]
===============================
第4轮排序最终结果[17, 55, 5, 42, 46, 94, 13, 70]
===============================
**
**
**
**
**
增量:2
[5, 55, 17, 42, 46, 94, 13, 70]
第1轮排序最终结果[5, 55, 17, 42, 46, 94, 13, 70]
===============================
[5, 42, 17, 55, 46, 94, 13, 70]
第2轮排序最终结果[5, 42, 17, 55, 46, 94, 13, 70]
===============================
第3轮排序最终结果[5, 42, 17, 55, 46, 94, 13, 70]
===============================
第4轮排序最终结果[5, 42, 17, 55, 46, 94, 13, 70]
===============================
[5, 42, 17, 55, 13, 94, 46, 70]
[5, 42, 13, 55, 17, 94, 46, 70]
第5轮排序最终结果[5, 42, 13, 55, 17, 94, 46, 70]
===============================
[5, 42, 13, 55, 17, 70, 46, 94]
第6轮排序最终结果[5, 42, 13, 55, 17, 70, 46, 94]
===============================
**
**
**
**
**
增量:1
第1轮排序最终结果[5, 42, 13, 55, 17, 70, 46, 94]
===============================
[5, 13, 42, 55, 17, 70, 46, 94]
第2轮排序最终结果[5, 13, 42, 55, 17, 70, 46, 94]
===============================
第3轮排序最终结果[5, 13, 42, 55, 17, 70, 46, 94]
===============================
[5, 13, 42, 17, 55, 70, 46, 94]
[5, 13, 17, 42, 55, 70, 46, 94]
第4轮排序最终结果[5, 13, 17, 42, 55, 70, 46, 94]
===============================
第5轮排序最终结果[5, 13, 17, 42, 55, 70, 46, 94]
===============================
[5, 13, 17, 42, 55, 46, 70, 94]
[5, 13, 17, 42, 46, 55, 70, 94]
第6轮排序最终结果[5, 13, 17, 42, 46, 55, 70, 94]
===============================
第7轮排序最终结果[5, 13, 17, 42, 46, 55, 70, 94]
===============================
*/
简化:可以取数组长度的一半来做为增量
import java.util.Arrays;
public class SortDemo04 {
public static void main(String[] args) {
//希尔排序
int[] arr={46,55,13,42,17,94,5,70};
shellSort(arr);
}
//希尔排序是对直接插入排序的优化,通过设置增量(步长),
//对相同步长间隔的元素进行比较,然后不断缩减增量,最终使增量为1,完成排序。
//直接插入排序可以看成增量为1的希尔排序。
private static void shellSort(int[] arr) {
for (int h = arr.length/2; h > 0; h/=2) {
System.out.println("增量:"+h);
for (int i = h; i < arr.length; i++) {
int j=i;
while(j>h-1&&arr[j]<arr[j-h]){
int t=arr[j-h];
arr[j-h]=arr[j];
arr[j]=t;
j-=h;
System.out.println(Arrays.toString(arr));
}
System.out.println("第"+(i-h+1)+"轮排序最终结果"+Arrays.toString(arr));
System.out.println("===============================");
}
System.out.println("**");
System.out.println("**");
System.out.println("**");
System.out.println("**");
System.out.println("**");
}
}
}
/*
增量:4
[17, 55, 13, 42, 46, 94, 5, 70]
第1轮排序最终结果[17, 55, 13, 42, 46, 94, 5, 70]
===============================
第2轮排序最终结果[17, 55, 13, 42, 46, 94, 5, 70]
===============================
[17, 55, 5, 42, 46, 94, 13, 70]
第3轮排序最终结果[17, 55, 5, 42, 46, 94, 13, 70]
===============================
第4轮排序最终结果[17, 55, 5, 42, 46, 94, 13, 70]
===============================
**
**
**
**
**
增量:2
[5, 55, 17, 42, 46, 94, 13, 70]
第1轮排序最终结果[5, 55, 17, 42, 46, 94, 13, 70]
===============================
[5, 42, 17, 55, 46, 94, 13, 70]
第2轮排序最终结果[5, 42, 17, 55, 46, 94, 13, 70]
===============================
第3轮排序最终结果[5, 42, 17, 55, 46, 94, 13, 70]
===============================
第4轮排序最终结果[5, 42, 17, 55, 46, 94, 13, 70]
===============================
[5, 42, 17, 55, 13, 94, 46, 70]
[5, 42, 13, 55, 17, 94, 46, 70]
第5轮排序最终结果[5, 42, 13, 55, 17, 94, 46, 70]
===============================
[5, 42, 13, 55, 17, 70, 46, 94]
第6轮排序最终结果[5, 42, 13, 55, 17, 70, 46, 94]
===============================
**
**
**
**
**
增量:1
第1轮排序最终结果[5, 42, 13, 55, 17, 70, 46, 94]
===============================
[5, 13, 42, 55, 17, 70, 46, 94]
第2轮排序最终结果[5, 13, 42, 55, 17, 70, 46, 94]
===============================
第3轮排序最终结果[5, 13, 42, 55, 17, 70, 46, 94]
===============================
[5, 13, 42, 17, 55, 70, 46, 94]
[5, 13, 17, 42, 55, 70, 46, 94]
第4轮排序最终结果[5, 13, 17, 42, 55, 70, 46, 94]
===============================
第5轮排序最终结果[5, 13, 17, 42, 55, 70, 46, 94]
===============================
[5, 13, 17, 42, 55, 46, 70, 94]
[5, 13, 17, 42, 46, 55, 70, 94]
第6轮排序最终结果[5, 13, 17, 42, 46, 55, 70, 94]
===============================
第7轮排序最终结果[5, 13, 17, 42, 46, 55, 70, 94]
===============================
*/
最终版:常常采用克努特(Kunth)间隔数列来计算最佳增量。
克努特(Kunth)间隔数列:h=3h+1--->1、4、13、40、121、364...
融合到希尔排序中,即选取h=3h+1的最大取值为增量,每次不断缩减h=(h-1)/3--->...364、121、40、13、4、1
import java.util.Arrays;
public class SortDemo04 {
public static void main(String[] args) {
//希尔排序
int[] arr={46,55,13,42,17,94,5,70,15,14,2,4,13,89};
shellSort(arr);
}
//希尔排序是对直接插入排序的优化,通过设置增量(步长),
//对相同步长间隔的元素进行比较,然后不断缩减增量,最终使增量为1,完成排序。
//直接插入排序可以看成增量为1的希尔排序。
private static void shellSort(int[] arr) {
int interval=1;//通过克努特数列来计算最佳增量取值
while(interval*3+1<=arr.length){
interval=interval*3+1;
}
for (int h = interval; h > 0; h=(h-1)/3) {
System.out.println("增量:"+h);
for (int i = h; i < arr.length; i++) {
int j=i;
while(j>h-1&&arr[j]<arr[j-h]){
int t=arr[j-h];
arr[j-h]=arr[j];
arr[j]=t;
j-=h;
System.out.println(Arrays.toString(arr));
}
System.out.println("第"+(i-h+1)+"轮排序最终结果"+Arrays.toString(arr));
System.out.println("===============================");
}
System.out.println("**");
System.out.println("**");
System.out.println("**");
System.out.println("**");
System.out.println("**");
}
}
}
/*
增量:13
**
**
**
**
**
增量:4
[17, 55, 13, 42, 46, 94, 5, 70]
第1轮排序最终结果[17, 55, 13, 42, 46, 94, 5, 70]
===============================
第2轮排序最终结果[17, 55, 13, 42, 46, 94, 5, 70]
===============================
[17, 55, 5, 42, 46, 94, 13, 70]
第3轮排序最终结果[17, 55, 5, 42, 46, 94, 13, 70]
===============================
第4轮排序最终结果[17, 55, 5, 42, 46, 94, 13, 70]
===============================
**
**
**
**
**
增量:2
[5, 55, 17, 42, 46, 94, 13, 70]
第1轮排序最终结果[5, 55, 17, 42, 46, 94, 13, 70]
===============================
[5, 42, 17, 55, 46, 94, 13, 70]
第2轮排序最终结果[5, 42, 17, 55, 46, 94, 13, 70]
===============================
第3轮排序最终结果[5, 42, 17, 55, 46, 94, 13, 70]
===============================
第4轮排序最终结果[5, 42, 17, 55, 46, 94, 13, 70]
===============================
[5, 42, 17, 55, 13, 94, 46, 70]
[5, 42, 13, 55, 17, 94, 46, 70]
第5轮排序最终结果[5, 42, 13, 55, 17, 94, 46, 70]
===============================
[5, 42, 13, 55, 17, 70, 46, 94]
第6轮排序最终结果[5, 42, 13, 55, 17, 70, 46, 94]
===============================
**
**
**
**
**
增量:1
第1轮排序最终结果[5, 42, 13, 55, 17, 70, 46, 94]
===============================
[5, 13, 42, 55, 17, 70, 46, 94]
第2轮排序最终结果[5, 13, 42, 55, 17, 70, 46, 94]
===============================
第3轮排序最终结果[5, 13, 42, 55, 17, 70, 46, 94]
===============================
[5, 13, 42, 17, 55, 70, 46, 94]
[5, 13, 17, 42, 55, 70, 46, 94]
第4轮排序最终结果[5, 13, 17, 42, 55, 70, 46, 94]
===============================
第5轮排序最终结果[5, 13, 17, 42, 55, 70, 46, 94]
===============================
[5, 13, 17, 42, 55, 46, 70, 94]
[5, 13, 17, 42, 46, 55, 70, 94]
第6轮排序最终结果[5, 13, 17, 42, 46, 55, 70, 94]
===============================
第7轮排序最终结果[5, 13, 17, 42, 46, 55, 70, 94]
===============================
*/
经测试,并不是所有的数组最佳排序算法都是用克努特序列,其步长的选择有时并不一定是最佳的,但大多数是循环调用次数最少的,相比于直接插入排序,调用少了太多,自行测试吧
五、快速排序
原理:分治法,再分区。
1.先取一个基准数,在通过基准数来进行比较
2.将比这个数大的放右边,将比这个数小的放左边
3.不断重复
实现:
1.采用挖坑填数的思想
2.先找一个基准数,一般取第一个元素
3.将这个基准数挖出,从右往左,如果遇到比基准数小的,将这个数挖出放入前一个坑中,此时坑已经变了,再变换方向
4.从左往右,如果遇到比基准数大的,将这个数挖出放入前一个坑中,此时坑已经变了,再变换方向到第二步,如此循环下去,直到坑位与上一个坑位重合,最后将基准数填入最后一个坑中
5.重选基准数,直到排序完成(通过回调的方式实现)
import java.util.Arrays;
public class SortDemo05 {
static int flag=0;
public static void main(String[] args) {
//快速排序
//1.先取一个基准数,在通过基准数来进行比较
//2.将比这个数大的放右边,将比这个数小的放左边
//3.不断重复
int[] arr={4,9,8,7,6,5,342,523};
System.out.println("原始数组"+Arrays.toString(arr));
sort(arr,0,arr.length-1);
System.out.println("最终排序结果"+Arrays.toString(arr));
}
private static void sort(int[] arr, int start, int end) {
if (start<end){
int index=getIndex(arr,start,end);
sort(arr,start,index-1);
sort(arr,index+1,end);
}
}
private static int getIndex(int[] arr, int start, int end) {
int i=start;
int j=end;
int x=arr[i];//基准数
flag++;//标志位++
while(i<j){
//从右往左,如果遇到比基准数小的,将这个数挖出放入前一个坑中,此时坑已经变了,再变换方向
while(i<j&&arr[j]>=x){
j--;//遇不到,则把j--,与前一个数继续比较
}
if (i < j) {
arr[i]=arr[j];
System.out.println("第"+flag+"轮while1"+Arrays.toString(arr));
i++;//从左边的下一位开始比,因此要++
}
//从左往右,如果遇到比基准数大的,将这个数挖出放入前一个坑中,此时坑已经变了,再变换方向
while(i<j&&arr[i]<x){
i++;
}
if (i < j) {
arr[j]=arr[i];
System.out.println("第"+flag+"轮while2"+Arrays.toString(arr));
j--;//从右边的下一位开始比,因此要++
}
}
arr[i]=x;//将基准数放到最后一个坑中
System.out.println("第"+flag+"轮"+Arrays.toString(arr));
System.out.println("index="+i);
return i;//返回最终的索引,通过+1,-1来进行回调
}
}
/*
输出结果:
原始数组[4, 9, 8, 7, 6, 5, 342, 523]
第1轮[4, 9, 8, 7, 6, 5, 342, 523]
index=0
第2轮while1[4, 5, 8, 7, 6, 5, 342, 523]
第2轮[4, 5, 8, 7, 6, 9, 342, 523]
index=5
第3轮[4, 5, 8, 7, 6, 9, 342, 523]
index=1
第4轮while1[4, 5, 6, 7, 6, 9, 342, 523]
第4轮[4, 5, 6, 7, 8, 9, 342, 523]
index=4
第5轮[4, 5, 6, 7, 8, 9, 342, 523]
index=2
第6轮[4, 5, 6, 7, 8, 9, 342, 523]
index=6
最终排序结果[4, 5, 6, 7, 8, 9, 342, 523]
*/
六、归并排序
原理:
- 先分成长度为1的子序列
- 将数组的每个元素看成是一个有序的子序列,两两归并,再两两归并,直到长度与数组长度相等,这个排序称为2路并归排序。
先分后治:分是对半分
实现思路:
- 先拆分:用递归的方式通过取中间索引不断的进行拆分,直到其长度为1,无法在拆分,
- 在拆分的最后调用归并函数,因为递归是层层调用后返回到上一层,在每次拆分到最后时进行归并,并不断的向上归并
- 归并需要创建一个临时数组,用来存放归并后的元素
import java.util.Arrays;
public class SortDemo {
public static void main(String[] args) {
//原始数组
int[] arr={10,30,2,1,0,8,7,5};
//归并测试数组,从中间分开
//int[] arr={4,5,7,8,1,2,3,6};
//拆分
charFen(arr,0,arr.length-1);
//归并测试
//guiBing(arr,0,arr.length/2-1,arr.length-1);//3为中间索引
System.out.println((Arrays.toString(arr)));
}
//是chaifen。。,打错
private static void charFen(int[] arr, int startIndex, int endIndex) {
int centerIndex=(startIndex+endIndex)/2;
if (startIndex<endIndex){
//10,30,2,1,0,8,7,5,19,29
charFen(arr,startIndex,centerIndex);
charFen(arr,centerIndex+1,endIndex);
guiBing(arr,startIndex,centerIndex,endIndex);
}
}
private static void guiBing(int[] arr, int startIndex, int centerIndex, int endIndex) {//001
//定义一个临时数组,要动态的定义数组长度,不能写死
int[] tempArr=new int[endIndex-startIndex+1];
//定义左起始索引
int i=startIndex;
//定义右数组起始索引
int j=centerIndex+1;
int index=0;//临时数组的起始索引
//比较左右两个数组的元素大小,往临时数组里放
while(i<=centerIndex && j<=endIndex){
if (arr[i]<=arr[j]){
tempArr[index]=arr[i];
i++;
System.out.println("1."+Arrays.toString(tempArr));
System.out.println("---------------------------------");
}else{
tempArr[index]=arr[j];
j++;
System.out.println("2."+Arrays.toString(tempArr));
System.out.println("---------------------------------");
}
index++;
}
//处理剩余元素
while(i<=centerIndex){
tempArr[index]=arr[i];
i++;
index++;
System.out.println("3."+Arrays.toString(tempArr));
System.out.println("---------------------------------");
}
while(j<=endIndex){
tempArr[index]=arr[j];
j++;
index++;
System.out.println("4."+Arrays.toString(tempArr));
System.out.println("---------------------------------");
}
//将临时数组的元素赋值到arr中
for (int k = 0; k < tempArr.length; k++) {
arr[k+startIndex]=tempArr[k];
}
}
}
//如果有3个数,刚好两个条件的循环会不满足,因为不对称,会调用单个条件的循环如调用3.
/*
输出
1.[10, 0]
---------------------------------
4.[10, 30]
---------------------------------
2.[2, 0, 0]
---------------------------------
3.[2, 10, 0]
---------------------------------
3.[2, 10, 30]
---------------------------------
2.[0, 0]
---------------------------------
3.[0, 1]
---------------------------------
2.[0, 0, 0, 0, 0]
---------------------------------
2.[0, 1, 0, 0, 0]
---------------------------------
3.[0, 1, 2, 0, 0]
---------------------------------
3.[0, 1, 2, 10, 0]
---------------------------------
3.[0, 1, 2, 10, 30]
---------------------------------
2.[7, 0]
---------------------------------
3.[7, 8]
---------------------------------
1.[5, 0]
---------------------------------
4.[5, 5]
---------------------------------
2.[5, 0, 0, 0]
---------------------------------
2.[5, 5, 0, 0]
---------------------------------
3.[5, 5, 7, 0]
---------------------------------
3.[5, 5, 7, 8]
---------------------------------
1.[0, 0, 0, 0, 0, 0, 0, 0, 0]
---------------------------------
1.[0, 1, 0, 0, 0, 0, 0, 0, 0]
---------------------------------
1.[0, 1, 2, 0, 0, 0, 0, 0, 0]
---------------------------------
2.[0, 1, 2, 5, 0, 0, 0, 0, 0]
---------------------------------
2.[0, 1, 2, 5, 5, 0, 0, 0, 0]
---------------------------------
2.[0, 1, 2, 5, 5, 7, 0, 0, 0]
---------------------------------
2.[0, 1, 2, 5, 5, 7, 8, 0, 0]
---------------------------------
3.[0, 1, 2, 5, 5, 7, 8, 10, 0]
---------------------------------
3.[0, 1, 2, 5, 5, 7, 8, 10, 30]
---------------------------------
[0, 1, 2, 5, 5, 7, 8, 10, 30]
*/
七、基数排序
原理:通过分配再收集的方式来进行数据排序
实现:假设有10个桶,按照最大数的位数来确定需要进行几轮排序
1.第一轮:按照个位数来将元素分别装入到每个桶中,按从前往后、从上往下的方法再取出组成新的数组
2.第二轮:按照十位数来将元素分别装入到每个桶中,按从前往后、从上往下的方法再取出组成新的数组
3.第三轮:按照百位数来将元素分别装入到每个桶中,按从前往后、从上往下的方法再取出组成新的数组
4....不断进行排序
图解第一轮的实现方式:
- 可以假设有10个桶
- 每个桶中放个位数相同的数
- 放好之后再按桶的位置和数的位置取出来组成一个新的数组
import java.util.Arrays;
public class SortDemo01 {
public static void main(String[] args) {
//基础排序:通过分配再收集的方式进行数据的排序
int[] arr={2,1,5,21,31,444,23,33,47,10,903,124,987,100};
//确定排序轮次
//获取最大值
// int turn= Max(arr);
sortArray(arr);
System.out.println(Arrays.toString(arr));
}
private static void sortArray(int[] arr) {
//定义一个二维数组,来模拟10个桶
int[][] tempArray=new int[10][arr.length];//用arr.length来代表1级数组的极限长度(个位数全为1时,则全加到一个一维数组中)
//定义一个统计数组,用来存放每个桶存放了几个数,默认为0
int[] counts=new int[10];
int max=Max(arr);
int len=String.valueOf(max).length();//返回最大值的长度,valueof:将其他类型转换成字符串类型
//System.out.println(len);//3,进行3次循环
//循环轮数
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;
//System.out.println(ys);
tempArray[ys][counts[ys]++]=arr[j];
}
int index=0;//定义一个索引
//取出桶中元素
for (int k = 0; k < counts.length; k++) {
if (counts[k]!=0){
for (int h = 0; h < counts[k]; h++) {
arr[index]=tempArray[k][h];
index++;
}
counts[k]=0;//清除上次的统计
}
}
}
}
//获取最大值
private static int Max(int[] arr) {
int max=arr[0];
for (int i = 0; i < arr.length; i++) {
if (max<arr[i]){
max=arr[i];
}
}
return max;
}
}
八、堆排序
原理:将数组按完全二叉树的结构排列,从最后一个非叶子节点开始转,转成大顶堆,将根节点的元素和最后一个元素进行交换,重新转成大顶堆,如此往复
堆排序 是利用堆这种数据结构而设计的一种排序算法,堆排序是一种选择排序。
基本实现:
- 将待排序的数列构造成一个大顶堆,此时,整个序列的最大值就是堆顶的根节点。
- 将其与末尾元素进行交换,此时末尾就是最大值
- 然后剩余n-1个元素重新构造成一人上大顶堆,这样就会得到n个元素的次大值
- 反复执行,最终可以排序为有序序列
import java.util.Arrays;
public class SortDemo02 {
public static void main(String[] args) {
int[] arr={1,0,6,7,2,3,4};
//调整为大顶堆
//toMaxHeap(arr,arr.length,1);
//sortArray(arr,);
//定义开始调整的位置
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[0];
arr[0]=arr[i];
arr[i]=t;
//换完之后,再把剩余元素调成大顶堆
toMaxHeap(arr,i,0);
}
System.out.println(Arrays.toString(arr));
}
/**
*
* @param arr 要排序的数组
* @param size 调整元素的个数
* @param index 从哪里开始调整
*/
private static void toMaxHeap(int[] arr, int size, int index) {
//获取左右子节点的索引
int leftNodeIndex=index*2+1;
int rightNodeIndex=index*2+2;
//查找最大节点所对应的索引
int maxIndex=index;
if (leftNodeIndex<size && arr[leftNodeIndex]>arr[maxIndex]){
maxIndex=leftNodeIndex;
}
if (rightNodeIndex<size && arr[rightNodeIndex]>arr[maxIndex]){
maxIndex=rightNodeIndex;
}
//调换位置,最大值节点索引变了,则说明需要进行交换
if (maxIndex!=index){
int t=arr[maxIndex];
arr[maxIndex]=arr[index];
arr[index]=t;
//考虑到对后面的影响,需要重新进行大顶堆的构造
toMaxHeap(arr,size,maxIndex);
}
System.out.println(Arrays.toString(arr));
}
}
本文来自博客园,作者:一只快乐的小67,转载请注明原文链接:https://www.cnblogs.com/sp520/p/15668518.html