八大排序算法
时间复杂度
各种排序算法的时间复杂度
空间复杂度
冒泡排序
图解冒泡排序算法的过程
总结:一趟排序可以确定一个最大值
第一趟排序:可以把最大的值确定下来
冒泡排序应用实例
冒泡排序时间复杂度O(n^2)
未优化的冒泡排序代码
public class BubbleSort {
public static void main(String[] args) {
int[] arr={3,9,-1,10,-2};
//冒泡排序的时间复杂度O(n^2)
int temp=0;//临时变量,用来做交换
System.out.println("------------------------");
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]){//改从大到小改这个
temp=arr[j];
arr[j]=arr[j+1];
arr[j+1]=temp;
}
}
System.out.println("第"+(i+1)+"趟排序后的数组:");
System.out.println(Arrays.toString(arr));
}
//为了容易理解,我们把冒泡排序的演变过程展示出来
/*//第一趟排序就是将最大的数排在最后
int temp=0;//临时变量,用来做交换
for (int i = 0; i < arr.length-1-0; i++) {
//如果前面的数比后面的大,则交换
if(arr[i]>arr[i+1]){
temp=arr[i];
arr[i]=arr[i+1];
arr[i+1]=temp;
}
}
System.out.println("第一趟排序后的数组:");
System.out.println(Arrays.toString(arr));
//第二趟排序,就是将第二大的数排在倒数第二位
for (int i = 0; i < arr.length-1-1; i++) {
//如果前面的数比后面的大,则交换
if(arr[i]>arr[i+1]){
temp=arr[i];
arr[i]=arr[i+1];
arr[i+1]=temp;
}
}
System.out.println("第二趟排序后的数组:");
System.out.println(Arrays.toString(arr));
//第三趟排序,就是将第三大的数排在倒数第三位
for (int i = 0; i < arr.length-1-2; i++) {
//如果前面的数比后面的大,则交换
if(arr[i]>arr[i+1]){
temp=arr[i];
arr[i]=arr[i+1];
arr[i+1]=temp;
}
}
System.out.println("第三趟排序后的数组:");
System.out.println(Arrays.toString(arr));
//第四趟排序,就是将第四大的数排在倒数第四位
for (int i = 0; i < arr.length-1-3; i++) {
//如果前面的数比后面的大,则交换
if(arr[i]>arr[i+1]){
temp=arr[i];
arr[i]=arr[i+1];
arr[i+1]=temp;
}
}
System.out.println("第四趟排序后的数组:");
System.out.println(Arrays.toString(arr));*/
}
}
优化后的冒泡排序代码
public class BubbleSort {
public static void main(String[] args) {
int[] arr={3,9,-1,10,20};
//冒泡排序的时间复杂度O(n^2)
int temp=0;//临时变量,用来做交换
boolean flag=false;//标识变量,表示是否进行过交换
System.out.println("------------------------");
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]){
flag=true;
temp=arr[j];
arr[j]=arr[j+1];
arr[j+1]=temp;
}
}
System.out.println("第"+(i+1)+"趟排序后的数组:");
System.out.println(Arrays.toString(arr));
if(!flag){//说明在一趟排序中,一次交换都没有发生过
break;
}else{
flag=false;//重置flag进行下次判断,必须要进行重置,否则会出问题
}
}
}
}
选择排序
public class SelectSort {
public static void main(String[] args) {
//int[] arr={101,34,119,1,-1,90,123};
int[] arr=new int[80000];
for (int i = 0; i <80000 ; i++) {
arr[i]=(int)(Math.random()*8000000);//生成一个[0,8000000)之间的数
}
//System.out.println(Arrays.toString(arr));
System.out.println("-------------------");
Date date1=new Date();
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String date1Str=simpleDateFormat.format(date1);
System.out.println("排序前的时间:"+date1Str);
long start=System.currentTimeMillis();
selectSort(arr);
long end=System.currentTimeMillis();
System.out.println(end-start);
Date date2=new Date();
String date2Str=simpleDateFormat.format(date2);
System.out.println("排序后的时间:"+date2Str);
}
//选择排序
public static void selectSort(int[] arr){
//选择排序:时间复杂度O(n^2)
for (int i = 0; i < arr.length-1; i++) {
int minIndex=i;
int min=arr[i];
for (int j = i+1; j <arr.length ; j++) {
if(min>arr[j]){//说明假定的最小值并不是最小 //改从大到小改这个
min=arr[j];//重置最小值
minIndex=j;//重置minindex
}
}
if(minIndex!=i){
//找到了最小值,进行交换
arr[minIndex]=arr[i];
arr[i]=min;
}
/*System.out.println("第"+(i+1)+"轮之后的数组:");
System.out.println(Arrays.toString(arr));*/
}
//使用逐步推导的方式
//原始数组:101,34,119,1
//第一轮:1,34,119,101
//算法:先简单后复杂,复杂问题简单化---》逐步解决
/*//第一轮
int minIndex=0;
int min=arr[0];
for (int j = 0+1; j <arr.length ; j++) {
if(min>arr[j]){//说明假定的最小值并不是最小
min=arr[j];//重置最小值
minIndex=j;//重置minindex
}
}
if(minIndex!=0){
//找到了最小值,进行交换
arr[minIndex]=arr[0];
arr[0]=min;
}
System.out.println("第一轮之后的数组:");
System.out.println(Arrays.toString(arr));
//第二轮:
minIndex=1;
min=arr[1];
for (int j = 1+1; j <arr.length ; j++) {
if(min>arr[j]){//说明假定的最小值并不是最小
min=arr[j];//重置最小值
minIndex=j;//重置minindex
}
}
if(minIndex!=1){
//找到了最小值,进行交换
arr[minIndex]=arr[1];
arr[1]=min;
}
System.out.println("第二轮之后的数组:");
System.out.println(Arrays.toString(arr));
//第三轮:
minIndex=2;
min=arr[2];
for (int j = 2+1; j <arr.length ; j++) {
if(min>arr[j]){//说明假定的最小值并不是最小
min=arr[j];//重置最小值
minIndex=j;//重置minindex
}
}
if(minIndex!=2){
//找到了最小值,进行交换
arr[minIndex]=arr[2];
arr[2]=min;
}
System.out.println("第三轮之后的数组:");
System.out.println(Arrays.toString(arr));*/
}
}
选择排序的时间比冒泡排序要少较多
80000个数值,冒泡大概需要20s,而选择排序只需要2s
插入排序
public class InsertSort {
public static void main(String[] args) {
//int[] arr={101,34,119,1,-1,89};
int[] arr=new int[80000];
for (int i = 0; i <80000 ; i++) {
arr[i]=(int)(Math.random()*8000000);//生成一个[0,8000000)之间的数
}
Date date1=new Date();
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String date1Str=simpleDateFormat.format(date1);
System.out.println("排序前的时间:"+date1Str);
long start=System.currentTimeMillis();
insertSort(arr);
long end=System.currentTimeMillis();
System.out.println(end-start);
Date date2=new Date();
String date2Str=simpleDateFormat.format(date2);
System.out.println("排序后的时间:"+date2Str);
}
//插入排序
public static void insertSort(int[] arr){
//使用for循环简化代码
int insertVal=0;
int insertIndex=0;
for (int i = 1; i <arr.length ; i++) {
insertVal=arr[i];
insertIndex=i-1;
while(insertIndex>=0&&insertVal<arr[insertIndex]){//改从大到小改这个
arr[insertIndex+1]=arr[insertIndex];
insertIndex--;
}
//判断是否需要赋值?
if(insertIndex+1!=i){
arr[insertIndex+1]=insertVal;
}
/*System.out.println("第"+(i)+"趟插入排序后的数组:");
System.out.println(Arrays.toString(arr));*/
}
/*//第一轮
//定义待插入的数
int insertVal=arr[1];
//定义待插入数的索引
int insertIndex=1-1;//即arr【1】前面这个数的下标
//给insertVal找到插入的位置
//1. insertIndex>=0保证找插入位置时不越界
//2. insertVal<arr[insertIndex]说明待插入的数还没有找到插入位置
//3. 需要将arr[insertIndex]后移
while(insertIndex>=0&&insertVal<arr[insertIndex]){
arr[insertIndex+1]=arr[insertIndex];
insertIndex--;
}
//当退出while循环时,说明已经找到插入位置,insertIndex+1;
arr[insertIndex+1]=insertVal;
System.out.println("第一趟插入排序后的数组:");
System.out.println(Arrays.toString(arr));
//第二轮
insertVal=arr[2];
insertIndex=2-1;
while(insertIndex>=0&&insertVal<arr[insertIndex]){
arr[insertIndex+1]=arr[insertIndex];
insertIndex--;
}
arr[insertIndex+1]=insertVal;
System.out.println("第二趟插入排序后的数组:");
System.out.println(Arrays.toString(arr));
//第三轮
insertVal=arr[3];
insertIndex=3-1;
while(insertIndex>=0&&insertVal<arr[insertIndex]){
arr[insertIndex+1]=arr[insertIndex];
insertIndex--;
}
arr[insertIndex+1]=insertVal;
System.out.println("第三趟插入排序后的数组:");
System.out.println(Arrays.toString(arr));*/
}
}
希尔排序,也称缩小增量排序
采用交换法的希尔排序
实际上就是分组套冒泡排序
public class ShellSort {
public static void main(String[] args) {
int[] arr={8,9,1,7,2,3,5,4,6,0};
shellSort(arr);
}
public static void shellSort(int[] arr){
//使用交换法
int temp=0;
int count=0;
for (int gap = arr.length/2; gap > 0; gap/=2) {
for (int i = gap; i < arr.length; i++) {
//遍历各组中所有的元素(共有gap组,每组length/gap有个元素),步长为gap
for (int j = i-gap; j >=0 ; j-=gap) {
//如果当前元素大于加上步长后的那个元素,说明需要交换
if(arr[j]>arr[j+gap]){
temp=arr[j];
arr[j]=arr[j+gap];
arr[j+gap]=temp;
}
}
}
count++;
System.out.println("希尔排序第"+count+"轮="+Arrays.toString(arr));
}
/*//使用逐步推导的方式编写shell排序
//10个数据进行三轮
//希尔排序第一轮
//第一轮将10个数据分成5组
int temp=0;
for (int i = 5; i < arr.length; i++) {
//遍历各组中所有的元素(共有5组,每组有两个元素),步长5
for (int j = i-5; j >=0 ; j-=5) {//为什么是j-=5????????
//如果当前元素大于加上步长后的那个元素,说明需要交换
if(arr[j]>arr[j+5]){
temp=arr[j];
arr[j]=arr[j+5];
arr[j+5]=temp;
}
}
}
System.out.println("希尔排序第一轮之后的情况:");
System.out.println(Arrays.toString(arr));
//第二轮将10个数据分成5/2=2组
for (int i = 2; i < arr.length; i++) {
//遍历各组中所有的元素(共有5组,每组有两个元素),步长5
for (int j = i-2; j >=0 ; j-=2) {//为什么时j-=5
//如果当前元素大于加上步长后的那个元素,说明需要交换
if(arr[j]>arr[j+2]){
temp=arr[j];
arr[j]=arr[j+2];
arr[j+2]=temp;
}
}
}
System.out.println("希尔排序第二轮之后的情况:");
System.out.println(Arrays.toString(arr));
//第三轮将10个数据分成2/2=1组
for (int i = 1; i < arr.length; i++) {
//遍历各组中所有的元素(共有5组,每组有两个元素),步长5
for (int j = i-1; j >=0 ; j-=1) {//为什么时j-=5
//如果当前元素大于加上步长后的那个元素,说明需要交换
if(arr[j]>arr[j+1]){
temp=arr[j];
arr[j]=arr[j+1];
arr[j+1]=temp;
}
}
}
System.out.println("希尔排序第三轮之后的情况:");
System.out.println(Arrays.toString(arr));*/
}
}
采用移动法的希尔排序
实际上是分组套插入排序
public class ShellSort {
public static void main(String[] args) {
/*int[] arr={8,9,1,7,2,3,5,4,6,0};
shellSort2(arr);*/
int[] arr=new int[80000];
for (int i = 0; i <80000 ; i++) {
arr[i]=(int)(Math.random()*8000000);//生成一个[0,8000000)之间的数
}
Date date1=new Date();
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String date1Str=simpleDateFormat.format(date1);
System.out.println("排序前的时间:"+date1Str);
long start=System.currentTimeMillis();
shellSort2(arr);
long end=System.currentTimeMillis();
System.out.println("耗时:"+(end-start));
Date date2=new Date();
String date2Str=simpleDateFormat.format(date2);
System.out.println("排序后的时间:"+date2Str);
}
//移位式希尔排序
public static void shellSort2(int[] arr){
int count=0;
//增量gap并逐步缩小
for (int gap = arr.length/2; gap >0 ; gap/=2) {
//从第gap个元素开始,逐个对其所在的组进行直接插入
for(int i=gap;i<arr.length;i++){
int j=i;
int temp=arr[j];
if(arr[j]<arr[j-gap]){
while(j-gap>=0&&temp<arr[j-gap]){//while循环是在找位置
//移动
arr[j]=arr[j-gap];
j-=gap;
}//当退出while循环后说明就给temp找到了插入位置
arr[j]=temp;
}
}
count++;
//System.out.println("希尔排序第"+count+"轮="+Arrays.toString(arr));
}
}
}
快速排序
package paixu;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
/**
* @author : sky
* @version : 1.0
*/
public class QuickSort {
public static void main(String[] args) {
int[] arr={-9,78,0,23,-567,70,-1,900,4561};
/*int[] arr=new int[8000000];
for (int i = 0; i <8000000 ; i++) {
arr[i]=(int)(Math.random()*8000000);//生成一个[0,8000000)之间的数
}
Date date1=new Date();
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String date1Str=simpleDateFormat.format(date1);
System.out.println("排序前的时间:"+date1Str);
long start=System.currentTimeMillis();*/
quickSort(arr,0,arr.length-1);
/*long end=System.currentTimeMillis();
System.out.println("耗时:"+(end-start));
Date date2=new Date();
String date2Str=simpleDateFormat.format(date2);
System.out.println("排序后的时间:"+date2Str);*/
System.out.println("快速排序");
System.out.println(Arrays.toString(arr));
}
//快速排序
/**
*
* @param arr arr传进来的数组
* @param left left指针,指向数组的最左边的值
* @param right right指针,指向数组的最右边的值
*/
public static void quickSort(int[] arr,int left,int right){
int l=left;//左下标,即左边的索引
int r=right;//右下标,即右边的索引
int pivot=arr[(left+right)/2];//中间的基准值,即中轴值
int temp=0;//临时变量,交换时使用
//while循环的目的,是让比中轴值小的放到左边,比中轴值大的放到右边
while(l<r){
//在pivot左边一直找,找到大于等于pivot的值,才退出
while(arr[l]<pivot){
l+=1;
}
//在pivot右边一直找,找到小于等于pivot的值,才退出
while(arr[r]>pivot){
r-=1;
}
//如果l>=r说明pivot的左右两边的值,已经按照左边全部是小于等于pivot的值,右边全部是大于等于pivot的值
if(l>=r){
//如果满足这个条件的话就说明循环可以退出
break;
}
//开始交换
temp=arr[l];
arr[l]=arr[r];
arr[r]=temp;
//这里的控制不太明白???????
//如果交换完之后发现arr[l]==pivot值相等,需要r--,相当于前移
if(arr[l]==pivot){
r-=1;
}
//如果交换完之后发现arr[r]==pivot值相等,需要l++,相当于后移
if(arr[r]==pivot){
l+=1;
}
}
//如果l==r,必须l++,r--,否则会出现栈溢出
if(l==r){
l+=1;
r-=1;
}
//向左递归
if(left<r){
quickSort(arr,left,r);
}
//向右递归
if(right>l){
quickSort(arr,l,right);
}
}
}
归并排序
实际上合并共有4+2+1=7次
package paixu;
import com.sun.scenario.effect.impl.sw.sse.SSEBlend_SRC_OUTPeer;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
/**
* @author : sky
* @version : 1.0
*/
public class MergeSort {
public static void main(String[] args) {
/*int[] arr={8,4,5,7,1,3,6,2};
int[] temp=new int[arr.length];//归并排序需要一个额外的排序
mergeSort(arr,0,arr.length-1,temp);
System.out.println("归并排序后:"+ Arrays.toString(arr));
*/
int[] arr=new int[8000000];
int[] temp=new int[arr.length];
for (int i = 0; i <8000000 ; i++) {
arr[i]=(int)(Math.random()*8000000);//生成一个[0,8000000)之间的数
}
Date date1=new Date();
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String date1Str=simpleDateFormat.format(date1);
System.out.println("排序前的时间:"+date1Str);
long start=System.currentTimeMillis();
mergeSort(arr,0,arr.length-1,temp);
long end=System.currentTimeMillis();
System.out.println("耗时:"+(end-start));
Date date2=new Date();
String date2Str=simpleDateFormat.format(date2);
System.out.println("排序后的时间:"+date2Str);
}
//合并的方法
/**
*
* @param arr arr待排序的原始数组
* @param left left左边有序序列的初始索引
* @param mid mid中间索引,即右边数组的结束索引
* @param right right右边索引
* @param temp temp做中转的数组
*/
public static void merge(int[] arr,int left,int mid,int right,int[] temp){
//System.out.println("11");
int i=left;//初始化i,左边有序序列的初始索引
int j=mid+1;//初始化j,右边有序序列的初始索引
int t=0;//指向temp数组的当前索引
//1.先把左右两边(有序)的数据按照规则填充到temp数组,直到左右两边有序序列有一边处理完毕为止
while(i<=mid && j<=right){//只要满足这个条件就继续
//如果左边有序序列的当前元素小于等于右边有序序列的当前元素,即将左边的当前元素拷贝到temp数组中
//然后t++,i++后移
if(arr[i]<=arr[j]){
temp[t]=arr[i];
t+=1;
i+=1;
}else{//反之,将右边的当前元素拷贝到temp数组中
temp[t]=arr[j];
t+=1;
j+=1;
}
}
//2.把有剩余数据的一方一次填充到temp中
while(i<=mid){//说明左边的有序序列还有剩余元素,就全部填充到temp
temp[t]=arr[i];
t+=1;
i+=1;
}
while(j<=right){//说明右边的有序序列还有剩余元素,就全部填充到temp
temp[t]=arr[j];
t+=1;
j+=1;
}
//3.将temp数组的元素拷贝到arr原数组
//注意,并不是每次都拷贝所有数据
t=0;
int tempLeft=left;
//System.out.println("templeft="+tempLeft+" right="+right);
while(tempLeft<=right){//第一次合并时,tempLeft=0;right=1//第二次 tL=2;r=3//第三次 tL=0;r=3//第四次 tL=4;r=5
//第五次 tL=6;r=7//第六次 tL=4;r=7
//第七次最后一次才是tL=0;r=7
arr[tempLeft]=temp[t];
t+=1;
tempLeft+=1;
}
}
//分+合的方法
//归并排序
public static void mergeSort(int[] arr,int left,int right,int[] temp){
if(left<right){
int mid=(left+right)/2;//中间的索引
//向左递归进行分解
mergeSort(arr,left,mid,temp);
//向右递归进行分解
mergeSort(arr,mid+1,right,temp);
//每分解一次就合并一次
//合并
merge(arr,left,mid,right,temp);
}
}
}
基数排序(桶排序)
稳定性排序是指:如果有两数相等,那么原先在前的那个数,排序完之后仍然在前
使用基数排序对{53,3,542,748,14,214}进行升序排序
第一轮:
第二轮:
第三轮:
轮数取决于最大的数的位数
package paixu;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
/**
* @author : sky
* @version : 1.0
*/
public class RadixSort {
public static void main(String[] args) {
/*int[] arr={53,3,542,748,14,214};
radixSort(arr);*/
int[] arr=new int[8000000];
int[] temp=new int[arr.length];
for (int i = 0; i <8000000 ; i++) {
arr[i]=(int)(Math.random()*8000000);//生成一个[0,8000000)之间的数
}
Date date1=new Date();
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String date1Str=simpleDateFormat.format(date1);
System.out.println("排序前的时间:"+date1Str);
long start=System.currentTimeMillis();
radixSort(arr);
long end=System.currentTimeMillis();
System.out.println("耗时:"+(end-start));
Date date2=new Date();
String date2Str=simpleDateFormat.format(date2);
System.out.println("排序后的时间:"+date2Str);
}
//基数排序
public static void radixSort(int[] arr){
//要得到数组中最大的数的位数
int max=arr[0];//假设第一个数就是最大的数
for (int i = 1; i <arr.length ; i++) {
if(arr[i]>max){
max=arr[i];
}
}
//最大的数是几位数
int maxLength=(max+"").length();
//第一轮排序:针对每个元素的个位进行排序处理
//定义一个二位数组表示10个桶,每个桶就是一个一维数组
//说明:
//1.二位数组包含10个一维数组
//2.为了防止在放入数的时候数据溢出,每个桶(一维数组)的大小定义为arr.length
//3.基数排序是使用空间换时间的经典算法
int[][] bucket=new int[10][arr.length];
//为了记录每个桶中实际存放了多少个数据,定义一个一维数组来记录各个桶的每次放入数据的个数
//即bucketElementCount[0],记录的就是bucket[0]桶里元素的个数
int[] bucketElementCount=new int[10];
//最终代码:
for (int i = 0,n=1; i <maxLength ; i++,n*=10) {
for(int j=0;j<arr.length;j++){
//针对每个元素对应的位数进行处理,第一轮个位,第二轮十位,第三轮百位
int digitOfElement=arr[j]/ n % 10;
//放入到对应的桶中
bucket[digitOfElement][bucketElementCount[digitOfElement]]=arr[j];
bucketElementCount[digitOfElement]++;
}
//按照桶的顺序,取出数据并放入原来的数组
int index=0;
//遍历每一个桶,并将桶中的数据放入到原数组
for(int k=0;k<bucket.length;k++){
//如果桶中有数据,才取出到原数组
if(bucketElementCount[k]!=0){
//循环该桶,即第k个一维数组
for(int l=0;l<bucketElementCount[k];l++){
//取出元素放入到arr中
arr[index]=bucket[k][l];
index++;
}
}
//第i+1轮处理后,需要将每个bucketElementCount[k]置0!!!!!
bucketElementCount[k]=0;
}
//System.out.println("第"+(i+1)+"轮,对个位的排序处理:"+ Arrays.toString(arr));
}
/*for(int j=0;j<arr.length;j++){
//取出每个元素的个位
int digitOfElement=arr[j]%10;
//放入到对应的桶中
bucket[digitOfElement][bucketElementCount[digitOfElement]]=arr[j];
bucketElementCount[digitOfElement]++;
}
//按照桶的顺序,取出数据并放入原来的数组
int index=0;
//遍历每一个桶,并将桶中的数据放入到原数组
for(int k=0;k<bucket.length;k++){
//如果桶中有数据,才取出到原数组
if(bucketElementCount[k]!=0){
//循环该桶,即第k个一维数组
for(int l=0;l<bucketElementCount[k];l++){
//取出元素放入到arr中
arr[index]=bucket[k][l];
index++;
}
}
//第一轮处理后,需要将每个bucketElementCount[k]置0!!!!!
bucketElementCount[k]=0;
}
System.out.println("第1轮,对个位的排序处理:"+ Arrays.toString(arr));
//第二轮,放十位
for(int j=0;j<arr.length;j++){
//取出每个元素的个位
int digitOfElement=arr[j]/10%10;
//放入到对应的桶中
bucket[digitOfElement][bucketElementCount[digitOfElement]]=arr[j];
bucketElementCount[digitOfElement]++;
}
//按照桶的顺序,取出数据并放入原来的数组
index=0;
//遍历每一个桶,并将桶中的数据放入到原数组
for(int k=0;k<bucket.length;k++){
//如果桶中有数据,才取出到原数组
if(bucketElementCount[k]!=0){
//循环该桶,即第k个一维数组
for(int l=0;l<bucketElementCount[k];l++){
//取出元素放入到arr中
arr[index]=bucket[k][l];
index++;
}
}
bucketElementCount[k]=0;
}
System.out.println("第2轮,对十位的排序处理:"+ Arrays.toString(arr));
//第三轮,放百位
for(int j=0;j<arr.length;j++){
//取出每个元素的个位
int digitOfElement=arr[j]/100%10;
//放入到对应的桶中
bucket[digitOfElement][bucketElementCount[digitOfElement]]=arr[j];
bucketElementCount[digitOfElement]++;
}
//按照桶的顺序,取出数据并放入原来的数组
index=0;
//遍历每一个桶,并将桶中的数据放入到原数组
for(int k=0;k<bucket.length;k++){
//如果桶中有数据,才取出到原数组
if(bucketElementCount[k]!=0){
//循环该桶,即第k个一维数组
for(int l=0;l<bucketElementCount[k];l++){
//取出元素放入到arr中
arr[index]=bucket[k][l];
index++;
}
}
bucketElementCount[k]=0;
}
System.out.println("第3轮,对百位的排序处理:"+ Arrays.toString(arr));*/
}
}
堆排序
堆排序思路
构建大顶堆时用的是数组
package paixu;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
/**
* @author : sky
* @version : 1.0
*/
public class HeapSort {
public static void main(String[] args) {
//数组进行升序排序
/*int[] arr={4,6,8,5,9};
heapSort(arr);*/
int[] arr=new int[8000000];
for (int i = 0; i <8000000 ; i++) {
arr[i]=(int)(Math.random()*8000000);//生成一个[0,8000000)之间的数
}
Date date1=new Date();
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String date1Str=simpleDateFormat.format(date1);
System.out.println("排序前的时间:"+date1Str);
long start=System.currentTimeMillis();
heapSort(arr);
long end=System.currentTimeMillis();
System.out.println("耗时:"+(end-start));
Date date2=new Date();
String date2Str=simpleDateFormat.format(date2);
System.out.println("排序后的时间:"+date2Str);
}
//堆排序的方法
public static void heapSort(int[] arr){
int temp=0;
System.out.println("堆排序");
//分步完成
/*adjustHeap(arr,1,arr.length);
System.out.println(Arrays.toString(arr));//[4, 9, 8, 5, 6]
adjustHeap(arr,0,arr.length);
System.out.println(Arrays.toString(arr));//[9, 6, 8, 5, 4]*/
//最终代码
//将无序序列构建成一个大顶堆, 第一个非叶子节点的值为arr.length/2-1
for (int i = arr.length/2-1; i >=0 ; i--) {
adjustHeap(arr,i,arr.length);
}
//将堆顶元素与末尾元素交换,最大值放到数组最后
for (int j = arr.length-1; j >0 ; j--) {
//交换
temp=arr[j];
arr[j]=arr[0];
arr[0]=temp;
adjustHeap(arr,0,j);
}
}
//将一个数组 (二叉树),调整成为一个大顶堆
/**
* 功能:完成将以i对应的非叶子节点的树,调整成大顶堆,即图解中的步骤一(2)
* 即将{4,6,8,5,9}=> i=1 => 第一次调整为{4,9,8,5,6};
* i=0 => 再次调整为 {9,6,8,5,4};
* @param arr 待调整的数组
* @param i 非叶子节点在数组中的索引
* @param length 表示对多少个元素进行调整,length在逐渐减少
*/
public static void adjustHeap(int[] arr,int i,int length){
int temp=arr[i];//先取出当前元素的值,保存在临时变量
//开始调整
//k是i节点的左子节点
for (int k = i*2+1; k <length ; k=k*2+1) {
if(k+1<length && arr[k]<arr[k+1]){//说明左子节点的值小于右子节点的值
k++;//k指向右子节点
}
if(arr[k]>temp){//如果子节点大于父节点
arr[i]=arr[k];//把较大的值付给当前的节点
i=k;//!!!然后让i指向k,继续循环比较
}else{
break;//因为是从最后一个非叶子节点走的,所以他之下的都是小的
}
}
//当for循环结束后,我们已经将以i为父节点的树的最大值,放在了最顶上,即i的位置,此时是局部调整
arr[i]=temp;//将temp的值放到调整后的位置
}
}
计数排序
桶排序
k=10,如果log n>10,那么基数排序会更快一点