先看实验报告:
好吧,这次实验报告没有什么好吐槽的,安安分分的写了好久。
bug无数,虽然之前写过,但是没这么详细。
代码+注释:
import java.io.*;
import java.util.Arrays;
public class Main3 {
/*直接排序,希尔排序,冒泡排序,快速排序,直接选择排序,堆排序,归并排序算法
* 直接排序和直接选择排序不是同一个吗?
* 太虚假了吧
* 既然如此我就写一个好了
*/
static PrintWriter out=new PrintWriter(new OutputStreamWriter(System.out));
public static void main(String[] args) {
int arr[]=new int[10]; //测试一个1万数据的数组
randomArrays(arr);
long startTime,endTime;
startTime = System.currentTimeMillis();
chooseSort(arr);
endTime = System.currentTimeMillis();
System.out.println("选择排序的时间是:"+(endTime-startTime)+"ms");
upsetArrays(arr);
startTime = System.currentTimeMillis();
bubbleSort(arr);
endTime = System.currentTimeMillis();
System.out.println("冒泡排序的时间是:"+(endTime-startTime)+"ms");
upsetArrays(arr);
startTime = System.currentTimeMillis();
shellSort(arr);
endTime = System.currentTimeMillis();
System.out.println("希尔排序的时间是:"+(endTime-startTime)+"ms");
upsetArrays(arr);
startTime = System.currentTimeMillis();
memerySort(arr);
endTime = System.currentTimeMillis();
System.out.println("归并排序的时间是:"+(endTime-startTime)+"ms");
upsetArrays(arr);
startTime = System.currentTimeMillis();
heapSort(arr);
endTime = System.currentTimeMillis();
System.out.println("堆排序的时间是:"+(endTime-startTime)+"ms");
upsetArrays(arr);
startTime = System.currentTimeMillis();
quickSort(arr);
endTime = System.currentTimeMillis();
System.out.println("快排的时间是:"+(endTime-startTime)+"ms");
upsetArrays(arr);
startTime = System.currentTimeMillis();
Arrays.sort(arr);
endTime = System.currentTimeMillis();
System.out.println("JAVA类库自带快速的时间是:"+(endTime-startTime)+"ms");
}
//选择排序=====================================================================================================
/*
* 柿子先挑软的捏,当然要先写选择排序
*/
static void chooseSort(int arr[]) {
for(int i=0;i<arr.length;i++) {
for(int j=i+1;j<arr.length;j++) {
if(arr[i]>arr[j]) {
swap(arr,i,j);
}
}
}
}
//============================================================================================================
//冒泡排序=====================================================================================================
/*
* 冒泡排序
* 加个flag优化一下
*/
static void bubbleSort(int arr[]) {
boolean flag=true;
for(int i=0;i<arr.length&&flag;i++) {
flag=false;
for(int j=arr.length-1;j>i;j--) {
if(arr[j]<arr[j-1]) {
flag=true;
swap(arr,j,j-1);
}
}
}
}
//=============================================================================================================
//希尔排序=====================================================================================================
/*
* 希尔排序
* 这个排序挺有趣的,刚才看了一个视频理解了:
* https://www.bilibili.com/video/av17062242?from=search&seid=2961680739883013473
* 不过下一个视频也挺有趣的
* https://www.bilibili.com/video/av17004970/?spm_id_from=trigger_reload
* 代码我自己实现一下,不行可以调试,或者看别人的。
* 这个排序不太稳定
* 不过我很奇怪这个原理
*/
static void shellSort(int arr[]) {
int len=arr.length;
int gap=len; //过程增量
do {
gap=gap/3+1;
for(int i=0;i<len-gap;i++) {
if(arr[i]>arr[i+gap]) {
int j=i;
while(j>=0&&arr[j]>arr[j+gap]) {
swap(arr,j,j+gap);
j-=gap;
}
}
}
}
while(gap>1);
// 写下了感觉还是很简单的,而且测试发现也没什么问题。
}
//=============================================================================================================
//归并排序=====================================================================================================
/*
* 归并排序还是很好用的,很稳定的。
* 记得刚加入ACM的时候,学长就是通过选择排序和归并排序给我们讲复杂度
* 这个在我大一上学期自己实现了一下,觉得也没有什么难度。
* 很经典的分治递归
*/
static void memerySort(int arr[]) {
int[] temp=new int[arr.length];
memerySort(arr,0,arr.length-1,temp);
}
static void memerySort(int arr[],int l,int r,int temp[]) {
int t=(l+r)>>1; //位运算,(x>>1)==x/2。计算比较快,堆排应该会用到比较多的位运算
if(l==r)
return;
memerySort(arr,l,t,temp);
memerySort(arr,t+1,r,temp);
memeryArrays(arr,l,r,t,temp);
}
static void memeryArrays(int arr[],int l,int r,int t,int temp[]) {
int i=l,j=t+1;
int now=0;
while(i<=t&&j<=r) {
if(arr[i]<arr[j])
temp[now++]=arr[i++];
else
temp[now++]=arr[j++];
}
for(;i<=t;i++) {
temp[now++]=arr[i];
}
for(;j<=r;j++) {
temp[now++]=arr[j];
}
for(int k=l;k<=r;k++) {
arr[k]=temp[k-l];
}
}
//=============================================================================================================
//堆排序=======================================================================================================
/*
* 堆排这东西,每次都是写bug10分钟。debug两小时。东西太多了,思路太严谨了。
* 虽然写过好几次吧
* 我本来以为堆排一定要额外开一个堆,没想到看了网上的思路,不一定是这样的
* 很节省空间啊
* 大概就是,需要一个adjust函数调整堆(如果要从小排序,需要挑成最大堆)
* 把这个无序数组调整成堆
* 然后把堆顶和数组最后一个元素交换,堆容量-1
* 这样每次都把堆里最大一个元素放到了最后面,就排好序了
* 其实我感觉堆排严谨的复杂度应该是n*logn!
*/
static void heapSort(int[] arr) {
buildHeap(arr); //建堆
getSort(arr); //排序
}
//需要从下向上调整
static void buildHeap(int[] arr) {
for(int i=(arr.length-2)/2;i>=0;i--) {
adjustHeap(arr,i,arr.length);
}
}
static void getSort(int[] arr) {
for(int i=arr.length-1;i>=1;i--) {
swap(arr,0,i);
adjustHeap(arr,0,i);
}
}
//i是调整节点为i的点,len是堆容量
static void adjustHeap(int arr[],int i,int len) {
while((i<<1|1)<len) {
int left=i<<1|1,right=(i<<1)+2;
if(right<len&&arr[right]>arr[i]&&arr[right]>arr[left]) {
swap(arr,i,right);
i=right;
}
else if(arr[left]>arr[i]) {
swap(arr,i,left);
i=left;
}
else
break;
}
}
//=============================================================================================================
//快排=========================================================================================================
/*
* 安利一篇文章,挺不错的
https://mp.weixin.qq.com/s?__biz=MzA5MzY4NTQwMA==&mid=2651005737&idx=1&sn=924250b9065f44f5f
8c7b026ff914fcc&chksm=8bad90debcda19c8fc016c5968d4c817b16c736c0a2c9a5de378ddac1c82b5c4df446
dbeb8e1&mpshare=1&scene=23&srcid=0910GbfDP3XhEWpCqgfK2Ffc#rd
*/
static void quickSort(int[] arr) {
quickSort(arr,0,arr.length-1);
}
static void quickSort(int[] arr,int l,int r) {
if(l>=r)
return;
int privot=partition(arr,l,r);
quickSort(arr,l,privot-1);
quickSort(arr,privot+1,r);
}
static int partition(int[] arr,int start,int end) {
int l=start,r=end;
int pivot=arr[start];
while(l!=r) {
while(l<r&&arr[r]>pivot) {
r--;
}
while(l<r&&arr[l]<=pivot) {
l++;
}
if(l<r) {
swap(arr,l,r);
}
}
if(l!=start)
swap(arr,l,start);
return l;
}
//=============================================================================================================
//打印一个数组,方便测试
static void print(int arr[]) {
for(int i=0;i<arr.length;i++) {
out.write(arr[i]+" ");
}
out.write("\n");
out.flush();
}
//随机生成一个数组,方便测试
static void randomArrays(int arr[]) {
for(int i=0;i<arr.length;i++)
arr[i]=(int) (Math.random()*1000);
}
//随机打乱一个数组,方便测试
static void upsetArrays(int[] arr) {
for(int i=0;i<arr.length;i++) {
int t=(int) (Math.random()*arr.length);
if(i!=t)
swap(arr,i,t);
}
}
//异或运算交换两个变量,比较节省时间。
static void swap(int arr[],int a,int b) {
arr[a]^=arr[b];
arr[b]^=arr[a];
arr[a]^=arr[b];
}
}
/*
*1000的数据量
*选择排序的时间是:4ms
*冒泡排序的时间是:5ms
*希尔排序的时间是:1ms
*归并排序的时间是:1ms
*堆排序的时间是:0ms
*快排的时间是:1ms
*JAVA类库自带快速的时间是:1ms
*1w的数据量
*选择排序的时间是:59ms
*冒泡排序的时间是:150ms
*希尔排序的时间是:3ms
*归并排序的时间是:2ms
*堆排序的时间是:3ms
*快排的时间是:3ms
*JAVA类库自带快速的时间是:5ms
*5W的数据量
*选择排序的时间是:1391ms
*冒泡排序的时间是:3770ms
*希尔排序的时间是:10ms
*归并排序的时间是:11ms
*堆排序的时间是:12ms
*快排的时间是:20ms
*JAVA类库自带快速的时间是:9ms
*10W的数据量
*选择排序的时间是:4915ms
*冒泡排序的时间是:15191ms
*希尔排序的时间是:17ms
*归并排序的时间是:20ms
*堆排序的时间是:17ms
*快排的时间是:18ms
*JAVA类库自带快速的时间是:10ms
*1千万的数据,选择排序和冒泡排序不敢玩了,就搞下这些。
*希尔排序的时间是:1835ms
*归并排序的时间是:1181ms
*堆排序的时间是:2030ms
*快排的时间是:15282ms
*JAVA类库自带快速的时间是:500ms
*由此可见,数组的容量越大,差距越大,还是系统自带的好用,哈哈哈
*/