排序算法

这是我参与更文挑战的第18天,活动详情查看: 更文挑战

内容一 排序算法

要求:

1.分别针对随机生成的若干组整数序列(比 如规模为1000个数,10000个数,100000 个数)进行排序,排序算法使用四种方法, 至少包括以下三种经典方法:插入排序算 法、合并排序算法和快速排序算法。

2.在用不同的排序算法对多组整数进行排序 时,统计各种情况下排序所耗费的时间, 并对结果进行分析 。

3.当要求为降序时,如何修改?并尝试实现。

4.如果随机生成了10个数,在使用快速排序 进行排序时,尝试给出数组的演化情况 。

5.排序算法的稳定性。

6.排序算法的空间性能。

实验过程:

一、生成随机数

借助java.util.Random

	Random r=new Random();
        	a[i]=r.nextInt(100);//生成0-100内的随机整数,为了方便查看后续排序情况
复制代码
补充:Random常用用法

1.random.nextInt()

random.nextIn()的作用是随机生成一个int类型,因为int 的取值范围是 -2147483648——2147483647 ,所以生成的数也是处于这个范围。示例代码:

Random random = new Random();
System.out.println("int:"+random.nextInt());

输出:
int:-1849568817
复制代码

2.random.nextInt(int bound)

random.nextInt(int bound)方法的作用是生成一个0-参数bound范围内的随机数,但是要记住,参数bound必须是正数,不可为负数,否则在运行时会报java.lang.IllegalArgumentException: bound must be positive的错误,提示bound必须是正数。

3.random.nextLong()

random.nextLong()会随机生成一个Long类型,同理,因为Long的取值范围是 -9223372036854775808——9223372036854775807

4.random.nextDouble()

random.nextDouble()会生成一个0-1的double类型,而不是生成double取值范围中的数,下附取值范围:

Random random = new Random();
System.out.println("double:"+random.nextDouble());

输出:
double:0.9059561641891956
复制代码

5.random.nextFloat()

random.nextFloat()会生成一个随机的0-1之间的浮点型,大体同double一样.

Random random = new Random();
System.out.println("float:"+random.nextFloat());

输出:
float:0.56538385
复制代码

6.random.nextBoolean()

random.nextBoolean()会生成一个true或false

Random random = new Random();
System.out.println("boolean:"+random.nextBoolean());

输出:
boolean:false
复制代码

二、四种排序算法的升序和降序(直接插入,冒泡,合并,快排)

package paixu;

