桂 林 理 工 大 学
实 验 报 告
同组实验者 无
实验名称 实验一 算法设计基础 日期 2020年 11 月13 日
一、实验目的:
掌握算法设计的基本步骤,并能进行时间复杂度分析。
掌握不同算法时间复杂度比较方法。
二、实验环境:
Eclipse
三、实验内容:
-
分别用穷举法和欧几里德算法实现求两个整数的最大公约数,并比较算法的效率。
测试截图:
-
排序算法效率比较。编程实现以下几种不同的排序算法(以升序为例):冒泡排序、选择排序、 希尔排序、快速排序,比较不同的排序过程的运行时间。具体要求:(1)为了消除数据之间差异导致排序效果的影响,使用相同的数组进行排序,方法为:首先创建一个数组,数组长度至少为100000,数组元素取值范围在[0, 100000]之间的随机正整数,并将这个数组复制4份,分别用不同的排序算法进行排序。(2)记录不同排序算法的运行时间。(3)对完全逆序的情况进行测试,将待排序数组赋值为逆序,即与最终排序要求完全相反。
测试截图
(2)
(3)
四、源代码:
第一题
import java.util.Scanner;
public class Main {
public static int gcd(int a, int b)//欧几里得算法
{
return b == 0 ? a : gcd(b, a % b);
}
public static int Exhaus(int a,int b) {//穷举法
int temp;
if(a < b) {
temp = a;
a = b;
b = temp;
}
for(temp = b;; temp--) {
if(a%temp == 0&&b%temp == 0) break;
}
System.out.println("最大公约数为:"+temp);
return temp;
}
public static void main(String args[]){
Scanner input = new Scanner(System.in);
int a = input.nextInt();
int b = input.nextInt();
long start = 0;
long end = 0;
System.out.println("<--穷举法测试开始:-->");
start = System.currentTimeMillis();
System.out.println("最大公约数为:"+Exhaus(a,b));
end = System.currentTimeMillis();
System.out.println("穷举法耗时:"+(end - start) + "毫秒");
System.out.println("<--欧几里得算法测试开始:-->");
start = System.currentTimeMillis();
System.out.println("最大公约数为:"+gcd(a,b%a));
end = System.currentTimeMillis();
System.out.println("欧几里得算法耗时:"+(end - start) + "毫秒");
}
}
第二题
public class Solution {
// --冒泡排序--
public static void bubbleSort(int [] a, int N)
{
int j , k;
int flag = N ;//flag来记录最后交换的位置,也就是排序的尾边界
while (flag > 0){//排序未结束标志
k = flag; //k 来记录遍历的尾边界
flag = 0;
for(j=1; j<k; j++){
if(a[j-1] > a[j]){//前面的数字大于后面的数字就交换
//交换a[j-1]和a[j]
int temp;
temp = a[j-1];
a[j-1] = a[j];
a[j]=temp;
//表示交换过数据;
flag = j;//记录最新的尾边界.
}
}
}
}
// --希尔排序--
//将数组列在一个表中并对列分别进行插入排序,重复这过程,不过每次用更长的列(步长更长了,列数更少了)来进行。最后整个表就只有一列了。
//将数组转换至表是为了更好地理解这算法,算法本身还是使用数组进行排序。
static void shell_sort( int[] arr, int N )
{
int tmp;
int i;
for (int d=N/2; d>0; d/=2)
{
for (int j=d; j<N; ++j)
{
tmp = arr[j];
for (i=j; i>=d && arr[i-d]>tmp; i-=d)
arr[i] = arr[i-d];
arr[i] = tmp;
}
}
}
// --选择排序--
//选择排序:每次从待排序的元素中选出最小值
//算法性能分析:时间复杂度为O(N^2),对于长度为N的数组,需要进行N(N-1)/2次比较和0到N-1次交换。最好情况是已经有序,交换0次;最坏情况交换N-1次;逆序交换N/2次。
public static void selectionSort(int[] arr ,int N){
for(int i = 0; i < N - 1; i++){
int min = i;
for(int j = i + 1; j < N; j++){
//将a[i]和a[i+1...N-1]中的最小元素交换
if(arr[j] < arr[min]){//升序排列
min = j;
}
}
if(min != i){
int temp = arr[i];
arr[i] = arr[min];
arr[min] = temp;
}
}
}
//arr 需要排序的数组
//low 开始时最左边的索引=0
//high 开始时最右边的索引=arr.length-1
public static void quickSort(int[] arr,int low,int high){
int i,j,temp,t;
if(low>high){
return;
}
i=low;//左边哨兵的索引
j=high;//右边哨兵的索引
//temp就是基准位
temp = arr[low];//以最左边为 基准位
while (i<j) {
//先看右边,依次往左递减
//先从右往左找一个小于 基准位的数
//当右边的哨兵位置所在的数>基准位的数 时
//继续从右往左找(同时 j 索引-1)
//找到后会跳出 while循环
while (temp<=arr[j]&&i<j) {
j--;
}
//再看左边,依次往右递增
//步骤和上面类似
while (temp>=arr[i]&&i<j) {
i++;
}
//如果满足条件则交换
if (i<j) {
//z、y 都是临时参数,用于存放 左右哨兵 所在位置的数据
int z = arr[i];
int y = arr[j];
//左右哨兵 交换数据(互相持有对方的数据)
arr[i] = y;
arr[j] = z;
}
}
//这时 跳出了 “while (i<j) {}” 循环
//说明 i=j 左右在同一位置
//最后将基准为与i和j相等位置的数字交换
arr[low] = arr[i];//或 arr[low] = arr[j];
arr[i] = temp;//arr[j] = temp;
/*i=j
这时 左半数组<(i或j所在索引的数)<右半数组
也就是说(i或j所在索引的数)已经确定排序位置, 所以就不用再排序了,
# 只要用相同的方法 分别处理 左右数组就可以了*/
//递归调用左半数组
quickSort(arr, low, j-1);
//递归调用右半数组
quickSort(arr, j+1, high);
}
public static void main(String[] args) {
System.out.println("创建一个100000整数级随机数数组,分别进行排序,比较4种基本排序算法用时");
long start = 0;
long end = 0;
int[] originArray = new int[100000]; //创建一个原始数组
//填充随机数组
for(int i = 0; i < originArray.length; i++) {
originArray[i] = (int)(Math.random() * 100000); //原始数组的每一个元素都是一个取之范围在[0, 99999]之间的随机整数
}
//为了公平起见,我们将原始数组拷贝4份,分别使用4种排序算法进行排序计算事件,消除因为随机数数组取之不同导致的差异
int[] array1 = Arrays.copyOf(originArray, originArray.length);
int[] array2 = Arrays.copyOf(originArray, originArray.length);
int[] array3 = Arrays.copyOf(originArray, originArray.length);
int[] array4 = Arrays.copyOf(originArray, originArray.length);
int[] array5 = new int[1000]; //创建一个原始数组
//逆序赋值
for(int i = array5.length-1; i >= 0; i--) {
array5[i] = i; //原始数组的每一个元素都是一个取之范围在[0, 99999]之间的随机整数
}
//开始比较
System.out.println("冒泡排序开始……");
start = System.currentTimeMillis();
bubbleSort(array1,array1.length);
end = System.currentTimeMillis();
System.out.println("冒泡排序结束,用时" + (end - start) + "毫秒");
System.out.println("----------");
System.out.println("选择排序开始……");
start = System.currentTimeMillis();
selectionSort(array2,array2.length);;
end = System.currentTimeMillis();
System.out.println("选择排序结束,用时" + (end - start) + "毫秒");
System.out.println("----------");
System.out.println("希尔排序开始……");
start = System.currentTimeMillis();
shell_sort( array3 , array3.length);
end = System.currentTimeMillis();
System.out.println("希尔排序结束,用时" + (end - start) + "毫秒");
System.out.println("----------");
System.out.println("快速排序开始……");
start = System.currentTimeMillis();
quickSort(array4,0,array4.length-1);
end = System.currentTimeMillis();
System.out.println("快速排序结束,用时" + (end - start) + "毫秒");
System.out.println("----------");
/*//第三题测试代码
System.out.println("<--------对完全逆序的情况进行测试,将待排序数组赋值为逆序-------------->");
start = System.currentTimeMillis();
System.out.println("冒泡排序开始……");
start = System.currentTimeMillis();
bubbleSort(array5,array5.length);
end = System.currentTimeMillis();
System.out.println("冒泡排序结束,用时" + (end - start) + "毫秒");
System.out.println("----------");
System.out.println("选择排序开始……");
start = System.currentTimeMillis();
selectionSort(array5,array5.length);;
end = System.currentTimeMillis();
System.out.println("选择排序结束,用时" + (end - start) + "毫秒");
System.out.println("----------");
System.out.println("希尔排序开始……");
start = System.currentTimeMillis();
shell_sort( array5 , array5.length);
end = System.currentTimeMillis();
System.out.println("希尔排序结束,用时" + (end - start) + "毫秒");
System.out.println("----------");
System.out.println("快速排序开始……");
start = System.currentTimeMillis();
quickSort(array5,0,array5.length-1);
end = System.currentTimeMillis();
System.out.println("快速排序结束,用时" + (end - start) + "毫秒");*/
System.out.println("----------");
}
}
五、心得体会: