冒泡排序
package paixu;
import java.util.Random;
/*
* 冒泡排序
* 时间复杂度:平均O(n^2),最坏O(n^2)
* */
public class maopao {
public static void main(String[] args){
long start=System.currentTimeMillis(); //获取开始时间
int arr[]=new int[20000];
//设置一个数组长度为20000,然后往里面随机赋值0~20000的数字
for(int i=0;i<20000;i++){
Random random = new Random();
arr[i]= random.nextInt(20000);
}
//冒泡排序算法
for(int i=1;i<arr.length;i++){
for(int j=0;j<arr.length-i;j++){
if(arr[j]>arr[j+1]){
int temp=arr[j];
arr[j]=arr[j+1];
arr[j+1]=temp;
}
}
}
//输出结果
for(int i=0;i<arr.length;i++){
if(i!=arr.length-1)
System.out.print(arr[i]+",");
else
System.out.println(arr[i]);
}
long end=System.currentTimeMillis(); //获取结束时间
System.out.println("程序运行时间: "+(end-start)+"ms");
}
}
运行结果
程序运行时间: 558ms
插入排序
package paixu;
import java.util.Random;
/*
* 插入排序
* 时间复杂度:平均O(n^2),最坏O(n^2)
* */
public class charu {
public static void main(String[] args){
long start=System.currentTimeMillis(); //获取开始时间
int arr[]=new int[20000];
//设置一个数组长度为20000,然后往里面随机赋值0~20000的数字
for(int i=0;i<20000;i++){
Random random = new Random();
arr[i]= random.nextInt(20000);
}
//插入排序算法
int j, temp;
for (int i = 1; i < arr.length; i++) {// 从数组的第二个元素开始循环将数组中的元素插入
temp = arr[i];// 设置数组中的第2个元素为第一次循环要插入的数据
j = i - 1;
while (j >= 0 && temp < arr[j]) {
arr[j + 1] = arr[j];// 如果要插入的元素小于第j个元素,就将第j个元素向后移动
j--;
}
arr[j + 1] = temp;// 直到要插入的元素不小于第j个元素,将temp插入到数组中
}
//输出结果
for(int i=0;i<arr.length;i++){
if(i!=arr.length-1)
System.out.print(arr[i]+",");
else
System.out.println(arr[i]);
}
long end=System.currentTimeMillis(); //获取结束时间
System.out.println("程序运行时间: "+(end-start)+"ms");
}
}
运行结果
程序运行时间: 188ms
希尔排序
package paixu;
import java.util.Random;
/*
* 希尔排序
* 平均O(n^1.5),最坏O(n^2)
* */
public class xier {
public static void main(String[] args){
long start=System.currentTimeMillis(); //获取开始时间
int arr[]=new int[20000];
//设置一个数组长度为20000,然后往里面随机赋值0~20000的数字
for(int i=0;i<20000;i++){
Random random = new Random();
arr[i]= random.nextInt(20000);
}
//希尔排序算法
int incrementNum=arr.length/2;
for (int increment = incrementNum; increment > 0; increment /= 2) {
//下面就是一个修改过的插入排序
for (int i = increment; i < arr.length; i++) {
if(arr[i] < arr[i-increment]){
int temp = arr[i];
int j;
for(j = i-increment; j >= 0 && arr[j] > temp; j -=increment){
arr[j+increment] = arr[j];
}
arr[j+increment] = temp;
}
}
}
//输出结果
for(int i=0;i<arr.length;i++){
if(i!=arr.length-1)
System.out.print(arr[i]+",");
else
System.out.println(arr[i]);
}
long end=System.currentTimeMillis(); //获取结束时间
System.out.println("程序运行时间: "+(end-start)+"ms");
}
}
具体可以看https://www.cnblogs.com/chengxiao/p/6104371.html
运行结果
程序运行时间: 83ms
快速排序
package paixu;
import java.util.Random;
public class kuaisu {
public static void main(String[] args){
long start=System.currentTimeMillis(); //获取开始时间
int arr[]=new int[20000];
//设置一个数组长度为20000,然后往里面随机赋值0~20000的数字
for(int i=0;i<20000;i++){
Random random = new Random();
arr[i]= random.nextInt(20000);
}
//快速排序算法
quickSort(arr,0,arr.length-1);
//输出结果
for(int i=0;i<arr.length;i++){
if(i!=arr.length-1)
System.out.print(arr[i]+",");
else
System.out.println(arr[i]);
}
long end=System.currentTimeMillis(); //获取结束时间
System.out.println("程序运行时间: "+(end-start)+"ms");
}
public static void quickSort(int[] array,int low,int high){
int start = low;//开始位置(前端)
int end = high;//结束位置(后端)
int key = array[low];//关键值,也就是枢轴。第一次从位置0开始取,一轮排完会后排到中间。
while(end>start){//
//现在关键值在“前端”,从后往前比较,要找到小于关键值的值
//如果比关键值大,则比较下一个,直到有比关键值小的交换位置,然后又从前往后比较
while(end>start&&array[end]>=key)
end--;//如果最后一个值大于关键值,则end往前移一位,拿倒数第二个比···
//由于之前的end--,现在是往前移了一位了,
// 如果这时候刚好比关键值小,则将小的值和关键值交换位置。
if(array[end]<=key){
int temp = array[end];
array[end] = array[start];
array[start] = temp;
}
//现在关键值在后端,从前往后比较,要找到大于关键值的值
//如果比关键值小,则比较下一个,直到有比关键值大的交换位置
while(end>start&&array[start]<=key)
//从前端开始找,如果前端的值比目前处在后端的关键值小,
// 则start++,将前端位置往后移一位
start++;
//由于前端往后移了一位,就再比一次,
// 如果此时前端值刚好比关键值大,则交换位置,把关键值交换到前端。
if(array[start]>=key){
int temp = array[start];
array[start] = array[end];
array[end] = temp;
}
//此时第一次循环比较结束,关键值(枢轴)的位置已经确定了。
// 左边的值都比关键值小,右边的值都比关键值大,
// 但是两边的顺序还有可能是不一样的,进行下面的递归调用
}
//递归,此时分别对枢轴两边进行快排
//此时low是初始时的开始位置,start则++了好几次,low位至start位构成了左边序列。
// low作为左边序列的起始位,start其实是枢轴的位置,所以start-1就是左边序列的结束位
if(start>low) quickSort(array,low,start-1);
//此时end是枢轴的位置,所以end+1是右边序列的起始位,high是最初的结束为
// (也就是最后一个数,期间改变的是end,high没变),所以high就是右边序列的结束位
if(end<high) quickSort(array,end+1,high);
}
}
运行结果
程序运行时间: 77ms
选择排序
package paixu;
import java.util.Random;
public class xuanze {
public static void main(String[] args){
long start=System.currentTimeMillis(); //获取开始时间
int arr[]=new int[20000];
//设置一个数组长度为20000,然后往里面随机赋值0~20000的数字
for(int i=0;i<20000;i++){
Random random = new Random();
arr[i]= random.nextInt(20000);
}
//选择排序算法
int len=arr.length;
int small;//一次比较中最小的下标。
int temp;
//初始从第0位开始找,此位放最小的数,之后第1位放第二小的数·····
for(int i=0;i<len-1;i++){
small=i;//该此比较中最小的下标
//把假定最小下标后的下标的值与该值循环比较,每次都将更小的下标赋给small,
// 一轮下来,small里就是真正的最小下标
for(int j=i+1;j<len;j++){
//如果找到比“最小下标”小的值,则将该下标改成最小下标
if(arr[j]<arr[small]){
small=j;
}
}
//查询一轮下来,判断small是否变更,如果没变就表示目前i位就是最小的,不用换位。否则换位
if(i!=small){
//将目前找到的最小元素临时装到temp中
temp=arr[small];
//此处没有直接将i位于small位交换,
// 因为直接交换可能会导致相同的数据元素位置发生变化,引起排序不稳定。
//将第i位至第samll-1位的元素集体向后移一位
// (这样就刚好把第samll位盖住了,顺序也不会发生改变,也保证了稳定性)
for(int k=small;k>i;k--){
arr[k]=arr[k-1];
}
arr[i]=temp;//将目前最小值赋值给第i位
}
}
//输出结果
for(int i=0;i<arr.length;i++){
if(i!=arr.length-1)
System.out.print(arr[i]+",");
else
System.out.println(arr[i]);
}
long end=System.currentTimeMillis(); //获取结束时间
System.out.println("程序运行时间: "+(end-start)+"ms");
}
}
运行结果
程序运行时间: 201ms
归并
package paixu;
import java.util.Random;
/*
* 插入排序
* 时间复杂度:平均O(n^2),最坏O(n^2)
* */
public class guibing {
public static void main(String[] args){
long start=System.currentTimeMillis(); //获取开始时间
int arr[]=new int[20000];
//设置一个数组长度为20000,然后往里面随机赋值0~20000的数字
for(int i=0;i<20000;i++){
Random random = new Random();
arr[i]= random.nextInt(20000);
}
//归并排序算法
mergingSort(arr,0,arr.length-1);
//输出结果
for(int i=0;i<arr.length;i++){
if(i!=arr.length-1)
System.out.print(arr[i]+",");
else
System.out.println(arr[i]);
}
long end=System.currentTimeMillis(); //获取结束时间
System.out.println("程序运行时间: "+(end-start)+"ms");
}
public static void mergingSort(int[] array, int left, int right){
if (left<right){
//找到传入数组的中间位
int center = (left + right)/2;
//将中间位作为“左边边界”递归,这样就能不断二分左边数组
mergingSort(array, left, center);
//找到和左边数组对应的右边部分
mergingSort(array, center + 1, right);
//根据相关数据可以确定需要排序的范围,进行排序
merge(array, left, center, right);
}
}
/**
* 相当于有三个数组:
* leftPos到leftEnd组成了第一个待排数组,
* rightPos到rightEnd组成了第二个待排数组。
* 还有一个空的数组用来临时存储结果。
*
* 每次将两个待排数组的最靠前项相比较,
* 将其中最小的一项放入空数组中,
* 然后该最小项所在数组的靠前下标+1
*
* 即有a[],b[]两个数组比较,
* 先比较a[0],b[0],发现a[0]小,就将a[0]放入result[],再比较a[1]和b[0]······
*
* 其中两个待排数组自身肯定是有序的(因为他们也是经过现有步骤排出来的)
*
* 当其中某个待排数组排完后,
* 就表示“另一个待排数组的剩余项肯定大于之前所有的排序项”,又因为剩余项是有序的,
*
* 所以可以将剩余项全部按序装入临时结果数组。
* 之后用结果数组覆盖掉原数组
*
* @param array 待排数组
* @param leftPos 待排数组的左边部分的起始位
* @param leftEnd 待排数组左边部分的结束位
* @param rightEnd 待排数组右边部分的结束位
*/
private static void merge(int[] array, int leftPos, int leftEnd, int rightEnd) {
int[] tmpArr = new int[rightEnd+1];//临时的结果数组,将排序后的结果存放其中
int rightPos = leftEnd + 1;//位于右边的待排数组开始位
int tmpPos = leftPos; //临时数组的存储位,每存一个,就后移一位
int tmp = leftPos;//排序的起始位置
// 从两个数组中取出最小的放入临时数组
while (leftPos <= leftEnd && rightPos <= rightEnd) {
if ((array[leftPos] <= array[rightPos])){
tmpArr[tmpPos++] = array[leftPos++];
}else {
tmpArr[tmpPos++] = array[rightPos++];
}
}
//此时肯定有一个待排数组已经排完了,现在查找那个数组排完了,
// 并将另一个数组的剩余部分装入临时数组
while (rightPos <= rightEnd) {
tmpArr[tmpPos++] = array[rightPos++];
}
while (leftPos <= leftEnd) {
tmpArr[tmpPos++] = array[leftPos++];
}
// 将临时数组中的内容复制回原数组
for (int i = tmp; i <= rightEnd; i++) {
array[i] = tmpArr[i];
}
}
}
运行结果
程序运行时间: 241ms
基数排序
package paixu;
import java.util.Random;
/*
* 插入排序
* 时间复杂度:平均O(n^2),最坏O(n^2)
* */
public class jishu {
public static void main(String[] args){
long start=System.currentTimeMillis(); //获取开始时间
int arr[]=new int[20000];
//设置一个数组长度为20000,然后往里面随机赋值0~20000的数字
for(int i=0;i<20000;i++){
Random random = new Random();
arr[i]= random.nextInt(20000);
}
//基数排序算法
radixSort(arr,5);
//输出结果
for(int i=0;i<arr.length;i++){
if(i!=arr.length-1)
System.out.print(arr[i]+",");
else
System.out.println(arr[i]);
}
long end=System.currentTimeMillis(); //获取结束时间
System.out.println("程序运行时间: "+(end-start)+"ms");
}
public static void radixSort(int[] array,int len_max){
/**
* 一般的桶排序的count[]只是一维数组,
* 里面的每项(0-9)的具体值代表了该数出现的次数,
* 如count[2]=3,代表2这个“项”,出现了3次。
*
* 但现在是“从个位开始”,每一位都要做桶排序。
* 如果还是使用count[],
* 那么count[2]=3只能代表“在所有项的第n位桶排序中”2这个数“作为第n位数”出现了3次。
*
* 显然,正常的流程是:
* 先查找“个位”的count[0]=n,将这些“个位为0”的数从第0位开始放入数组。
* 再看“个位”的count[1]=m,将这些“个位为1”的数紧挨着刚刚插入的数插进来。·····
* “个位”的第一轮排序完后,原数组相当于“依据个位大小,进行了一次排序”,
* 接下来就要“依据十位大小再进行一次排序了”····。
*
* 综上流程能够发现,第n位中count[2]=3,这个2代表了“3个n位为2的数”,
* 我们要排序就必须知道“这3个数具体是什么”,然后把这些数按序放入原数组。
* 所以引入二维数组count[][],
* 第一维的下标代表了该位数“具体是几”,所以范围是0-9。
* 第二维的下标代表了该位数相同的值“第几次出现”,
* (如个位桶排序时,count[2][34]就代表了第34个“个位为2的数”。)
* 第二维中存储的是具体的某个数
*/
int[][] count = new int[10][array.length];
//该数组frequency[n]=m,用来计算“某位的桶排序”中“n这个数第m次出现”。
// 所以n的范围只能是0-9,而m最多可能是原数组的长度(当该数组某一位的值都是同一个数时)
int[] frequency = new int[10];
int now_digit = 1;//当前排序的是各项的第几位数(从第一位(个位)开始排)
int n = 1;//用来计算当前位的具体值
//从个位开始排,然后再排十位·····
while (now_digit<=len_max){
//根据原数组中各项的“now_digit位”,进行桶排序。
for (int i=0;i<array.length;i++){
//找到具体某位的值。如n=1时,找到的就是个位的值。n=10时,找到的就是十位的值
int digit = ((array[i] / n) % 10);
count[digit][frequency[digit]]=array[i];
frequency[digit]++;
}
/**
* 现在所有的项已经根据桶排序规则存入count[][]中,现在需要按序再存回原数组。思路如下:
* count[][]中第一个下标意味着“当前位”的具体值,为0-9.
* 所以应该将count[0][n]中的各个数排在前面,count[1][m]中的各项跟在后面·····
* count[0][]中存了多个“当前位为0的数”,
* 而count[][]的第二个下标表示“被存储的数”是“第几个下标为0的数”。
* 如:当前位为“个位”排序时,count[0][1]=21表示21是第一个“个位为0的数”,
* count[0][6]=341表示341是第6个“个位为0的数”
*/
//把数据存在原数组的什么位置(起始的存储位置自然是0,然后每存一个数后移一位)
int k = 0;
//从count[i=0][]开始找,然后找count[i++][]····
for(int i = 0; i < 10; i++) {
//frequency[i]代表了“i这个数第几次出现”,所以为0就表示没出现过,也就不用排了
if(frequency[i] != 0){
//从第0次出现开始找,每次都装入原数组
for(int j = 0; j < frequency[i]; j++) {
//j代表了“位值为i”的数是第几个,count[i][j]代表了该数
array[k] = count[i][j];
k++;
}
}
//“当前位数”为i的数已经存完,需要初始化,否则下一“位数为i”的数存时会出错。
frequency[i] = 0;
}
//每循一次,用来计算当前位的具体值的n做+10处理
n *= 10;
//每循一次,当前位数+1
now_digit++;
}
}
}
运行结果
程序运行时间: 74ms