public class Sort {
	//插入排序升序
    public void insertSortAsc(int arr[]){
    	for(int index=1;index<arr.length;index++){
    		int temp=arr[index];//记录待插入元素
    		int leftindex=index-1;//从有序数组最后一个数开始比较
    		while(leftindex>=0&&arr[leftindex]>temp){
    			arr[leftindex+1]=arr[leftindex];
    			leftindex--;
    		}
    		arr[leftindex+1]=temp;
    	}
    }
    //插入排序降序
    public void insertSortDesc(int[] arr){
    	for(int index=1;index<arr.length;index++){
    		int temp=arr[index];//记录待插入元素
    		int leftindex=index-1;//从有序数组最后一个数开始比较
    		while(leftindex>=0&&arr[leftindex]<temp){
    			arr[leftindex+1]=arr[leftindex];
    			leftindex--;
    		}
    		arr[leftindex+1]=temp;
    	}
    }
    //合并排序升序
    //合并操作
    public void mergeAsc(int arr[],int L1,int R1,int L2,int R2){
    	int[] temp;
    	temp=new int[R1-L1+R2-L2+2];
    	int n=L1;
    	int m=L2;
    	int i=0;
    	while(n<=R1&&m<=R2){//数组arr[]拆成左右两个区间,从第一个数开始比较两个区间数大小,小的放在temp[]中
    		if(arr[n]<arr[m]){
    			temp[i++]=arr[n++];
    		}
    		else{
    			temp[i++]=arr[m++];
    		}
    	}
    	while(n<=R1){
    		temp[i++]=arr[n++];
    	}
    	while(m<=R2){
    		temp[i++]=arr[m++];
    	}
    	for(int j=0;j<i;j++){//将排好序的temp[]复制到arr[]中
    		arr[L1+j]=temp[j];
    	}
    }
    public void mergeSortAsc(int arr[],int left,int right){
    	if(left<right){
    		int mid=(left+right)/2;
    		mergeSortAsc(arr,left,mid);//递归
    		mergeSortAsc(arr,mid+1,right);
    		mergeAsc(arr,left,mid,mid+1,right);//合并
    	}
    }
    //合并排序降序
    //合并操作
public void mergeDesc(int arr[],int L1,int R1,int L2,int R2){
	int[] temp;
	temp=new int[100];
	int n=L1;
	int m=L2;
	int i=0;
	while(n<=R1&&m<=R2){//数组arr[]拆成左右两个区间,从第一个数开始比较两个区间数大小,大的放在temp[]中
		if(arr[n]>arr[m]){
			temp[i++]=arr[n++];
		}
		else{
			temp[i++]=arr[m++];
		}
	}
	while(n<=R1){
		temp[i++]=arr[n++];
	}
	while(m<=R2){
		temp[i++]=arr[m++];
	}
	for(int j=0;j<i;j++){//将排好序的temp[]复制到arr[]中
		arr[L1+j]=temp[j];
	}
}
public void mergeSortDesc(int arr[],int left,int right){
	if(left<right){
		int mid=(left+right)/2;
		mergeSortDesc(arr,left,mid);//递归
		mergeSortDesc(arr,mid+1,right);
		mergeDesc(arr,left,mid,mid+1,right);//合并
	}
}
	//快速排序升序
public int PartitionAsc(int arr[],int low,int high){//确定基准元素的位置
	int pivot=arr[low];
	while(low<high){
	while(low<high&&arr[high]>=pivot)
		high--;
	    arr[low]=arr[high];
    while(low<high&&arr[low]<=pivot)
		low++;
	    arr[high]=arr[low];
	}
	arr[low]=pivot;
	return low;
}
public void QuickSortAsc(int arr[],int low,int high){
     if(low<high){
    	 int q=PartitionAsc(arr,low,high);
    	 QuickSortAsc(arr,low,q-1);
    	 QuickSortAsc(arr,q+1,high);
     }	
}
//快速排序降序
public int PartitionDesc(int arr[],int low,int high){//确定基准元素的位置
int pivot=arr[low];
while(low<high){
while(low<high&&arr[high]<=pivot)
	high--;
    arr[low]=arr[high];
while(low<high&&arr[low]>=pivot)
	low++;
    arr[high]=arr[low];
}
arr[low]=pivot;
return low;
}
public void QuickSortDesc(int arr[],int low,int high){
 if(low<high){
	 int q=PartitionDesc(arr,low,high);
	 QuickSortDesc(arr,low,q-1);
	 QuickSortDesc(arr,q+1,high);
 }	
}
//冒泡排序升序
public void BubbleSortAsc(int arr[],int n){
	for(int i=0;i<n;i++){//外层循环表示趟数
		boolean flag=false;//若未发生交换,则flag仍为false
		for(int j=0;j<n-i;j++){
			if(arr[j]>arr[j+1]){//不能写>=,否则不稳定
				int temp=arr[j];
				arr[j]=arr[j+1];
				arr[j+1]=temp;
				flag=true;
			}
		}
		if(!flag){//从头到尾没有发生交换,说明数组有序
			break;
		}
	}
}
//冒泡排序降序
public void BubbleSortDesc(int arr[],int n){
	for(int i=0;i<n;i++){//外层循环表示趟数
		boolean flag=false;//若未发生交换,则flag仍为false
		for(int j=0;j<n-i;j++){
			if(arr[j]<arr[j+1]){//不能写<=,否则不稳定
				int temp=arr[j];
				arr[j]=arr[j+1];
				arr[j+1]=temp;
				flag=true;
			}
		}
		if(!flag){//从头到尾没有发生交换,说明数组有序
			break;
		}
	}
}
}
复制代码

列举其中一种输出结果:

System.out.println(Arrays.toString(a));
s.QuickSortDesc(a, 0, a.length-1);
System.out.println("快速排序降序结果为:");
System.out.println(Arrays.toString(a));	

[84, 15, 48, 23, 27, 79, 85, 63, 5, 32]
快速排序降序结果为:
[85, 84, 79, 63, 48, 32, 27, 23, 15, 5]
复制代码

三、计算各排序算法所用时间

补充:java计算程序运行时间:

(1) 以毫秒为单位计算

 long startTime=System.currentTimeMillis();   //获取开始时间
  doSomeThing();  //测试的代码段
 long endTime=System.currentTimeMillis(); //获取结束时间
  System.out.println("程序运行时间: "+(end-start)+"ms");
复制代码

(2)以纳秒为单位计算

 long startTime=System.nanoTime();   //获取开始时间
  doSomeThing();  //测试的代码段
 long endTime=System.nanoTime(); //获取结束时间
  System.out.println("程序运行时间: "+(end-start)+"ns");
复制代码

本次实验采取第二种方式针对1000个数比较四种排序算法的执行时间。为防止排序后数组对其它排序的影响,在一个排序算法允许时,将另三个排序算法注释掉。
由运行结果可知:

运行时间由小到大分别是:快速排序<合并排序<插入排序<冒泡排序

四、比较排序算法的稳定性和空间性能

稳定性:冒泡排序、插入排序、归并排序是稳定排序,快速排序是不稳定排序。

空间复杂度:冒泡排序、插入排序因为不使用额外空间,故为 O(1); 快速排序为 O(logn);归并为 O(n)。

实验中遇到的问题:

1.做合并排序降序时,复制升序代码,忘记改调用的递归函数。

2.快排时,调错快排函数,掉成partition函数,使得快排只执行一次。

3.使用scanner时,控制台不跳出来,还以为代码中有问题,后发现window-show view-console就能出来了。

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享