版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/ky415/article/details/80170974
大三下了,正在找实习,把一些常用的排序算法重新复习一遍,同时简单的比较了一下各个算法的效率,总的来说,快排效率最高,冒泡效率最低。-----具体的排序算法包括:直接插入排序、折半插入排序、Shell排序(插入排序) 冒泡、快速排序(交换排序)
欢迎大家一起讨论,如有错误务必指出~~~
先验证排序算法的正确性:
接着比较效率(注释掉了打印数组的功能):
得出结论:当待排数的数量较大时(示例中采用102400个随机整数),效率对比为:
快速排序 > 折半插入排序 > Shell排序 > 直接插入排序 > 冒泡排序
package com.ky415.loop;
import java.util.Arrays;
import java.util.Random;
import java.util.Scanner;
/**
* 测试数组的常用方法:最大值、求和、平均值、数组的翻转
* 使用多种排序方法对输入的数组进行排序(升序)
* 依次包括:直接插入排序、折半插入排序、Shell排序(插入排序)
* 冒泡、快速排序(交换排序)
* @author Mypc
*/
public class TestArray {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
System.out.println("请输入需要生成的随机数的个数:");
int count = input.nextInt();
Random random = new Random();
int[] number = new int[count];
for (int i = 0; i < number.length; i++) {
number[i] = random.nextInt();
}
// System.out.println("生成的随机数如下:");
// printArray(number);
System.out.println("对" + count + "个数进行排序,各个排序所需时间的对比如下" );
directInsertSort(number);
halfInsertSort(number);
shellSort(number);
bubbleSort(number);
quickSort(number);
}
/**
* 打印整型数组的值
* @param number
*/
public static void printArray(int [] number) {
int time = 0;
for(int i : number) {
System.out.print(i + "\t");
time ++;
if(time % 5 == 0) {
time = 0;
System.out.println();
}
}
System.out.println();
}
/**
* 测试数组的常用方法:最大值、求和、平均值、数组的翻转
* @param number
*/
public static void arrayCommonMethod(int[] number) {
//求数组最大值
int[] number1 = number;
System.out.print("数组的最大值为:");
int max = number1[0];
for (int i = 1; i < number1.length; i++) {
max = number1[i] > max ? number1[i] : max;
}
System.out.println(max);
//求数值所有的元素之和
System.out.print("数组的和为:");
int sum = number1[0];
for (int i = 1; i < number1.length; i++) {
sum += number1[i];
}
System.out.println(sum);
//求数组元素的平均值
System.out.print("数组的平均值为:");
int avge = 0;
for (int i : number1) {
avge += i;
}
System.out.println(avge / number1.length);
//对数组进行翻转
System.out.print("数组翻转后为:");
int[] number2 = new int[number.length];
for (int i = 0, j = number1.length - 1; j >= 0; i++, j--) {
number2[i] = number1[j];
}
for(int i : number2) {
System.out.print(i + "\t");
}
}
/**
* 直接插入排序
* --基本思想是每一趟将一个待排序的记录,按其关键字的大小插入到已经排好序的一组记录的适当位置上,直到所有待排序记录全部插入为止。
* @param number
*/
public static void directInsertSort(int[] number) {
//用以记录排序开始的时间
long start = System.currentTimeMillis();
int[] number1 = new int[number.length];
for (int i = 0, j = number.length - 1; j >= 0; i++, j--) {
number1[i] = number[j];
}
for (int i = 1; i < number1.length; i++) {
//判断当前值是否需要移动
if(number1[i] < number1[i - 1]) {
//记录需要移动的关键字位置
int moveSubscript = i;
//暂存需要移动的关键字
int temp = number1[moveSubscript];
//将已经排序好的记录,从需要移动的关键字前一个开始,将每一个比关键字大的元素都向后移一位
for (int j = i - 1; j >= 0 && number1[j] > temp; j--) {
moveSubscript = j;
number1[j + 1] = number1[j];
}
//将需要移动的关键字,放置在最终的位置上
number1[moveSubscript] = temp;
}
}
//用以记录排序完成的时间
long end = System.currentTimeMillis();
System.out.println("直接插入排序--"+ "完成排序需要的时间为:" + (end - start) +" :");
}
/**
* 折半插入排序 -- 折半插入算法是对直接插入排序算法的改进,排序原理同直接插入算法。
* 两者区别在于:在有序表中寻找待排序数据的正确位置时,使用了折半查找/二分查找。
* @param number
*/
public static void halfInsertSort(int [] number) {
//构建一个新的数组进行排序操作
int[] number1 = new int[number.length];
for (int i = 0, j = number.length - 1; j >= 0; i++, j--) {
number1[i] = number[j];
}
//用以记录排序开始的时间
long start = System.currentTimeMillis();
for (int i = 1; i < number1.length; i++) {
//判断当前值是否需要移动
if(number1[i] < number1[i - 1]) {
//暂存需要移动的关键字
int temp = number1[i];
//查找需要移动的关键字应该插入的位置 目标位置为low
int low = 0, high = i - 1, mid = 0;
while(low <= high){
mid = (low + high) / 2;
if(number1[mid] < temp) {
low = mid + 1;
}
else {
high = mid - 1;
}
}
//将已经排序好的记录,从需要移动的关键字前一个开始,将每一个比关键字大的元素都向后移一位
for (int j = i;j > low; j--) {
number1[j] = number1[j - 1];
}
//将需要移动的关键字,放置在最终的位置上
number1[low] = temp;
}
}
//用以记录排序完成的时间
long end = System.currentTimeMillis();
System.out.println("折半插入排序--"+ "完成排序需要的时间为:" + (end - start) +" :");
}
/**
* Shell排序--也是对直接插入排序的改进; 基本思想:先将整个待排元素序列切割成若干个子序列(由相隔某个“增量”的元素组成的)
* 分别进行直接插入排序,然后依次缩减增量再进行排序,待整个序列中的元素基本有序(增量足够小)时,再对全体元素进行一次直接插入排序。
* @param number
*/
public static void shellSort(int[] number) {
//构建一个新的数组进行排序操作
int[] number1 = new int[number.length];
for (int i = 0, j = number.length - 1; j >= 0; i++, j--) {
number1[i] = number[j];
}
//用以记录排序开始的时间
long start = System.currentTimeMillis();
//设置每次分组的大小--当 gap 为 0 时排序完成
for(int gap = number1.length / 2; gap > 0; gap /= 2) {
for(int j = gap; j < number1.length; j += gap) {
if(number1[j] < number1[j - gap]) {
int temp = number1[j];
int k = j;
while(k - gap >= 0 && number1[k - gap] > temp) {
number1[k] = number1[k - gap];
k -= gap;
}
number1[k] = temp;
}
}
}
//用以记录排序完成的时间
long end = System.currentTimeMillis();
System.out.println("Shell排序--"+ "完成排序需要的时间为:" + (end - start) +" :");
// printArray(number1);
}
/**
* 冒泡排序--依次比较相邻的两个数,将小数放在前面,大数放在后面。即在第一趟:首先比较第1个和第2个数,将小数放前,大数放后。
* 然后比较第2个数和第3个数,将小数放前,大数放后,如此继续,直至比较最后两个数,将小数放前,大数放后。重复第一趟步骤,直至全部排序完成。
* @param number
*/
public static void bubbleSort(int[] number) {
//构建一个新的数组进行排序操作
int[] number1 = new int[number.length];
for (int i = 0, j = number.length - 1; j >= 0; i++, j--) {
number1[i] = number[j];
}
//用以记录排序开始的时间
long start = System.currentTimeMillis();
for (int i = 0; i < number1.length -1; i++) {
for (int j = 0; j < number1.length - 1 - i; j++) {
//遇到不满足排序要求的数,交换两个数的位置
if(number1[j] > number1[j + 1]) {
int temp = number1[j];
number1[j] = number1[j + 1];
number1[j + 1] = temp;
}
}
}
//用以记录排序完成的时间
long end = System.currentTimeMillis();
System.out.println("冒泡排序--"+ "完成排序需要的时间为:" + (end - start) +" :");
// printArray(number1);
}
/**
* 基本思想主要分为三个步骤:1、先从数列中取出一个数作为基准数(标兵-通常取第一个数),
* 2、先从右到左找到第一个比基准数小数,然后停下来(大哨兵移动 j--),从左到右找到第一个比基准数大的数,然后停下来(小哨兵移动 i++)
* 此时大小哨兵交换值,然后继续移动,直到大小哨兵相遇(i >= j),然后以此值为界限,将数列进行左右两区
* 3、再对左右区间重复第二步,直到各区间只有一个数
* @param number
*/
public static void quickSort(int [] number) {
//构建一个新的数组进行排序操作
int[] number1 = new int[number.length];
for (int i = 0, j = number.length - 1; j >= 0; i++, j--) {
number1[i] = number[j];
}
//用以记录排序开始的时间
long start = System.currentTimeMillis();
//调用快速排序算法
quick(number1, 0, number1.length - 1);
//用以记录排序完成的时间
long end = System.currentTimeMillis();
System.out.println("快速排序--"+ "完成排序需要的时间为:" + (end - start) +" :");
// printArray(number1);
}
/**
* 对数组的 low 到 high 的区间进行一次快速排序
* @param number 数组名
* @param low 快排区间开始的下标
* @param high 快排区间结束的下标
*/
public static void quick(int[] number, int low, int high) {
//递归跳出条件--所有的数都已经归位
if(low >= high) {
return ;
}
//取出基准数(标兵)
int key = number[low];
//取左右标兵
int left = low;
int right = high;
//只有当左哨兵与右哨兵相等时,才结束循环
while(left < right) {
//右哨兵左移--直到遇见一个比key小的值
while(number[right] >= key && right > left) {
right --;
}
//左哨兵右移--直到遇见一个比key大的值
while (number[left] <= key && right > left) {
left ++;
}
//交换左右哨兵的值
int temp = number[right];
number[right] = number[left];
number[left] = temp;
}
//将标兵置于最终的位置--标兵归位
number[low] = number[left];
number[left] = key;
//对余下的左右两部分继续进行快排
quick(number, low, left - 1);
quick(number, left + 1, high);
}
}